/******************************************************************/
/* drawpanel.cpp - fonctions des classes du type WinEDA_DrawPanel */
/******************************************************************/


#ifdef __GNUG__
#pragma implementation
#endif

#include "fctsys.h"
#include "common.h"

#include "macros.h"
#include "id.h"

// defines locaux
#define CURSOR_SIZE 12	         // taille de la croix du curseur PCB

// Variables locales

// table des evenements captes par un WinEDA_DrawPanel
BEGIN_EVENT_TABLE( WinEDA_DrawPanel, EDA_DRAW_PANEL )
	EVT_LEAVE_WINDOW(WinEDA_DrawPanel::OnMouseLeaving)
	EVT_MOUSE_EVENTS(WinEDA_DrawPanel::OnMouseEvent)
	EVT_CHAR(WinEDA_DrawPanel::OnKeyEvent)
	EVT_CHAR_HOOK(WinEDA_DrawPanel::OnKeyEvent)
	EVT_PAINT(WinEDA_DrawPanel::OnPaint)
	EVT_SIZE(WinEDA_DrawPanel::OnSize)
	EVT_ERASE_BACKGROUND(WinEDA_DrawPanel::OnEraseBackground)
	EVT_SCROLLWIN(WinEDA_DrawPanel::OnScroll)
	EVT_ACTIVATE(WinEDA_DrawPanel::OnActivate)

	EVT_MENU_RANGE(	ID_POPUP_ZOOM_START_RANGE, ID_POPUP_ZOOM_END_RANGE,
		WinEDA_DrawPanel::Process_Popup_Zoom)
END_EVENT_TABLE()

	/***********************************************************/
	/* Fonctions de base de WinEDA_DrawPanel: l'ecran de trace */
	/***********************************************************/

WinEDA_DrawPanel::WinEDA_DrawPanel(WinEDA_DrawFrame *parent, int id,
						const wxPoint& pos, const wxSize& size):
		EDA_DRAW_PANEL(parent, id, pos, size,
		wxBORDER|wxNO_FULL_REPAINT_ON_RESIZE)
{
	m_Parent = parent;
	m_Ident = m_Parent->m_Ident;
	m_Scroll_unit = 1;
	m_ScrollButt_unit = 40;
	SetBackgroundColour(wxColour(ColorRefs[g_DrawBgColor].m_Red,
						ColorRefs[g_DrawBgColor].m_Green,
						ColorRefs[g_DrawBgColor].m_Blue ) );
	EnableScrolling(TRUE,TRUE);
	m_ClipBox.SetSize(size);
	m_ClipBox.SetX(0);
	m_ClipBox.SetY(0);
	m_CanStartBlock = -1;	// Command block can start if >= 0
	m_AbortEnable = m_AbortRequest = FALSE;
	m_AutoPAN_Enable = TRUE;
	m_IgnoreMouseEvents = FALSE;

	ManageCurseur = NULL;
	ForceCloseManageCurseur = NULL;

	if ( m_Parent->m_Parent->m_EDA_Config )
		m_AutoPAN_Enable = m_Parent->m_Parent->m_EDA_Config->Read(wxT("AutoPAN"), TRUE);
	m_AutoPAN_Request = FALSE;
	m_Block_Enable = FALSE;
	m_PanelDefaultCursor = m_PanelCursor = wxCURSOR_ARROW;
	m_CursorLevel = 0;
}


/*********************************************************************************/
void WinEDA_DrawPanel::Trace_Curseur(wxDC * DC, int color)
/*********************************************************************************/
/*
 Trace Le curseur sur la zone PCB , se deplacant sur la grille
*/
{
	if (m_CursorLevel != 0) {
		return;
	}

wxPoint Cursor = GetScreen()->m_Curseur;
	
	if ( DC == NULL ) return;
	
	GRSetDrawMode(DC, GR_XOR);
	if( g_CursorShape == 1 )	/* Trace d'un reticule */
		{
		int dx = m_ClipBox.GetWidth() * GetZoom();
		int dy = m_ClipBox.GetHeight() * GetZoom();
		GRLine(&m_ClipBox, DC, Cursor.x - dx, Cursor.y,
							Cursor.x + dx, Cursor.y, 0, color); // axe Y
		GRLine(&m_ClipBox, DC, Cursor.x, Cursor.y - dx,
				Cursor.x, Cursor.y + dy, 0, color);  // axe X
		}

	else
		{
		int len = CURSOR_SIZE * GetZoom();
		GRLine(&m_ClipBox, DC, Cursor.x - len, Cursor.y,
				Cursor.x + len, Cursor.y, 0, color);
		GRLine(&m_ClipBox, DC, Cursor.x, Cursor.y - len,
				Cursor.x, Cursor.y + len, 0, color);
		}
}


