1541 lines
46 KiB
C++
1541 lines
46 KiB
C++
/*****************/
|
|
/* drawpanel.cpp */
|
|
/*****************/
|
|
|
|
#include "fctsys.h"
|
|
#include "appl_wxstruct.h"
|
|
#include "gr_basic.h"
|
|
#include "common.h"
|
|
#include "macros.h"
|
|
#include "id.h"
|
|
#include "class_drawpanel.h"
|
|
#include "class_base_screen.h"
|
|
#include "wxstruct.h"
|
|
|
|
#include <wx/wupdlock.h>
|
|
#include "kicad_device_context.h"
|
|
|
|
#define CURSOR_SIZE 12 // Cursor size in pixels
|
|
|
|
#define CLIP_BOX_PADDING 12
|
|
|
|
|
|
/* Definitions for enabling and disabling debugging features in drawpanel.cpp.
|
|
* Please don't forget to turn these off before making any SvN commits.
|
|
*/
|
|
|
|
#define DEBUG_SHOW_CLIP_RECT 0 // Set to 1 to draw clipping rectangle.
|
|
#define DEBUG_DUMP_CLIP_COORDS 0 // Set to 1 to dump clipping rectangle coordinates.
|
|
#define DEBUG_DUMP_SCROLL_SETTINGS 0 // Set to 1 to dump scroll settings.
|
|
|
|
|
|
/* Used to inhibit a response to a mouse left button release, after a
|
|
* double click (when releasing the left button at the end of the second
|
|
* click. Used in eeschema to inhibit a mouse left release command when
|
|
* switching between hierarchical sheets on a double click.
|
|
*/
|
|
static bool s_IgnoreNextLeftButtonRelease = false;
|
|
|
|
|
|
// Events used by WinEDA_DrawPanel
|
|
BEGIN_EVENT_TABLE( WinEDA_DrawPanel, wxScrolledWindow )
|
|
EVT_LEAVE_WINDOW( WinEDA_DrawPanel::OnMouseLeaving )
|
|
EVT_MOUSEWHEEL( WinEDA_DrawPanel::OnMouseWheel )
|
|
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_SCROLLWIN( WinEDA_DrawPanel::OnScroll )
|
|
EVT_ACTIVATE( WinEDA_DrawPanel::OnActivate )
|
|
EVT_MENU_RANGE( ID_PAN_UP, ID_PAN_RIGHT, WinEDA_DrawPanel::OnPan )
|
|
END_EVENT_TABLE()
|
|
|
|
/***********************************************************************/
|
|
/* WinEDA_DrawPanel base functions (WinEDA_DrawPanel is the main panel)*/
|
|
/***********************************************************************/
|
|
|
|
WinEDA_DrawPanel::WinEDA_DrawPanel( WinEDA_DrawFrame* parent, int id,
|
|
const wxPoint& pos, const wxSize& size ) :
|
|
wxScrolledWindow( parent, id, pos, size,
|
|
wxBORDER | wxNO_FULL_REPAINT_ON_RESIZE )
|
|
{
|
|
m_Parent = parent;
|
|
wxASSERT( m_Parent );
|
|
|
|
m_scrollIncrementX = MIN( size.x / 8, 10 );
|
|
m_scrollIncrementY = MIN( size.y / 8, 10 );
|
|
SetBackgroundColour( wxColour( ColorRefs[g_DrawBgColor].m_Red,
|
|
ColorRefs[g_DrawBgColor].m_Green,
|
|
ColorRefs[g_DrawBgColor].m_Blue ) );
|
|
#if defined KICAD_USE_BUFFERED_DC || defined KICAD_USE_BUFFERED_PAINTDC
|
|
SetBackgroundStyle( wxBG_STYLE_CUSTOM );
|
|
#endif
|
|
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 = 0;
|
|
|
|
ManageCurseur = NULL;
|
|
ForceCloseManageCurseur = NULL;
|
|
|
|
if( wxGetApp().m_EDA_Config )
|
|
wxGetApp().m_EDA_Config->Read( wxT( "AutoPAN" ), &m_AutoPAN_Enable,
|
|
true );
|
|
|
|
m_AutoPAN_Request = false;
|
|
m_Block_Enable = false;
|
|
m_PanelDefaultCursor = m_PanelCursor = wxCURSOR_ARROW;
|
|
m_CursorLevel = 0;
|
|
m_PrintIsMirrored = false;
|
|
}
|
|
|
|
|
|
WinEDA_DrawPanel::~WinEDA_DrawPanel()
|
|
{
|
|
wxGetApp().m_EDA_Config->Write( wxT( "AutoPAN" ), m_AutoPAN_Enable );
|
|
}
|
|
|
|
|
|
BASE_SCREEN* WinEDA_DrawPanel::GetScreen()
|
|
{
|
|
WinEDA_DrawFrame* parentFrame = m_Parent;
|
|
|
|
return parentFrame->GetBaseScreen();
|
|
}
|
|
|
|
|
|
/*
|
|
* Draw the schematic cursor which is usually on grid
|
|
*/
|
|
void WinEDA_DrawPanel::DrawCursor( wxDC* aDC, int aColor )
|
|
{
|
|
if( m_CursorLevel != 0 || aDC == NULL )
|
|
return;
|
|
|
|
#ifdef __WXMAC__
|
|
SetCursor(*wxCROSS_CURSOR);
|
|
return;
|
|
#endif
|
|
|
|
wxPoint Cursor = GetScreen()->m_Curseur;
|
|
|
|
GRSetDrawMode( aDC, GR_XOR );
|
|
|
|
if( m_Parent->m_CursorShape == 1 ) /* Draws a crosshair. */
|
|
{
|
|
#ifdef USE_WX_ZOOM
|
|
wxSize clientSize = GetClientSize();
|
|
wxPoint lineStart = wxPoint( Cursor.x, aDC->DeviceToLogicalY( 0 ) );
|
|
wxPoint lineEnd = wxPoint( Cursor.x, aDC->DeviceToLogicalY( clientSize.y ) );
|
|
GRLine( &m_ClipBox, aDC, lineStart, lineEnd, 0, aColor ); // Y azis
|
|
lineStart = wxPoint( aDC->DeviceToLogicalX( 0 ), Cursor.y );
|
|
lineEnd = wxPoint( aDC->DeviceToLogicalX( clientSize.x ), Cursor.y );
|
|
GRLine( &m_ClipBox, aDC, lineStart, lineEnd, 0, aColor ); // X azis
|
|
#else
|
|
int dx = GetScreen()->Unscale( m_ClipBox.GetWidth() );
|
|
int dy = GetScreen()->Unscale( m_ClipBox.GetHeight() );
|
|
GRLine( &m_ClipBox, aDC, Cursor.x - dx, Cursor.y,
|
|
Cursor.x + dx, Cursor.y, 0, aColor ); // Y axis
|
|
GRLine( &m_ClipBox, aDC, Cursor.x, Cursor.y - dx,
|
|
Cursor.x, Cursor.y + dy, 0, aColor ); // X axis
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef USE_WX_ZOOM
|
|
int len = aDC->DeviceToLogicalXRel( CURSOR_SIZE );
|
|
#else
|
|
int len = GetScreen()->Unscale( CURSOR_SIZE );
|
|
#endif
|
|
|
|
GRLine( &m_ClipBox, aDC, Cursor.x - len, Cursor.y,
|
|
Cursor.x + len, Cursor.y, 0, aColor );
|
|
GRLine( &m_ClipBox, aDC, Cursor.x, Cursor.y - len,
|
|
Cursor.x, Cursor.y + len, 0, aColor );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Remove the grid cursor from the display in preparation for other drawing
|
|
* operations
|
|
*/
|
|
void WinEDA_DrawPanel::CursorOff( wxDC* DC )
|
|
{
|
|
DrawCursor( DC );
|
|
--m_CursorLevel;
|
|
}
|
|
|
|
|
|
/*
|
|
* Display the grid cursor
|
|
*/
|
|
void WinEDA_DrawPanel::CursorOn( wxDC* DC )
|
|
{
|
|
++m_CursorLevel;
|
|
DrawCursor( DC );
|
|
|
|
if( m_CursorLevel > 0 ) // Shouldn't happen, but just in case ..
|
|
m_CursorLevel = 0;
|
|
}
|
|
|
|
|
|
int WinEDA_DrawPanel::GetZoom()
|
|
{
|
|
return GetScreen()->GetZoom();
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::SetZoom( int zoom )
|
|
{
|
|
GetScreen()->SetZoom( zoom );
|
|
}
|
|
|
|
|
|
wxRealPoint WinEDA_DrawPanel::GetGrid()
|
|
{
|
|
return GetScreen()->GetGridSize();
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert a coordinate position in device (screen) units to logical (drawing) units.
|
|
*
|
|
* @param aPosition = position in device (screen) units.
|
|
* @return position in logical (drawing) units.
|
|
*/
|
|
wxPoint WinEDA_DrawPanel::CursorRealPosition( const wxPoint& aPosition )
|
|
{
|
|
double scalar = GetScreen()->GetScalingFactor();
|
|
wxPoint pos;
|
|
pos.x = wxRound( (double) aPosition.x / scalar );
|
|
pos.y = wxRound( (double) aPosition.y / scalar );
|
|
pos += GetScreen()->m_DrawOrg;
|
|
return pos;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function IsPointOnDisplay
|
|
* @param ref_pos is the position to test in pixels, relative to the panel.
|
|
* @return TRUE if ref_pos is a point currently visible on screen
|
|
* false if ref_pos is out of screen
|
|
*/
|
|
bool WinEDA_DrawPanel::IsPointOnDisplay( wxPoint ref_pos )
|
|
{
|
|
wxPoint pos;
|
|
EDA_Rect display_rect;
|
|
|
|
INSTALL_DC( dc, this ); // Refresh the boundary box.
|
|
|
|
display_rect = m_ClipBox;
|
|
|
|
// Slightly decreased the size of the useful screen area to avoid drawing
|
|
// limits.
|
|
#define PIXEL_MARGIN 8
|
|
display_rect.Inflate( -PIXEL_MARGIN );
|
|
|
|
#ifndef USE_WX_ZOOM
|
|
// Convert physical coordinates.
|
|
pos = CalcUnscrolledPosition( display_rect.GetPosition() );
|
|
|
|
GetScreen()->Unscale( pos );
|
|
pos += GetScreen()->m_DrawOrg;
|
|
display_rect.m_Pos = pos;
|
|
GetScreen()->Unscale( display_rect.m_Size );
|
|
#endif
|
|
|
|
return display_rect.Inside( ref_pos );
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::PostDirtyRect( EDA_Rect aRect )
|
|
{
|
|
// D( printf( "1) PostDirtyRect( x=%d, y=%d, width=%d, height=%d)\n", aRect.m_Pos.x, aRect.m_Pos.y, aRect.m_Size.x, aRect.m_Size.y ); )
|
|
|
|
// Convert the rect coordinates and size to pixels (make a draw clip box):
|
|
ConvertPcbUnitsToPixelsUnits( &aRect );
|
|
|
|
// Ensure the rectangle is large enough after truncations.
|
|
// The pcb units have finer granularity than the pixels, so it can happen
|
|
// that the rectangle is not large enough for the erase portion.
|
|
|
|
aRect.m_Size.x += 4; // += 1 is not enough!
|
|
aRect.m_Size.y += 4;
|
|
|
|
// D( printf( "2) PostDirtyRect( x=%d, y=%d, width=%d, height=%d)\n", aRect.m_Pos.x, aRect.m_Pos.y, aRect.m_Size.x, aRect.m_Size.y ); )
|
|
|
|
// pass wxRect() via EDA_Rect::operator wxRect() overload
|
|
RefreshRect( aRect, TRUE );
|
|
}
|
|
|
|
|
|
/**
|
|
* Scale and offset a rectangle in drawing units to device units.
|
|
*
|
|
* This is the equivalent of wxDC::LogicalToDevice.
|
|
*
|
|
* @param aRect - Rectangle to scale.
|
|
*/
|
|
void WinEDA_DrawPanel::ConvertPcbUnitsToPixelsUnits( EDA_Rect* aRect )
|
|
{
|
|
// Calculate the draw area origin in internal units:
|
|
wxPoint pos = aRect->GetPosition();
|
|
|
|
ConvertPcbUnitsToPixelsUnits( &pos );
|
|
aRect->SetOrigin( pos ); // rect origin in pixel units
|
|
|
|
double scale = GetScreen()->GetScalingFactor();
|
|
aRect->m_Size.x = wxRound( (double) aRect->m_Size.x * scale );
|
|
aRect->m_Size.y = wxRound( (double) aRect->m_Size.y * scale );
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::ConvertPcbUnitsToPixelsUnits( wxPoint* aPosition )
|
|
{
|
|
// Calculate the draw area origin in internal units:
|
|
wxPoint drwOrig;
|
|
int x_axis_scale, y_axis_scale;
|
|
|
|
// Origin in scroll units;
|
|
GetViewStart( &drwOrig.x, &drwOrig.y );
|
|
GetScrollPixelsPerUnit( &x_axis_scale, &y_axis_scale );
|
|
|
|
// Origin in pixels units
|
|
drwOrig.x *= x_axis_scale;
|
|
drwOrig.y *= y_axis_scale;
|
|
|
|
double x, y;
|
|
double scalar = GetScreen()->GetScalingFactor();
|
|
x = (double) aPosition->x - ( ( (double) drwOrig.x / scalar )
|
|
+ (double) GetScreen()->m_DrawOrg.x );
|
|
y = (double) aPosition->y - ( ( (double) drwOrig.y / scalar )
|
|
+ (double) GetScreen()->m_DrawOrg.y );
|
|
aPosition->x = wxRound( x * scalar );
|
|
aPosition->y = wxRound( y * scalar );
|
|
}
|
|
|
|
|
|
/**
|
|
* Function CursorScreenPosition
|
|
* @return the cursor current position in pixels in the screen draw area
|
|
*/
|
|
wxPoint WinEDA_DrawPanel::CursorScreenPosition()
|
|
{
|
|
wxPoint pos = GetScreen()->m_Curseur - GetScreen()->m_DrawOrg;
|
|
double scalar = GetScreen()->GetScalingFactor();
|
|
|
|
pos.x = wxRound( (double) pos.x * scalar );
|
|
pos.y = wxRound( (double) pos.y * scalar );
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function GetScreenCenterRealPosition
|
|
* @return position (in internal units) of the current area center showed
|
|
* on screen
|
|
*/
|
|
wxPoint WinEDA_DrawPanel::GetScreenCenterRealPosition( void )
|
|
{
|
|
int x, y, ppuX, ppuY;
|
|
wxPoint pos;
|
|
double scalar = GetScreen()->GetScalingFactor();
|
|
|
|
GetViewStart( &x, &y );
|
|
GetScrollPixelsPerUnit( &ppuX, &ppuY );
|
|
x *= ppuX;
|
|
y *= ppuY;
|
|
pos.x = wxRound( ( (double) GetClientSize().x / 2.0 + (double) x ) / scalar );
|
|
pos.y = wxRound( ( (double) GetClientSize().y / 2.0 + (double) y ) / scalar );
|
|
pos += GetScreen()->m_DrawOrg;
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
/* Move the mouse cursor to the current schematic cursor
|
|
*/
|
|
void WinEDA_DrawPanel::MouseToCursorSchema()
|
|
{
|
|
wxPoint Mouse = CursorScreenPosition();
|
|
|
|
MouseTo( Mouse );
|
|
}
|
|
|
|
|
|
/** Move the mouse cursor to the position "Mouse"
|
|
* @param Mouse = mouse cursor position, in pixels units
|
|
*/
|
|
void WinEDA_DrawPanel::MouseTo( const wxPoint& Mouse )
|
|
{
|
|
int x, y, xPpu, yPpu;
|
|
wxPoint screenPos, drawingPos;
|
|
wxRect clientRect( wxPoint( 0, 0 ), GetClientSize() );
|
|
|
|
CalcScrolledPosition( Mouse.x, Mouse.y, &screenPos.x, &screenPos.y );
|
|
|
|
/* Scroll if the requested mouse position cursor is outside the drawing
|
|
* area. */
|
|
if( !clientRect.Contains( screenPos ) )
|
|
{
|
|
GetViewStart( &x, &y );
|
|
GetScrollPixelsPerUnit( &xPpu, &yPpu );
|
|
CalcUnscrolledPosition( screenPos.x, screenPos.y,
|
|
&drawingPos.x, &drawingPos.y );
|
|
|
|
wxLogDebug( wxT( "MouseTo() initial screen position(%d, %d) " ) \
|
|
wxT( "rectangle(%d, %d, %d, %d) view(%d, %d)" ),
|
|
screenPos.x, screenPos.y, clientRect.x, clientRect.y,
|
|
clientRect.width, clientRect.height, x, y );
|
|
|
|
if( screenPos.y < clientRect.GetTop() )
|
|
y -= m_scrollIncrementY * yPpu;
|
|
else if( screenPos.y > clientRect.GetBottom() )
|
|
y += m_scrollIncrementY * yPpu;
|
|
else if( clientRect.GetRight() < screenPos.x )
|
|
x += m_scrollIncrementX * xPpu;
|
|
else
|
|
x -= m_scrollIncrementX * xPpu;
|
|
|
|
Scroll( x, y );
|
|
CalcScrolledPosition( drawingPos.x, drawingPos.y,
|
|
&screenPos.x, &screenPos.y );
|
|
|
|
wxLogDebug( wxT( "MouseTo() scrolled screen position(%d, %d) " ) \
|
|
wxT( "view(%d, %d)" ), screenPos.x, screenPos.y, x, y );
|
|
}
|
|
|
|
WarpPointer( screenPos.x, screenPos.y );
|
|
}
|
|
|
|
|
|
/**
|
|
* Called on window activation.
|
|
* init the member m_CanStartBlock to avoid a block start command
|
|
* on activation (because a left mouse button can be pressed and no block
|
|
* command wanted.
|
|
* This happens when enter on a hierarchy sheet on double click
|
|
*/
|
|
void WinEDA_DrawPanel::OnActivate( wxActivateEvent& event )
|
|
{
|
|
m_CanStartBlock = -1; // Block Command can't start
|
|
event.Skip();
|
|
}
|
|
|
|
void WinEDA_DrawPanel::OnScroll( wxScrollWinEvent& event )
|
|
{
|
|
int id = event.GetEventType();
|
|
int dir;
|
|
int x, y;
|
|
int ppux, ppuy;
|
|
int unitsX, unitsY;
|
|
int maxX, maxY;
|
|
|
|
GetViewStart( &x, &y );
|
|
GetScrollPixelsPerUnit( &ppux, &ppuy );
|
|
GetVirtualSize( &unitsX, &unitsY );
|
|
maxX = unitsX;
|
|
maxY = unitsY;
|
|
|
|
unitsX /= ppux;
|
|
unitsY /= ppuy;
|
|
|
|
dir = event.GetOrientation(); // wxHORIZONTAL or wxVERTICAL
|
|
|
|
if( id == wxEVT_SCROLLWIN_LINEUP )
|
|
{
|
|
if( dir == wxHORIZONTAL )
|
|
{
|
|
x -= m_scrollIncrementX;
|
|
if( x < 0 )
|
|
x = 0;
|
|
}
|
|
else
|
|
{
|
|
y -= m_scrollIncrementY;
|
|
if( y < 0 )
|
|
y = 0;
|
|
}
|
|
}
|
|
else if( id == wxEVT_SCROLLWIN_LINEDOWN )
|
|
{
|
|
if( dir == wxHORIZONTAL )
|
|
{
|
|
x += m_scrollIncrementX;
|
|
if( x > maxX )
|
|
x = maxX;
|
|
}
|
|
else
|
|
{
|
|
y += m_scrollIncrementY;
|
|
if( y > maxY )
|
|
y = maxY;
|
|
}
|
|
}
|
|
else if( id == wxEVT_SCROLLWIN_THUMBTRACK )
|
|
{
|
|
if( dir == wxHORIZONTAL )
|
|
x = event.GetPosition();
|
|
else
|
|
y = event.GetPosition();
|
|
}
|
|
else
|
|
{
|
|
event.Skip();
|
|
return;
|
|
}
|
|
|
|
#if DEBUG_DUMP_SCROLL_SETTINGS
|
|
wxLogDebug( wxT( "Setting scroll bars ppuX=%d, ppuY=%d, unitsX=%d, unitsY=%d," \
|
|
"posX=%d, posY=%d" ), ppux, ppuy, unitsX, unitsY, x, y );
|
|
#endif
|
|
|
|
Scroll( x/ppux, y/ppuy );
|
|
event.Skip();
|
|
}
|
|
|
|
void WinEDA_DrawPanel::OnSize( wxSizeEvent& event )
|
|
{
|
|
if( IsShown() )
|
|
{
|
|
INSTALL_DC( dc, this ); // Update boundary box.
|
|
}
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
/**
|
|
* Function SetBoundaryBox
|
|
* Set the clip box to the current displayed rectangle dimensions.
|
|
*
|
|
* When using wxDC for scaling, the clip box coordinates are in drawing (logical)
|
|
* units. In other words, the area of the drawing that will be displayed on the
|
|
* screen. When using Kicad's scaling, the clip box coordinates are in screen
|
|
* (device) units according to the current scroll position.
|
|
*
|
|
* @param dc - The device context use for drawing with the correct scale and
|
|
* offsets already configured. See DoPrepareDC().
|
|
*/
|
|
void WinEDA_DrawPanel::SetBoundaryBox( wxDC* dc )
|
|
{
|
|
wxASSERT( dc != NULL );
|
|
|
|
BASE_SCREEN* Screen = GetScreen();;
|
|
|
|
if( !Screen )
|
|
return;
|
|
|
|
Screen->m_StartVisu = CalcUnscrolledPosition( wxPoint( 0, 0 ) );
|
|
m_ClipBox.SetOrigin( wxPoint( 0, 0 ) );
|
|
m_ClipBox.SetSize( GetClientSize() );
|
|
|
|
int scrollX, scrollY;
|
|
|
|
#ifdef USE_WX_ZOOM
|
|
double scalar = Screen->GetScalingFactor();
|
|
scrollX = wxRound( Screen->GetGridSize().x * scalar );
|
|
scrollY = wxRound( Screen->GetGridSize().y * scalar );
|
|
#else
|
|
scrollX = wxRound( Screen->Scale( Screen->GetGridSize().x ) );
|
|
scrollY = wxRound( Screen->Scale( Screen->GetGridSize().y ) );
|
|
#endif
|
|
|
|
m_scrollIncrementX = MAX( GetClientSize().x / 8, scrollX );
|
|
m_scrollIncrementY = MAX( GetClientSize().y / 8, scrollY );
|
|
|
|
|
|
#ifdef USE_WX_ZOOM
|
|
/* Using wxDC scaling requires clipping in drawing (logical) units. */
|
|
m_ClipBox.SetOrigin( CalcUnscrolledPosition( wxPoint( 0, 0 ) ) );
|
|
m_ClipBox.Inflate( CLIP_BOX_PADDING );
|
|
m_ClipBox.m_Pos.x = wxRound( (double) m_ClipBox.m_Pos.x / scalar );
|
|
m_ClipBox.m_Pos.y = wxRound( (double) m_ClipBox.m_Pos.y / scalar );
|
|
m_ClipBox.m_Pos += Screen->m_DrawOrg;
|
|
m_ClipBox.m_Size.x = wxRound( (double) m_ClipBox.m_Size.x / scalar );
|
|
m_ClipBox.m_Size.y = wxRound( (double) m_ClipBox.m_Size.y / scalar );
|
|
#endif
|
|
|
|
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(),
|
|
0, g_DrawBgColor, g_DrawBgColor );
|
|
|
|
/* Set to one (1) to draw bounding box validate bounding box calculation. */
|
|
#if DEBUG_SHOW_CLIP_RECT
|
|
EDA_Rect bBox = m_ClipBox;
|
|
bBox.Inflate( -DC->DeviceToLogicalXRel( 1 ) );
|
|
GRRect( NULL, DC, bBox.GetOrigin().x, bBox.GetOrigin().y,
|
|
bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA );
|
|
#endif
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::DoPrepareDC(wxDC& dc)
|
|
{
|
|
#ifdef USE_WX_ZOOM
|
|
if( GetScreen() != NULL )
|
|
{
|
|
double scale = GetScreen()->GetScalingFactor();
|
|
dc.SetUserScale( scale, scale );
|
|
|
|
wxPoint pt = CalcUnscrolledPosition( wxPoint( 0, 0 ) );
|
|
dc.SetDeviceOrigin( -pt.x, -pt.y );
|
|
pt = GetScreen()->m_DrawOrg;
|
|
dc.SetLogicalOrigin( pt.x, pt.y );
|
|
}
|
|
#endif
|
|
|
|
GRResetPenAndBrush( &dc );
|
|
dc.SetBackgroundMode( wxTRANSPARENT );
|
|
SetBoundaryBox( &dc );
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::OnPaint( wxPaintEvent& event )
|
|
{
|
|
if( GetScreen() == NULL )
|
|
{
|
|
event.Skip();
|
|
return;
|
|
}
|
|
|
|
INSTALL_PAINTDC( paintDC, this );
|
|
|
|
/* wxAutoBufferedPaintDC does not work correctly by setting the user scale and
|
|
* logcial offset. The bitmap coordinates and scaling are not effected by the
|
|
* code below. It appears that the wxBufferPaintDC needs to be created with the
|
|
* wxBUFFER_VIRTUAL_AREA set and the wirtual method wxWindow::PrepareDC() needs
|
|
* to be overridden to set up the buffered paint DC properly. The bitmap grid
|
|
* draw code ( see DrawGrid() below ) will have to be fixed before this can be
|
|
* implemented.
|
|
*/
|
|
|
|
EDA_Rect tmp = m_ClipBox;
|
|
|
|
// Get the union of all rectangles in the update region.
|
|
wxRect PaintClipBox = GetUpdateRegion().GetBox();
|
|
|
|
#if DEBUG_DUMP_CLIP_COORDS
|
|
wxLogDebug( wxT( "1) PaintClipBox=(%d, %d, %d, %d), m_ClipBox=(%d, %d, %d, %d)" ),
|
|
PaintClipBox.x, PaintClipBox.y, PaintClipBox.width, PaintClipBox.height,
|
|
m_ClipBox.m_Pos.x, m_ClipBox.m_Pos.y, m_ClipBox.m_Size.x, m_ClipBox.m_Size.y );
|
|
#endif
|
|
|
|
#if defined( USE_WX_ZOOM )
|
|
/* When using wxDC scaling the clipping region coordinates are in drawing
|
|
* (logical) units.
|
|
*/
|
|
double scalar = GetScreen()->GetScalingFactor();
|
|
m_ClipBox.m_Pos = CalcUnscrolledPosition( PaintClipBox.GetPosition() );
|
|
m_ClipBox.m_Size = PaintClipBox.GetSize();
|
|
m_ClipBox.Inflate( CLIP_BOX_PADDING );
|
|
m_ClipBox.m_Pos.x = wxRound( (double) m_ClipBox.m_Pos.x / scalar );
|
|
m_ClipBox.m_Pos.y = wxRound( (double) m_ClipBox.m_Pos.y / scalar );
|
|
m_ClipBox.m_Pos += GetScreen()->m_DrawOrg;
|
|
m_ClipBox.m_Size.x = wxRound( (double) m_ClipBox.m_Size.x / scalar );
|
|
m_ClipBox.m_Size.y = wxRound( (double) m_ClipBox.m_Size.y / scalar );
|
|
PaintClipBox = m_ClipBox;
|
|
#else
|
|
/* When using Kicad's scaling the clipping region coordinates are in screen
|
|
* (device) units.
|
|
*/
|
|
m_ClipBox.SetX( PaintClipBox.GetX() );
|
|
m_ClipBox.SetY( PaintClipBox.GetY() );
|
|
m_ClipBox.SetWidth( PaintClipBox.GetWidth() );
|
|
m_ClipBox.SetHeight( PaintClipBox.GetHeight() );
|
|
|
|
// Be sure the drawpanel clipbox is bigger than the region to repair:
|
|
m_ClipBox.Inflate( 1 ); // Give it one pixel more in each direction
|
|
#endif
|
|
|
|
#if DEBUG_DUMP_CLIP_COORDS
|
|
wxLogDebug( wxT( "2) PaintClipBox=(%d, %d, %d, %d), m_ClipBox=(%d, %d, %d, %d)" ),
|
|
PaintClipBox.x, PaintClipBox.y, PaintClipBox.width, PaintClipBox.height,
|
|
m_ClipBox.m_Pos.x, m_ClipBox.m_Pos.y, m_ClipBox.m_Size.x, m_ClipBox.m_Size.y );
|
|
#endif
|
|
|
|
// call ~wxDCClipper() before ~wxPaintDC()
|
|
{
|
|
wxDCClipper dcclip( paintDC, PaintClipBox );
|
|
ReDraw( &paintDC, true );
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if( erasebg )
|
|
EraseScreen( DC );
|
|
|
|
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 );
|
|
}
|
|
|
|
|
|
/**
|
|
* Function DrawBackGround
|
|
* @param DC = current Device Context
|
|
* Draws (if allowed) :
|
|
* the grid
|
|
* X and Y axis
|
|
* X and Y auxiliary axis
|
|
*/
|
|
void WinEDA_DrawPanel::DrawBackGround( wxDC* DC )
|
|
{
|
|
int axis_color = BLUE;
|
|
BASE_SCREEN* screen = GetScreen();
|
|
|
|
GRSetDrawMode( DC, GR_COPY );
|
|
|
|
if( m_Parent->IsGridVisible() )
|
|
DrawGrid( DC );
|
|
|
|
/* Draw axis */
|
|
if( m_Parent->m_Draw_Axis )
|
|
{
|
|
/* Draw the Y axis */
|
|
GRDashedLine( &m_ClipBox, DC, 0, -screen->ReturnPageSize().y,
|
|
0, screen->ReturnPageSize().y, 0, axis_color );
|
|
|
|
/* Draw the X axis */
|
|
GRDashedLine( &m_ClipBox, DC, -screen->ReturnPageSize().x, 0,
|
|
screen->ReturnPageSize().x, 0, 0, axis_color );
|
|
}
|
|
|
|
if( m_Parent->m_Draw_Auxiliary_Axis )
|
|
DrawAuxiliaryAxis( DC, GR_COPY );
|
|
|
|
if( m_Parent->m_Draw_Grid_Axis )
|
|
DrawGridAxis( DC, GR_COPY );
|
|
}
|
|
|
|
|
|
/**
|
|
* Function DrawGrid
|
|
* @param DC = current Device Context
|
|
* draws the grid
|
|
* - the grid is drawn only if the zoom level allows a good visibility
|
|
* - the grid is always centered on the screen center
|
|
*/
|
|
void WinEDA_DrawPanel::DrawGrid( wxDC* DC )
|
|
{
|
|
#define MIN_GRID_SIZE 10 // min grid size in pixels to allow drawing
|
|
BASE_SCREEN* screen = GetScreen();
|
|
int ii, jj, xg, yg;
|
|
wxRealPoint screen_grid_size;
|
|
wxSize size;
|
|
wxPoint org;
|
|
wxRealPoint dgrid;
|
|
|
|
/* The grid must be visible. this is possible only is grid value
|
|
* and zoom value are sufficient
|
|
*/
|
|
screen_grid_size = screen->GetGridSize();
|
|
org = CalcUnscrolledPosition( wxPoint( 0, 0 ) );
|
|
screen->m_StartVisu = org;
|
|
size = GetClientSize();
|
|
|
|
#ifdef USE_WX_ZOOM
|
|
dgrid.x = DC->LogicalToDeviceXRel( wxRound( screen_grid_size.x ) );
|
|
dgrid.y = DC->LogicalToDeviceXRel( wxRound( screen_grid_size.y ) );
|
|
|
|
org = m_ClipBox.m_Pos;
|
|
size = m_ClipBox.m_Size;
|
|
#else
|
|
dgrid = screen_grid_size;
|
|
screen->Scale( dgrid ); // dgrid = grid size in pixels
|
|
screen->Unscale( size );
|
|
screen->Unscale( org );
|
|
org += screen->m_DrawOrg;
|
|
#endif
|
|
|
|
// if the grid size is small ( < MIN_GRID_SIZE pixels ) do not display all points
|
|
bool double_size = false;
|
|
if( dgrid.x < MIN_GRID_SIZE )
|
|
{
|
|
double_size = true;
|
|
dgrid.x *= 2;
|
|
}
|
|
if( dgrid.x < MIN_GRID_SIZE )
|
|
return; // The X grid is too small: do not show it
|
|
|
|
if( dgrid.y < MIN_GRID_SIZE )
|
|
{
|
|
double_size = true;
|
|
dgrid.y *= 2;
|
|
}
|
|
if( dgrid.y < MIN_GRID_SIZE )
|
|
return; // The Y grid is too small: do not show it
|
|
|
|
|
|
m_Parent->PutOnGrid( &org );
|
|
GRSetColorPen( DC, m_Parent->GetGridColor() );
|
|
int xpos, ypos;
|
|
|
|
/* When we use an double_size grid, we must align grid ord on double grid
|
|
*/
|
|
int increment = double_size ? 2 : 1;
|
|
if( double_size )
|
|
{
|
|
wxRealPoint dblgrid = screen_grid_size + screen_grid_size;
|
|
m_Parent->PutOnGrid( &org, &dblgrid );
|
|
}
|
|
|
|
// Draw grid: the best algorithm depend on the platform.
|
|
// under macOSX, the first method is better
|
|
// under window, the second method is better
|
|
// Under linux, to be tested (could be depend on linux versions
|
|
// so perhaps could be necessary to set this option at run time.
|
|
|
|
/* The bitmap grid drawing code below cannot be used when wxDC scaling is used
|
|
* as it does not scale the grid bitmap properly. This needs to be fixed.
|
|
*/
|
|
|
|
#if defined( __WXMAC__ ) && !defined( USE_WX_ZOOM )
|
|
// Use a pixel based draw to display grid
|
|
// When is not used USE_WX_ZOOM
|
|
for( ii = 0; ; ii += increment )
|
|
{
|
|
xg = wxRound( ii * screen_grid_size.x );
|
|
if( xg > size.x )
|
|
break;
|
|
xpos = org.x + xg;
|
|
xpos = GRMapX( xpos );
|
|
for( jj = 0; ; jj += increment )
|
|
{
|
|
yg = wxRound( jj * screen_grid_size.y );
|
|
if( yg > size.y )
|
|
break;
|
|
ypos = org.y + yg;
|
|
DC->DrawPoint( xpos, GRMapY( ypos ) );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined( USE_WX_ZOOM )
|
|
// Use a pixel based draw to display grid
|
|
// There is a lot of calls, so the cost is hight
|
|
// and grid is slowly drawn on some platforms
|
|
for( ii = 0; ; ii += increment )
|
|
{
|
|
xg = wxRound( ii * screen_grid_size.x );
|
|
if( xg > size.x )
|
|
break;
|
|
xpos = org.x + xg;
|
|
xpos = GRMapX( xpos );
|
|
if( xpos < m_ClipBox.GetOrigin().x ) // column not in active screen area.
|
|
continue;
|
|
if( xpos > m_ClipBox.GetEnd().x ) // end of active area reached.
|
|
break;
|
|
for( jj = 0; ; jj += increment )
|
|
{
|
|
yg = wxRound( jj * screen_grid_size.y );
|
|
if( yg > size.y )
|
|
break;
|
|
ypos = org.y + yg;
|
|
if( ypos < m_ClipBox.GetOrigin().y ) // column not in active screen area.
|
|
continue;
|
|
if( ypos > m_ClipBox.GetEnd().y ) // end of active area reached.
|
|
break;
|
|
DC->DrawPoint( xpos, GRMapY( ypos ) );
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
/* Currently on test: Use a fast way to draw the grid
|
|
* But this is fast only if the Blit function is fast. Not true on all platforms
|
|
* a grid column is drawn; and then copied to others grid columns
|
|
* this is possible because the grid is drawn only after clearing the screen.
|
|
*
|
|
* A first grid column is drawn in a temporary bitmap,
|
|
* and after is duplicated using the Blit function
|
|
* (copy from a screen area to an other screen area)
|
|
*/
|
|
|
|
wxSize screenSize = GetClientSize();
|
|
wxMemoryDC tmpDC;
|
|
wxBitmap tmpBM( 1, screenSize.y );
|
|
tmpDC.SelectObject( tmpBM );
|
|
GRSetColorPen( &tmpDC, g_DrawBgColor );
|
|
tmpDC.DrawLine( 0, 0, 0, screenSize.y-1 ); // init background
|
|
GRSetColorPen( &tmpDC, m_Parent->GetGridColor() );
|
|
for( jj = 0; ; jj += increment ) // draw grid points
|
|
{
|
|
yg = wxRound( jj * screen_grid_size.y );
|
|
ypos = screen->Scale( yg );
|
|
if( ypos > screenSize.y )
|
|
break;
|
|
tmpDC.DrawPoint( 0, ypos );
|
|
}
|
|
|
|
ypos = GRMapY( org.y );
|
|
for( ii = 0; ; ii += increment )
|
|
{
|
|
xg = wxRound( ii * screen_grid_size.x );
|
|
if( xg > size.x )
|
|
break;
|
|
xpos = GRMapX( org.x + xg );
|
|
if( xpos < m_ClipBox.GetOrigin().x) // column not in active screen area.
|
|
continue;
|
|
if( xpos > m_ClipBox.GetEnd().x) // end of active area reached.
|
|
break;
|
|
DC->Blit( xpos, ypos, 1, screenSize.y, &tmpDC, 0, 0 );
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Function DrawAuxiliaryAxis
|
|
* Draw the Auxiliary Axis, used in pcbnew which as origin coordinates
|
|
* for gerber and excellon files
|
|
* @param DC = current Device Context
|
|
*/
|
|
void WinEDA_DrawPanel::DrawAuxiliaryAxis( wxDC* DC, int drawmode )
|
|
{
|
|
if( m_Parent->m_Auxiliary_Axis_Position == wxPoint( 0, 0 ) )
|
|
return;
|
|
|
|
int Color = DARKRED;
|
|
BASE_SCREEN* screen = GetScreen();
|
|
|
|
GRSetDrawMode( DC, drawmode );
|
|
|
|
/* Draw the Y axis */
|
|
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 );
|
|
|
|
/* Draw the X axis */
|
|
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::DrawGridAxis( wxDC* DC, int drawmode )
|
|
/********************************************************************/
|
|
{
|
|
BASE_SCREEN* screen = GetScreen();
|
|
if( !m_Parent->m_Draw_Grid_Axis
|
|
|| ( screen->m_GridOrigin.x == 0
|
|
&& screen->m_GridOrigin.y == 0 ) )
|
|
return;
|
|
|
|
int Color = m_Parent->GetGridColor();
|
|
|
|
GRSetDrawMode( DC, drawmode );
|
|
|
|
/* Draw the Y axis */
|
|
GRDashedLine( &m_ClipBox, DC,
|
|
screen->m_GridOrigin.x,
|
|
-screen->ReturnPageSize().y,
|
|
screen->m_GridOrigin.x,
|
|
screen->ReturnPageSize().y,
|
|
0, Color );
|
|
|
|
/* Draw the X axis */
|
|
GRDashedLine( &m_ClipBox, DC,
|
|
-screen->ReturnPageSize().x,
|
|
screen->m_GridOrigin.y,
|
|
screen->ReturnPageSize().x,
|
|
screen->m_GridOrigin.y,
|
|
0, Color );
|
|
}
|
|
|
|
/** Build and display a Popup menu on a right mouse button click
|
|
* @return true if a popup menu is shown, or false
|
|
*/
|
|
bool WinEDA_DrawPanel::OnRightClick( wxMouseEvent& event )
|
|
{
|
|
wxPoint pos;
|
|
wxMenu MasterMenu;
|
|
|
|
pos = event.GetPosition();
|
|
|
|
if( !m_Parent->OnRightClick( pos, &MasterMenu ) )
|
|
return false;
|
|
|
|
m_Parent->AddMenuZoomAndGrid( &MasterMenu );
|
|
|
|
m_IgnoreMouseEvents = TRUE;
|
|
PopupMenu( &MasterMenu, pos );
|
|
MouseToCursorSchema();
|
|
m_IgnoreMouseEvents = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Called when the canvas receives a mouse event leaving frame.
|
|
void WinEDA_DrawPanel::OnMouseLeaving( wxMouseEvent& event )
|
|
{
|
|
if( ManageCurseur == NULL ) // No command in progress.
|
|
m_AutoPAN_Request = false;
|
|
|
|
if( !m_AutoPAN_Enable || !m_AutoPAN_Request || m_IgnoreMouseEvents )
|
|
return;
|
|
|
|
// Auto pan if mouse is leave working area:
|
|
wxSize size = GetClientSize();
|
|
|
|
if( ( size.x < event.GetX() ) || ( size.y < event.GetY() )
|
|
|| ( event.GetX() <= 0) || ( event.GetY() <= 0 ) )
|
|
{
|
|
wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED, ID_POPUP_ZOOM_CENTER );
|
|
cmd.SetEventObject( this );
|
|
GetEventHandler()->ProcessEvent( cmd );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Handle mouse wheel events.
|
|
*
|
|
* The mouse wheel is used to provide support for zooming and panning. This
|
|
* is accomplished by converting mouse wheel events in pseudo menu command
|
|
* events.
|
|
*/
|
|
void WinEDA_DrawPanel::OnMouseWheel( wxMouseEvent& event )
|
|
{
|
|
if( m_IgnoreMouseEvents )
|
|
return;
|
|
|
|
wxRect rect = wxRect( wxPoint( 0, 0 ), GetClientSize() );
|
|
|
|
/* Ignore scroll events if the cursor is outside the drawing area. */
|
|
if( event.GetWheelRotation() == 0 || !GetParent()->IsEnabled()
|
|
|| !rect.Contains( event.GetPosition() ) )
|
|
{
|
|
#if 0
|
|
wxLogDebug( wxT( "OnMouseWheel() position(%d, %d) " ) \
|
|
wxT( "rectangle(%d, %d, %d, %d)" ),
|
|
event.GetPosition().x, event.GetPosition().y,
|
|
rect.x, rect.y, rect.width, rect.height );
|
|
#endif
|
|
event.Skip();
|
|
return;
|
|
}
|
|
|
|
GetScreen()->m_Curseur =
|
|
CursorRealPosition( CalcUnscrolledPosition( event.GetPosition() ) );
|
|
|
|
wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
|
|
cmd.SetEventObject( this );
|
|
|
|
// This is a zoom in or out command
|
|
if( event.GetWheelRotation() > 0 )
|
|
{
|
|
if( event.ShiftDown() && !event.ControlDown() )
|
|
cmd.SetId( ID_PAN_UP );
|
|
else if( event.ControlDown() && !event.ShiftDown() )
|
|
cmd.SetId( ID_PAN_LEFT );
|
|
else
|
|
cmd.SetId( ID_POPUP_ZOOM_IN );
|
|
}
|
|
else if( event.GetWheelRotation() < 0 )
|
|
{
|
|
if( event.ShiftDown() && !event.ControlDown() )
|
|
cmd.SetId( ID_PAN_DOWN );
|
|
else if( event.ControlDown() && !event.ShiftDown() )
|
|
cmd.SetId( ID_PAN_RIGHT );
|
|
else
|
|
cmd.SetId( ID_POPUP_ZOOM_OUT );
|
|
}
|
|
|
|
GetEventHandler()->ProcessEvent( cmd );
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
// Called when the canvas receives a mouse event.
|
|
void WinEDA_DrawPanel::OnMouseEvent( wxMouseEvent& event )
|
|
{
|
|
int localrealbutt = 0, localbutt = 0, localkey = 0;
|
|
BASE_SCREEN* screen = GetScreen();
|
|
static WinEDA_DrawPanel* LastPanel;
|
|
|
|
if( !screen )
|
|
return;
|
|
|
|
/* Adjust value to filter mouse displacement before consider the drag
|
|
* mouse is really a drag command, not just a movement while click
|
|
*/
|
|
#define MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND 5
|
|
|
|
/* Count the drag events. Used to filter mouse moves before starting a
|
|
* block command. A block command can be started only if
|
|
* MinDragEventCount > MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND
|
|
* and m_CanStartBlock >= 0
|
|
* in order to avoid spurious block commands.
|
|
*/
|
|
static int MinDragEventCount;
|
|
if( event.Leaving() )
|
|
{
|
|
m_CanStartBlock = -1;
|
|
}
|
|
|
|
if( ManageCurseur == NULL ) // No command in progress
|
|
m_AutoPAN_Request = false;
|
|
|
|
if( m_Parent->m_FrameIsActive )
|
|
SetFocus();
|
|
else
|
|
return;
|
|
|
|
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;
|
|
|
|
localrealbutt |= localbutt; /* compensation default wxGTK */
|
|
|
|
/* Compute the cursor position in screen (device) units. */
|
|
screen->m_MousePositionInPixels = CalcUnscrolledPosition( event.GetPosition() );
|
|
|
|
/* Compute the cursor position in drawing (logical) units. */
|
|
screen->m_MousePosition =
|
|
CursorRealPosition( CalcUnscrolledPosition( event.GetPosition() ) );
|
|
|
|
INSTALL_DC( DC, this );
|
|
|
|
int kbstat = 0;
|
|
|
|
DC.SetBackground( *wxBLACK_BRUSH );
|
|
|
|
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;
|
|
|
|
// Calling Double Click and Click functions :
|
|
if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) )
|
|
{
|
|
m_Parent->OnLeftDClick( &DC, screen->m_MousePositionInPixels );
|
|
|
|
// inhibit a response to the mouse left button release,
|
|
// because we have a double click, and we do not want a new
|
|
// OnLeftClick command at end of this Double Click
|
|
s_IgnoreNextLeftButtonRelease = true;
|
|
}
|
|
else if( event.LeftUp() )
|
|
{
|
|
// A block command is in progress: a left up is the end of block
|
|
// or this is the end of a double click, already seen
|
|
if( screen->m_BlockLocate.m_State==STATE_NO_BLOCK
|
|
&& !s_IgnoreNextLeftButtonRelease )
|
|
m_Parent->OnLeftClick( &DC, screen->m_MousePositionInPixels );
|
|
|
|
s_IgnoreNextLeftButtonRelease = false;
|
|
}
|
|
|
|
if( !event.LeftIsDown() )
|
|
{
|
|
/* be sure there is a response to a left button release command
|
|
* even when a LeftUp event is not seen. This happens when a
|
|
* double click opens a dialog box, and the release mouse button
|
|
* is made when the dialog box is open.
|
|
*/
|
|
s_IgnoreNextLeftButtonRelease = false;
|
|
}
|
|
|
|
if( event.ButtonUp( wxMOUSE_BTN_MIDDLE )
|
|
&& (screen->m_BlockLocate.m_State == STATE_NO_BLOCK) )
|
|
{
|
|
// The middle button has been released, with no block command:
|
|
// We use it for a zoom center at cursor position command
|
|
wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED,
|
|
ID_POPUP_ZOOM_CENTER );
|
|
cmd.SetEventObject( this );
|
|
GetEventHandler()->ProcessEvent( cmd );
|
|
}
|
|
|
|
|
|
/* Calling the general function on mouse changes (and pseudo key commands) */
|
|
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 )
|
|
{
|
|
MinDragEventCount = 0;
|
|
m_CanStartBlock = -1;
|
|
}
|
|
|
|
/* A new command block can start after a release buttons
|
|
* and if the drag is enough
|
|
* This is to avoid a false start block when a dialog box is dismissed,
|
|
* or when changing panels in hierarchy navigation
|
|
* or when clicking while and moving mouse
|
|
*/
|
|
if( !event.LeftIsDown() && !event.MiddleIsDown() )
|
|
{
|
|
MinDragEventCount = 0;
|
|
m_CanStartBlock = 0;
|
|
|
|
/* Remember the last cursor position when a drag mouse starts
|
|
* this is the last position ** before ** clicking a button
|
|
* this is useful to start a block command from the point where the
|
|
* mouse was clicked first
|
|
* (a filter creates a delay for the real block command start, and
|
|
* we must remember this point)
|
|
*/
|
|
m_CursorStartPos = screen->m_Curseur;
|
|
}
|
|
|
|
if( m_Block_Enable && !(localbutt & GR_M_DCLICK) )
|
|
{
|
|
if( ( screen->m_BlockLocate.m_Command == BLOCK_IDLE )
|
|
|| ( screen->m_BlockLocate.m_State == STATE_NO_BLOCK ) )
|
|
{
|
|
screen->m_BlockLocate.SetOrigin( m_CursorStartPos );
|
|
}
|
|
if( event.LeftDown() || event.MiddleDown() )
|
|
{
|
|
if( screen->m_BlockLocate.m_State == STATE_BLOCK_MOVE )
|
|
{
|
|
m_AutoPAN_Request = false;
|
|
m_Parent->HandleBlockPlace( &DC );
|
|
s_IgnoreNextLeftButtonRelease = true;
|
|
}
|
|
}
|
|
else if( ( m_CanStartBlock >= 0 )
|
|
&& ( event.LeftIsDown() || event.MiddleIsDown() )
|
|
&& ManageCurseur == NULL
|
|
&& ForceCloseManageCurseur == NULL )
|
|
{
|
|
// Mouse is dragging: if no block in progress, start a block
|
|
// command.
|
|
if( screen->m_BlockLocate.m_State == STATE_NO_BLOCK )
|
|
{
|
|
// Start a block command
|
|
int cmd_type = kbstat;
|
|
|
|
if( event.MiddleIsDown() )
|
|
cmd_type |= MOUSE_MIDDLE;
|
|
|
|
/* A block command is started if the drag is enough. A small
|
|
* drag is ignored (it is certainly a little mouse move when
|
|
* clicking) not really a drag mouse
|
|
*/
|
|
if( MinDragEventCount < MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND )
|
|
MinDragEventCount++;
|
|
else
|
|
{
|
|
if( !m_Parent->HandleBlockBegin( &DC, cmd_type,
|
|
m_CursorStartPos ) )
|
|
{
|
|
// should not occurs: error
|
|
m_Parent->DisplayToolMsg(
|
|
wxT( "WinEDA_DrawPanel::OnMouseEvent() Block Error" ) );
|
|
}
|
|
else
|
|
{
|
|
m_AutoPAN_Request = TRUE;
|
|
SetCursor( m_PanelCursor = wxCURSOR_SIZING );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( event.ButtonUp( wxMOUSE_BTN_LEFT ) || event.ButtonUp( wxMOUSE_BTN_MIDDLE ) )
|
|
{
|
|
/* Release the mouse button: end of block.
|
|
* The command can finish (DELETE) or have a next command (MOVE,
|
|
* COPY). However the block command is canceled if the block
|
|
* size is small because a block command filtering is already
|
|
* made, this case happens, but only when the on grid cursor has
|
|
* not moved.
|
|
*/
|
|
#define BLOCK_MINSIZE_LIMIT 1
|
|
bool BlockIsSmall =
|
|
( ABS( screen->Scale( screen->m_BlockLocate.GetWidth() ) )
|
|
< BLOCK_MINSIZE_LIMIT)
|
|
&& ( ABS( screen->Scale( screen->m_BlockLocate.GetHeight() ) )
|
|
< BLOCK_MINSIZE_LIMIT);
|
|
|
|
if( (screen->m_BlockLocate.m_State
|
|
!= STATE_NO_BLOCK) && BlockIsSmall )
|
|
{
|
|
if( ForceCloseManageCurseur )
|
|
{
|
|
ForceCloseManageCurseur( this, &DC );
|
|
m_AutoPAN_Request = false;
|
|
}
|
|
SetCursor( m_PanelCursor = m_PanelDefaultCursor );
|
|
}
|
|
else if( screen->m_BlockLocate.m_State == STATE_BLOCK_END )
|
|
{
|
|
m_AutoPAN_Request = false;
|
|
m_Parent->HandleBlockEnd( &DC );
|
|
SetCursor( m_PanelCursor = m_PanelDefaultCursor );
|
|
if( screen->m_BlockLocate.m_State == STATE_BLOCK_MOVE )
|
|
{
|
|
m_AutoPAN_Request = TRUE;
|
|
SetCursor( m_PanelCursor = wxCURSOR_HAND );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// End of block command on a double click
|
|
// To avoid an unwanted block move command if the mouse is moved while
|
|
// double clicking
|
|
if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) )
|
|
{
|
|
if( screen->m_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->m_BlockLocate.m_State,
|
|
screen->m_BlockLocate.m_Command );
|
|
m_Parent->PrintMsg( msg_debug );
|
|
#endif
|
|
|
|
LastPanel = this;
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::OnKeyEvent( wxKeyEvent& event )
|
|
{
|
|
long key, localkey;
|
|
bool escape = false;
|
|
wxPoint pos;
|
|
|
|
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 WXK_ALT:
|
|
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;
|
|
|
|
/* Normalize keys code to easily handle keys from Ctrl+A to Ctrl+Z
|
|
* They have an ascii code from 1 to 27 remapped
|
|
* to GR_KB_CTRL + 'A' to GR_KB_CTRL + 'Z'
|
|
*/
|
|
if( (localkey > GR_KB_CTRL) && (localkey <= GR_KB_CTRL+26) )
|
|
localkey += 'A' - 1;
|
|
|
|
INSTALL_DC( DC, this );
|
|
|
|
BASE_SCREEN* Screen = GetScreen();
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
/* Some key commands use the current mouse position: refresh it */
|
|
pos = CalcUnscrolledPosition( wxGetMousePosition() - GetScreenPosition() );
|
|
|
|
/* Compute cursor position in screen units (pixel) including the
|
|
* current scroll bar position. Also known as device units to wxDC. */
|
|
Screen->m_MousePositionInPixels = pos;
|
|
|
|
/* Compute the cursor position in drawing units. Also known as logical units
|
|
* to wxDC. */
|
|
Screen->m_MousePosition = CursorRealPosition( pos );
|
|
|
|
m_Parent->GeneralControle( &DC, pos );
|
|
|
|
#if 0
|
|
event.Skip(); // Allow menu shortcut processing
|
|
#endif
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::OnPan( wxCommandEvent& event )
|
|
{
|
|
int x, y;
|
|
int ppux, ppuy;
|
|
int unitsX, unitsY;
|
|
int maxX, maxY;
|
|
|
|
GetViewStart( &x, &y );
|
|
GetScrollPixelsPerUnit( &ppux, &ppuy );
|
|
GetVirtualSize( &unitsX, &unitsY );
|
|
maxX = unitsX;
|
|
maxY = unitsY;
|
|
unitsX /= ppux;
|
|
unitsY /= ppuy;
|
|
|
|
switch( event.GetId() )
|
|
{
|
|
case ID_PAN_UP:
|
|
y -= m_scrollIncrementY;
|
|
break;
|
|
|
|
case ID_PAN_DOWN:
|
|
y += m_scrollIncrementY;
|
|
break;
|
|
|
|
case ID_PAN_LEFT:
|
|
x -= m_scrollIncrementX;
|
|
break;
|
|
|
|
case ID_PAN_RIGHT:
|
|
x += m_scrollIncrementX;
|
|
break;
|
|
|
|
default:
|
|
wxLogDebug( wxT( "Unknown ID %d in WinEDA_DrawPanel::OnPan()." ),
|
|
event.GetId() );
|
|
}
|
|
|
|
if( x < 0 )
|
|
x = 0;
|
|
if( y < 0 )
|
|
y = 0;
|
|
if( x > maxX )
|
|
x = maxX;
|
|
if( y > maxY )
|
|
y = maxY;
|
|
|
|
Scroll( x/ppux, y/ppuy );
|
|
}
|
|
|
|
|
|
void WinEDA_DrawPanel::UnManageCursor( int id, int cursor,
|
|
const wxString& title )
|
|
{
|
|
if( ManageCurseur && ForceCloseManageCurseur )
|
|
{
|
|
INSTALL_DC( dc, this );
|
|
ForceCloseManageCurseur( this, &dc );
|
|
m_AutoPAN_Request = false;
|
|
}
|
|
if( id != -1 && cursor != -1 )
|
|
{
|
|
wxASSERT( cursor > wxCURSOR_NONE && cursor < wxCURSOR_MAX );
|
|
m_Parent->SetToolID( id, cursor, title );
|
|
}
|
|
}
|