/*******************************************************************/
void WinEDA_DrawPanel::CursorOff(wxDC * DC)
/*******************************************************************/
/*
 Remove the grid cursor from the display in preparation for other drawing operations
*/
{
	Trace_Curseur(DC);
	--m_CursorLevel;
}


/*******************************************************************/
void WinEDA_DrawPanel::CursorOn(wxDC * DC)
/*******************************************************************/
/*
 Display the grid cursor
*/
{
	++m_CursorLevel;
	Trace_Curseur(DC);

	if (m_CursorLevel > 0)     // Shouldn't happen, but just in case ..
		m_CursorLevel = 0;
}


/***********************************/
int WinEDA_DrawPanel::GetZoom(void)
/***********************************/
{
	return GetScreen()->GetZoom();
}


/***************************************/
void WinEDA_DrawPanel::SetZoom(int zoom)
/***************************************/
{
	GetScreen()->SetZoom(zoom);
}


/************************************/
wxSize WinEDA_DrawPanel::GetGrid(void)
/************************************/
{
	return GetScreen()->GetGrid();
}


/******************************************************/
void WinEDA_DrawPanel::PrepareGraphicContext(wxDC * DC)
/******************************************************/
{
	GRResetPenAndBrush(DC);
	DC->SetBackgroundMode(wxTRANSPARENT);
#ifdef WX_ZOOM
int zoom = GetZoom();
double f_scale = 1.0/(double)zoom;

	DC->SetUserScale(f_scale, f_scale);
	PrepareDC(*DC);
#endif
	SetBoundaryBox();
}


/*********************************************************************/
wxPoint WinEDA_DrawPanel::CalcAbsolutePosition(const wxPoint & rel_pos)
/*********************************************************************/
/* retourne la position absolue en pixels de la position rel_pos,
donnée en position relative scrollée (en pixel)
*/
{
wxPoint pos;

#ifdef WX_ZOOM
	CalcUnscrolledPosition( rel_pos.x, rel_pos.y, &pos.x, &pos.y );
#else
int ii, jj;
	GetViewStart(&pos.x, &pos.y);
	GetScrollPixelsPerUnit(&ii, &jj);
	pos.x *= ii; pos.y *= jj;
	pos.x += rel_pos.x;
	pos.y += rel_pos.y;
#endif
	return pos;
}


/**********************************************************************/
wxPoint WinEDA_DrawPanel::CursorRealPosition(const wxPoint & ScreenPos)
/**********************************************************************/
/* Retourne la position en unites utilisateur du pointeur souris
	ScreenPos = position pointeur en coord absolue ecran
*/
{
wxPoint curpos;

	curpos = GetScreen()->CursorRealPosition(ScreenPos);

	return curpos;
}


/********************************************************/
bool WinEDA_DrawPanel::IsPointOnDisplay(wxPoint ref_pos)
/********************************************************/
/* retourne TRUE si le point de coord physique ref_pos
	est visible sur l'ecran, c'est a dire:
	si ref_pos est sur la partie du schema ou pcb affichee a l'ecran
*/
{
wxPoint pos;
EDA_Rect display_rect;

	SetBoundaryBox();
	display_rect = m_ClipBox;

	// Reduction legere des dimension de l'ecran utile pour eviter cadrage
	// en limite d'ecran
	#define PIXEL_MARGIN 8
	display_rect.Inflate(-PIXEL_MARGIN,-PIXEL_MARGIN);

	// Conversion en coord physiques
	pos = CalcAbsolutePosition( display_rect.GetPosition() );
	pos.x *= GetZoom();
	pos.y *= GetZoom();
	pos.x += GetScreen()->m_DrawOrg.x;
	pos.y += GetScreen()->m_DrawOrg.y;
	display_rect.SetX(pos.x); display_rect.SetY(pos.y);
	display_rect.SetWidth( display_rect.GetWidth() * GetZoom() );
	display_rect.SetHeight( display_rect.GetHeight() * GetZoom() );

	return display_rect.Inside(ref_pos);
}


/********************************************************/
wxPoint WinEDA_DrawPanel::CursorScreenPosition(void)
/********************************************************/
/* retourne la position sur l'ecran,en pixels, du curseur
	Orgine = coord absolue 0,0;
*/
{
wxPoint curpos = GetScreen()->m_Curseur;

	curpos.x -= GetScreen()->m_DrawOrg.x;
	curpos.y -= GetScreen()->m_DrawOrg.y;

	curpos.x /= GetZoom();
	curpos.y /= GetZoom();

	return curpos;
}


/*********************************************************/
wxPoint WinEDA_DrawPanel::GetScreenCenterRealPosition(void)
/*********************************************************/
{
wxSize size;
wxPoint realpos;

	size = GetClientSize();
	size.x /= 2; size.y /= 2;

	realpos = CalcAbsolutePosition( wxPoint(size.x, size.y) );
	realpos.x *= GetZoom();
	realpos.y *= GetZoom();
	realpos.x += GetScreen()->m_DrawOrg.x;
	realpos.y += GetScreen()->m_DrawOrg.y;

	return realpos;
}


/**********************************************/
void WinEDA_DrawPanel::MouseToCursorSchema(void)
/**********************************************/
/* place le curseur souris sur la position du curseur schema
*/
{
wxPoint Mouse = CursorScreenPosition();
	MouseTo(Mouse);
}


/****************************************************/
void WinEDA_DrawPanel::MouseTo(const wxPoint & Mouse)
/****************************************************/
/* place le curseur souris sur la position Mouse
*/
{
wxPoint mouse;
#ifdef WX_ZOOM
	CalcScrolledPosition(Mouse.x, Mouse.y, &mouse.x, &mouse.y);
#else
	mouse = Mouse;
	mouse.x -= GetScreen()->m_StartVisu.x;
	mouse.y -= GetScreen()->m_StartVisu.y;
#endif
	GRMouseWarp(this, mouse);
}

/********************************************************/
void WinEDA_DrawPanel::OnActivate(wxActivateEvent& event)
/********************************************************/
{
	m_CanStartBlock = -1;	// Commande block can't start
	event.Skip();
}


/***********************************************************/
void WinEDA_DrawPanel::OnEraseBackground(wxEraseEvent& event)
/***********************************************************/
{
	event.Skip();
}

/*********************************************************/
void WinEDA_DrawPanel::OnScroll( wxScrollWinEvent &event )
/*********************************************************/
{
int id = event.GetEventType();
int dir, value = 0;
int x,y;

	GetViewStart( &x, &y );
	dir = event.GetOrientation();	// wxHORIZONTAL ou wxVERTICAL

	if ( id == wxEVT_SCROLLWIN_LINEUP) value = - m_ScrollButt_unit;

	else if ( id == wxEVT_SCROLLWIN_LINEDOWN) value = m_ScrollButt_unit;

	else if ( id == wxEVT_SCROLLWIN_THUMBTRACK )
	{
		value = event.GetPosition();
		if ( dir == wxHORIZONTAL ) Scroll( value, -1 );
		else Scroll( -1, value );
		return;
	}

	else
	{
		event.Skip();
		return;
	}

	if ( dir == wxHORIZONTAL )
	{
		Scroll( x + value, -1 );
	}
	else
	{
		Scroll( -1, y + value );
	}
	event.Skip();
}


/*************************************************/
void WinEDA_DrawPanel::OnSize(wxSizeEvent & event)
/*************************************************/
{
	SetBoundaryBox();
	event.Skip();
}

/******************************************/
void WinEDA_DrawPanel::SetBoundaryBox(void)
/******************************************/
{
BASE_SCREEN * Screen = GetScreen();;
wxPoint org;
int ii, jj;

	Screen->m_SizeVisu = GetClientSize();
	GetViewStart(&org.x, &org.y);

	GetScrollPixelsPerUnit(&ii, &jj);
	org.x *= ii; org.y *= jj;
	Screen->m_StartVisu = org;

	m_ClipBox.SetOrigin(org);
	m_ClipBox.SetSize(GetClientSize());

#ifdef WX_ZOOM
	m_ClipBox.m_Pos.x *= GetZoom();
	m_ClipBox.m_Pos.y *= GetZoom();
	m_ClipBox.m_Size.x *= GetZoom();
	m_ClipBox.m_Size.y *= GetZoom();
#else
	m_ClipBox.m_Pos.x -= GetScreen()->m_StartVisu.x;
	m_ClipBox.m_Pos.y -= GetScreen()->m_StartVisu.y;
#endif

	m_ScrollButt_unit = MIN( Screen->m_SizeVisu.x, Screen->m_SizeVisu.y ) / 4;
	if ( m_ScrollButt_unit < 2 ) m_ScrollButt_unit = 2;

	Screen->m_ScrollbarPos.x = GetScrollPos(wxHORIZONTAL);
	Screen->m_ScrollbarPos.y = GetScrollPos(wxVERTICAL);
}


/*********************************************/
void WinEDA_DrawPanel::EraseScreen(wxDC * DC)
/*********************************************/
{
	GRSetDrawMode(DC, GR_COPY);
	GRSFilledRect(&m_ClipBox, DC, m_ClipBox.GetX(), m_ClipBox.GetY(),
				m_ClipBox.GetRight(), m_ClipBox.GetBottom(),
				g_DrawBgColor, g_DrawBgColor);
}

/***************************************************/
void WinEDA_DrawPanel::OnPaint(wxPaintEvent & event)
/***************************************************/
{
wxPaintDC paintDC(this);
EDA_Rect tmp;
wxRect PaintClipBox;
wxPoint org;

	PrepareGraphicContext(&paintDC);
	tmp = m_ClipBox;

	org = m_ClipBox.GetOrigin();

	wxRegionIterator upd(GetUpdateRegion()); // get the update rect list

	while ( upd )
	{
		PaintClipBox = upd.GetRect();
		upd++;

		PaintClipBox.x += org.x;
		PaintClipBox.y += org.y;

#ifdef WX_ZOOM
		m_ClipBox.m_Pos.x = PaintClipBox.x * GetZoom();
		m_ClipBox.m_Pos.y = PaintClipBox.y * GetZoom();
		m_ClipBox.m_Size.x = PaintClipBox.m_Size.x * GetZoom();
		m_ClipBox.m_Size.y = PaintClipBox.m_Size.y * GetZoom();
		PaintClipBox = m_ClipBox;
#else
		m_ClipBox.SetX(PaintClipBox.GetX());
		m_ClipBox.SetY(PaintClipBox.GetY());
		m_ClipBox.SetWidth(PaintClipBox.GetWidth());
		m_ClipBox.SetHeight(PaintClipBox.GetHeight());
#endif

		wxDCClipper * dcclip = new wxDCClipper(paintDC, PaintClipBox);
		ReDraw(&paintDC, TRUE);
		delete dcclip;
	}

	m_ClipBox = tmp;
	event.Skip();		
}

/****************************************************/
void WinEDA_DrawPanel::ReDraw( wxDC* DC, bool erasebg )
/****************************************************/
{
    BASE_SCREEN * Screen = GetScreen();

	if( Screen == NULL ) 
        return;

	if( (g_DrawBgColor != WHITE) && (g_DrawBgColor != BLACK) ) 
        g_DrawBgColor = BLACK;
    
	if( g_DrawBgColor == WHITE )
	{
		g_XorMode = GR_NXOR;
		g_GhostColor = BLACK;
	}
	else
	{
		g_XorMode = GR_XOR;
		g_GhostColor = WHITE;
	}

#ifdef WX_ZOOM
    int zoom = GetZoom();
    double f_scale = 1.0/(double)zoom;
	DC->SetUserScale(f_scale, f_scale);
#endif

	if(erasebg) 
        PrepareGraphicContext(DC);
    
	DC->SetFont( *g_StdFont );
		
	SetBackgroundColour( wxColour(ColorRefs[g_DrawBgColor].m_Red,
						ColorRefs[g_DrawBgColor].m_Green,
						ColorRefs[g_DrawBgColor].m_Blue ) );

	GRResetPenAndBrush( DC );

	DC->SetBackground( *wxBLACK_BRUSH );
	DC->SetBackgroundMode( wxTRANSPARENT );
	m_Parent->RedrawActiveWindow( DC, erasebg );
}


/***********************************************/
void WinEDA_DrawPanel::DrawBackGround(wxDC * DC)
/***********************************************/
/* Trace les axes X et Y et la grille
	La grille n'est affichee que si elle peut etre facilement visible
	La grille passe toujours par le centre de l'ecran
*/
{
int Color = BLUE;
BASE_SCREEN * screen = GetScreen();
int ii,jj ,xg , yg , color;
wxSize pas_grille_affichee;
bool drawgrid = FALSE;
int zoom = GetZoom();
wxSize size;
wxPoint org;
double pasx, pasy;

	color = g_GridColor;
	GRSetDrawMode(DC, GR_COPY);

	/* le pas d'affichage doit etre assez grand pour avoir une grille visible */
	drawgrid = m_Parent->m_Draw_Grid;
	pas_grille_affichee = screen->GetGrid();

	ii = pas_grille_affichee.x / zoom;
	if (ii  < 5 ) { pas_grille_affichee.x *= 2 ; ii *= 2; }
	if( ii < 5 ) drawgrid = FALSE;	// grille trop petite
	ii = pas_grille_affichee.y / zoom;
	if (ii  < 5 ) { pas_grille_affichee.y *= 2 ; ii *= 2; }
	if( ii < 5 ) drawgrid = FALSE;	// grille trop petite

	GetViewStart(&org.x, &org.y);
	GetScrollPixelsPerUnit(&ii, &jj);
	org.x *= ii; org.y *= jj;
	screen->m_StartVisu = org;

	org.x *= zoom; org.y *= zoom;
	org.x += screen->m_DrawOrg.x; org.y += screen->m_DrawOrg.y;

	size = GetClientSize();
	size.x *= zoom; size.y *= zoom;
	pasx = screen->m_UserGrid.x * m_Parent->m_InternalUnits;
	pasy = screen->m_UserGrid.y * m_Parent->m_InternalUnits;
	if ( screen->m_UserGridUnit != INCHES )
	{
		pasx /= 25.4; pasy /= 25.4;
	}

	if( drawgrid)
	{
		m_Parent->PutOnGrid(&org) ;

		GRSetColorPen(DC, color );
		for ( ii = 0 ; ; ii++ )
		{
			xg = screen->m_UserGridIsON ? (int)( (ii * pasx) + 0.5)
				:ii * pas_grille_affichee.x;
			int xpos = org.x + xg;
			for ( jj = 0 ; ; jj++ )
			{
				yg = screen->m_UserGridIsON ? (int)( (jj * pasy) + 0.5)
					: jj * pas_grille_affichee.y;
				GRPutPixel(&m_ClipBox, DC, xpos, org.y + yg, color);
				if ( yg > size.y ) break;
			}
			if ( xg > size.x ) break;
		}
	}

	/* trace des axes principaux */
	if (  m_Parent->m_Draw_Axis )
	{
		/* Trace de l'axe vertical */
		GRDashedLine(&m_ClipBox, DC, 0, -screen->ReturnPageSize().y,
				0, screen->ReturnPageSize().y, 0, Color );

		/* Trace de l'axe horizontal */
		GRDashedLine(&m_ClipBox, DC, -screen->ReturnPageSize().x, 0,
				screen->ReturnPageSize().x, 0, 0, Color );
	}

	/* trace des axes auxiliaires */
	if ( m_Parent->m_Draw_Auxiliary_Axis)
	{
		m_Draw_Auxiliary_Axis(DC, FALSE);
	}
}

/********************************************************************/
void WinEDA_DrawPanel::m_Draw_Auxiliary_Axis(wxDC * DC, int drawmode)
/********************************************************************/
{
	if ( m_Parent->m_Auxiliary_Axis_Position.x == 0 &&
		 m_Parent->m_Auxiliary_Axis_Position.y == 0 )
		return;

int Color = DARKRED;
BASE_SCREEN * screen = GetScreen();

	GRSetDrawMode(DC, drawmode);

	/* Trace de l'axe vertical */
	GRDashedLine(&m_ClipBox, DC,
			m_Parent->m_Auxiliary_Axis_Position.x, -screen->ReturnPageSize().y,
			m_Parent->m_Auxiliary_Axis_Position.x, screen->ReturnPageSize().y,
			0, Color );

	/* Trace de l'axe horizontal */
	GRDashedLine(&m_ClipBox, DC,
			-screen->ReturnPageSize().x, m_Parent->m_Auxiliary_Axis_Position.y,
			screen->ReturnPageSize().x, m_Parent->m_Auxiliary_Axis_Position.y,
			0, Color );
}


/*******************************************************/
void WinEDA_DrawPanel::OnRightClick(wxMouseEvent& event)
/*******************************************************/
/* Construit et affiche un menu Popup lorsque on actionne le bouton droit
	de la souris
*/
{
wxPoint pos;
wxMenu MasterMenu;

	pos.x = event.GetX(); pos.y = event.GetY();
	m_Parent->OnRightClick(pos, &MasterMenu);
	AddMenuZoom(&MasterMenu);
	m_IgnoreMouseEvents = TRUE;
	PopupMenu( &MasterMenu, pos);
	MouseToCursorSchema();
	m_IgnoreMouseEvents = FALSE;
}


/******************************************************/
void WinEDA_DrawPanel::OnMouseLeaving(wxMouseEvent& event)
/*******************************************************/
// Called when the canvas receives a mouse event leaving frame. //
{
	if (ManageCurseur == NULL ) // Pas de commande encours
		m_AutoPAN_Request = FALSE;

	if ( ! m_AutoPAN_Enable || ! m_AutoPAN_Request || m_IgnoreMouseEvents)
		return;
	// Auto pan if mouse is leave working aera:
	wxSize size = GetClientSize();
	if ( (size.x < event.GetX() ) ||
		 (size.y < event.GetY() ) ||
		 ( event.GetX() <= 0) || ( event.GetY() <= 0 ) )
		m_Parent->OnZoom(ID_POPUP_ZOOM_CENTER);
}


/******************************************************/
void WinEDA_DrawPanel::OnMouseEvent(wxMouseEvent& event)
/*******************************************************/
// Called when the canvas receives a mouse event. //
{
int localrealbutt = 0, localbutt = 0, localkey = 0;
BASE_SCREEN * screen = GetScreen();
static WinEDA_DrawPanel * LastPanel;
	
	if ( event.Leaving() || event.Entering() )
	{
		m_CanStartBlock = -1;
	}

	if (ManageCurseur == NULL ) // Pas de commande en cours
		m_AutoPAN_Request = FALSE;

	if ( m_Parent->m_FrameIsActive ) SetFocus();
	else return;

	// Mouse Wheel is a zoom command:
	if ( event.m_wheelRotation )
	{
		// This is a zoom in ou out command
		if ( event.GetWheelRotation() > 0 )
		{
			if( event.ShiftDown() ) localkey = EDA_PANNING_UP_KEY;
			else if( event.ControlDown() ) localkey = EDA_PANNING_LEFT_KEY;
			else localkey = WXK_F1;
		}
		else 
		{
			if( event.ShiftDown() ) localkey = EDA_PANNING_DOWN_KEY;
			else if( event.ControlDown() ) localkey = EDA_PANNING_RIGHT_KEY;
			else localkey = WXK_F2;
		}
	}

	if( !event.IsButton() && !event.Moving() &&
		!event.Dragging() && ! localkey )
	{
		return;
	}

	if( event.RightDown() )
	{
		OnRightClick(event); return;
	}

	if ( m_IgnoreMouseEvents ) return;

	if( event.LeftIsDown() ) localrealbutt |= GR_M_LEFT_DOWN;
	if( event.MiddleIsDown() ) localrealbutt |= GR_M_MIDDLE_DOWN;

	if( event.LeftDown()) localbutt = GR_M_LEFT_DOWN;

	if( event.ButtonDClick(1)) localbutt = GR_M_LEFT_DOWN|GR_M_DCLICK;
	if( event.MiddleDown()) localbutt = GR_M_MIDDLE_DOWN;
	if( event.ButtonDClick(2)) {};	// Unused

	localrealbutt |= localbutt;		/* compensation defaut wxGTK */

	/* Compute absolute m_MousePosition in pixel units: */
	screen->m_MousePositionInPixels = CalcAbsolutePosition(wxPoint(event.GetX(), event.GetY()));
	/* Compute absolute m_MousePosition in user units: */
	screen->m_MousePosition = CursorRealPosition(screen->m_MousePositionInPixels);

wxClientDC DC(this);
int kbstat = 0;

	DC.SetBackground(*wxBLACK_BRUSH );
	PrepareGraphicContext(&DC);

	g_KeyPressed = localkey;

	if( event.ShiftDown() ) kbstat |= GR_KB_SHIFT;
	if( event.ControlDown() ) kbstat |= GR_KB_CTRL;
	if( event.AltDown() ) kbstat |= GR_KB_ALT;

	g_MouseOldButtons = localrealbutt;

	// Appel des fonctions liées au Double Click ou au Click
	if( localbutt == (int)(GR_M_LEFT_DOWN|GR_M_DCLICK) )
		m_Parent->OnLeftDClick(&DC, screen->m_MousePositionInPixels);

	else if ( event.LeftDown() )
		m_Parent->OnLeftClick(&DC, screen->m_MousePositionInPixels);

	if( event.ButtonUp(2) && (screen->BlockLocate.m_State == STATE_NO_BLOCK) )
	{	// The middle button has been relached, with no block command:
		// We use it for a zoom center command
		g_KeyPressed = localkey = WXK_F4;
	}
		

	/* Appel de la fonction generale de gestion des mouvements souris
	et commandes clavier */
	m_Parent->GeneralControle(&DC, screen->m_MousePositionInPixels);


	/*******************************/
	/* Control of block commands : */
	/*******************************/
	
	// Command block can't start if mouse is dragging a new panel
	if (LastPanel != this ) m_CanStartBlock = -1;

	// A new command block can start after a release buttons
	// Avoid a false start block when a dialog bos is demiss,
	// or when changing panels in hierachy navigation
	if ( !event.LeftIsDown() && !event.MiddleIsDown())
	{
		m_CanStartBlock = 0;
	}

	if( m_Block_Enable && !(localbutt & GR_M_DCLICK) )
	{
		if ( (screen->BlockLocate.m_Command == BLOCK_IDLE) ||
			(screen->BlockLocate.m_State == STATE_NO_BLOCK))
		{
			m_CursorStartPos = screen->m_Curseur;
			screen->BlockLocate.SetOrigin(m_CursorStartPos);
		}
		if ( event.LeftDown() || event.MiddleDown() )
		{
			m_CursorStartPos = screen->m_Curseur;
			if ( screen->BlockLocate.m_State == STATE_BLOCK_MOVE )
			{
				m_AutoPAN_Request = FALSE;
				m_Parent->HandleBlockPlace(&DC);
			}
		}
		else if( (m_CanStartBlock >= 0 ) &&
				( event.LeftIsDown() || event.MiddleIsDown() )
				&& ManageCurseur == NULL
				&& ForceCloseManageCurseur == NULL )
		{
			if ( screen->BlockLocate.m_State == STATE_NO_BLOCK )
			{
				int cmd_type = kbstat;
				if ( event.MiddleIsDown() )	cmd_type |= MOUSE_MIDDLE;
				if ( ! m_Parent->HandleBlockBegin(&DC, cmd_type, m_CursorStartPos) )
				{	// error
					m_Parent->DisplayToolMsg( wxT("WinEDA_DrawPanel::OnMouseEvent() Block Error") );
				}
				else
				{
					m_AutoPAN_Request = TRUE;
					SetCursor(m_PanelCursor = wxCURSOR_SIZING);
				}
			}
		}
		
		
		if( event.ButtonUp(1) || event.ButtonUp(2) )
		{ /* Relachement du bouton: fin de delimitation de block.
			La commande peut etre terminee (DELETE) ou continuer par le placement
			du block ainsi delimite (MOVE, COPY).
			Cependant bloc est annule si sa taille est trop petite*/
			bool BlockIsSmall =
				 ( ABS(screen->BlockLocate.GetWidth()/GetZoom()) < 3) &&
				 ( ABS(screen->BlockLocate.GetHeight()/GetZoom()) < 3);
			
			if ( (screen->BlockLocate.m_State != STATE_NO_BLOCK) && BlockIsSmall )
			{
				if( ForceCloseManageCurseur )
				{
					ForceCloseManageCurseur(this, &DC);
					m_AutoPAN_Request = FALSE;
				}
				SetCursor(m_PanelCursor = m_PanelDefaultCursor);
			}
			else if ( screen->BlockLocate.m_State == STATE_BLOCK_END )
			{
				m_AutoPAN_Request = FALSE;
				m_Parent->HandleBlockEnd(&DC);
				SetCursor(m_PanelCursor = m_PanelDefaultCursor);
				if ( screen->BlockLocate.m_State == STATE_BLOCK_MOVE )
				{
					m_AutoPAN_Request = TRUE;
					SetCursor(m_PanelCursor = wxCURSOR_HAND);
				}
			}
		}

	}

	// Arret de block sur un double click ( qui peut provoquer un move block
	// si on déplace la souris dans ce double click
	if ( localbutt == (int)(GR_M_LEFT_DOWN|GR_M_DCLICK) )
	{
		if ( screen->BlockLocate.m_Command != BLOCK_IDLE )
		{
			if( ForceCloseManageCurseur )
			{
				ForceCloseManageCurseur(this, &DC);
				m_AutoPAN_Request = FALSE;
			}
		}
	}


#if 0
	wxString msg_debug;
	msg_debug.Printf(" block state %d, cmd %d",
		screen->BlockLocate.m_State, screen->BlockLocate.m_Command);
	m_Parent->PrintMsg(msg_debug);
#endif

	LastPanel = this;
	m_Parent->SetToolbars();
}

/****************************************************/
void WinEDA_DrawPanel::OnKeyEvent(wxKeyEvent& event)
/****************************************************/
{
long key, localkey;
bool escape = FALSE;

	key = localkey = event.GetKeyCode();

	switch( localkey )
		{
		case WXK_CONTROL:
		case WXK_CAPITAL:
		case WXK_SHIFT:
		case WXK_NUMLOCK:
		case WXK_LBUTTON:
		case WXK_RBUTTON:
		case 0x0135:	/* Alt key */
			return;

		case WXK_ESCAPE:
			escape = m_AbortRequest = TRUE;
			break;
		}

	if( event.ControlDown() ) localkey |= GR_KB_CTRL;
	if( event.AltDown() ) localkey |= GR_KB_ALT;
	if( event.ShiftDown() && (key > 256) ) localkey |= GR_KB_SHIFT;

wxClientDC DC(this);
BASE_SCREEN * Screen = GetScreen();

	PrepareGraphicContext(&DC);

	g_KeyPressed = localkey;

	if ( escape )
	{
		if( ManageCurseur && ForceCloseManageCurseur )
		{
			SetCursor(m_PanelCursor = m_PanelDefaultCursor);
			ForceCloseManageCurseur(this, &DC);
			SetCursor(m_PanelCursor = m_PanelDefaultCursor);
		}
		else 
        {
            m_PanelCursor = m_PanelDefaultCursor = wxCURSOR_ARROW;
            m_Parent->SetToolID(0, m_PanelCursor, wxEmptyString);
        }
	}

	m_Parent->GeneralControle(&DC, Screen->m_MousePositionInPixels);

#if 0	
	event.Skip();	// Allow menu shortcut processing
#endif
}
