kicad-source/common/tool/common_tools.cpp
John Beard 445a9fa963 Put cursor and pan control in libcommon/tool, enable in Gerbview
Put the cursor and pan control TOOL_ACTIONs in ACTION,
and refer to them in that way.

The handlers are currently identical in Pcbnew and Cvpcb,
and Gerbview (and all canvases) can benefit from them as well
if they are in libcommon. Also saves duplicated code.

Fixes: lp:1795855
* https://bugs.launchpad.net/kicad/+bug/1795855
2018-10-04 11:41:06 +02:00

417 lines
12 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014-2016 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <tool/actions.h>
#include <tool/tool_manager.h>
#include <draw_frame.h>
#include <class_draw_panel_gal.h>
#include <view/view.h>
#include <view/view_controls.h>
#include <gal/graphics_abstraction_layer.h>
#include <base_screen.h>
#include <hotkeys.h>
#include <tool/common_tools.h>
static TOOL_ACTION ACT_toggleCursor( "common.Control.toggleCursor",
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_TOGGLE_CURSOR ),
_( "Toggle Always Show Cursor" ),
_( "Toggle display of the cursor, even when not in an interactive tool" ) );
COMMON_TOOLS::COMMON_TOOLS() :
TOOL_INTERACTIVE( "common.Control" ), m_frame( NULL )
{
}
COMMON_TOOLS::~COMMON_TOOLS()
{
}
void COMMON_TOOLS::Reset( RESET_REASON aReason )
{
m_frame = getEditFrame<EDA_DRAW_FRAME>();
}
// Cursor control
int COMMON_TOOLS::CursorControl( const TOOL_EVENT& aEvent )
{
long type = aEvent.Parameter<intptr_t>();
bool fastMove = type & ACTIONS::CURSOR_FAST_MOVE;
type &= ~ACTIONS::CURSOR_FAST_MOVE;
bool mirroredX = getView()->IsMirroredX();
VECTOR2D cursor = getViewControls()->GetRawCursorPosition( true );
VECTOR2I gridSize = VECTOR2D( m_frame->GetScreen()->GetGridSize() );
if( fastMove )
gridSize = gridSize * 10;
switch( type )
{
case ACTIONS::CURSOR_UP:
cursor -= VECTOR2D( 0, gridSize.y );
break;
case ACTIONS::CURSOR_DOWN:
cursor += VECTOR2D( 0, gridSize.y );
break;
case ACTIONS::CURSOR_LEFT:
cursor -= VECTOR2D( mirroredX ? -gridSize.x : gridSize.x, 0 );
break;
case ACTIONS::CURSOR_RIGHT:
cursor += VECTOR2D( mirroredX ? -gridSize.x : gridSize.x, 0 );
break;
case ACTIONS::CURSOR_CLICK: // fall through
case ACTIONS::CURSOR_DBL_CLICK:
{
TOOL_ACTIONS action = TA_NONE;
int modifiers = 0;
modifiers |= wxGetKeyState( WXK_SHIFT ) ? MD_SHIFT : 0;
modifiers |= wxGetKeyState( WXK_CONTROL ) ? MD_CTRL : 0;
modifiers |= wxGetKeyState( WXK_ALT ) ? MD_ALT : 0;
if( type == ACTIONS::CURSOR_CLICK )
action = TA_MOUSE_CLICK;
else if( type == ACTIONS::CURSOR_DBL_CLICK )
action = TA_MOUSE_DBLCLICK;
else
wxFAIL;
TOOL_EVENT evt( TC_MOUSE, action, BUT_LEFT | modifiers );
evt.SetMousePosition( getViewControls()->GetCursorPosition() );
m_toolMgr->ProcessEvent( evt );
return 0;
}
break;
}
getViewControls()->SetCursorPosition( cursor );
return 0;
}
int COMMON_TOOLS::PanControl( const TOOL_EVENT& aEvent )
{
long type = aEvent.Parameter<intptr_t>();
KIGFX::VIEW* view = getView();
VECTOR2D center = view->GetCenter();
VECTOR2I gridSize = VECTOR2D( m_frame->GetScreen()->GetGridSize() ) * 10;
bool mirroredX = view->IsMirroredX();
switch( type )
{
case ACTIONS::CURSOR_UP:
center -= VECTOR2D( 0, gridSize.y );
break;
case ACTIONS::CURSOR_DOWN:
center += VECTOR2D( 0, gridSize.y );
break;
case ACTIONS::CURSOR_LEFT:
center -= VECTOR2D( mirroredX ? -gridSize.x : gridSize.x, 0 );
break;
case ACTIONS::CURSOR_RIGHT:
center += VECTOR2D( mirroredX ? -gridSize.x : gridSize.x, 0 );
break;
default:
wxFAIL;
break;
}
view->SetCenter( center );
return 0;
}
int COMMON_TOOLS::ZoomInOut( const TOOL_EVENT& aEvent )
{
bool direction = aEvent.IsAction( &ACTIONS::zoomIn );
return doZoomInOut( direction, true );
}
int COMMON_TOOLS::ZoomInOutCenter( const TOOL_EVENT& aEvent )
{
bool direction = aEvent.IsAction( &ACTIONS::zoomInCenter );
return doZoomInOut( direction, false );
}
int COMMON_TOOLS::doZoomInOut( bool aDirection, bool aCenterOnCursor )
{
double zoom = m_frame->GetGalCanvas()->GetLegacyZoom();
// Step must be AT LEAST 1.3
if( aDirection )
zoom /= 1.3;
else
zoom *= 1.3;
// Now look for the next closest menu step
std::vector<double>& zoomList = m_frame->GetScreen()->m_ZoomList;
int idx;
if( aDirection )
{
for( idx = zoomList.size() - 1; idx >= 0; --idx )
{
if( zoomList[idx] <= zoom )
break;
}
if( idx < 0 )
idx = 0; // if we ran off the end then peg to the end
}
else
{
for( idx = 0; idx < (int)zoomList.size(); ++idx )
{
if( zoomList[idx] >= zoom )
break;
}
if( idx >= (int)zoomList.size() )
idx = zoomList.size() - 1; // if we ran off the end then peg to the end
}
return doZoomToPreset( idx + 1, aCenterOnCursor );
}
int COMMON_TOOLS::ZoomCenter( const TOOL_EVENT& aEvent )
{
KIGFX::VIEW_CONTROLS* ctls = getViewControls();
ctls->CenterOnCursor();
return 0;
}
int COMMON_TOOLS::ZoomFitScreen( const TOOL_EVENT& aEvent )
{
KIGFX::VIEW* view = getView();
EDA_DRAW_PANEL_GAL* galCanvas = m_frame->GetGalCanvas();
EDA_ITEM* model = getModel<EDA_ITEM>();
EDA_BASE_FRAME* frame = getEditFrame<EDA_BASE_FRAME>();
BOX2I bBox = model->ViewBBox();
VECTOR2D scrollbarSize = VECTOR2D( galCanvas->GetSize() - galCanvas->GetClientSize() );
VECTOR2D screenSize = view->ToWorld( galCanvas->GetClientSize(), false );
if( bBox.GetWidth() == 0 || bBox.GetHeight() == 0 )
{
bBox = galCanvas->GetDefaultViewBBox();
}
VECTOR2D vsize = bBox.GetSize();
double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
fabs( vsize.y / screenSize.y ) );
// Reserve a 10% margin around component bounding box.
double margin_scale_factor = 1.1;
// Leave 20% for library editors & viewers
if( frame->IsType( FRAME_PCB_MODULE_VIEWER ) || frame->IsType( FRAME_PCB_MODULE_VIEWER_MODAL )
|| frame->IsType( FRAME_SCH_VIEWER ) || frame->IsType( FRAME_SCH_VIEWER_MODAL )
|| frame->IsType( FRAME_SCH_LIB_EDITOR ) || frame->IsType( FRAME_PCB_MODULE_EDITOR ) )
{
margin_scale_factor = 1.2;
}
view->SetScale( scale / margin_scale_factor );
view->SetCenter( bBox.Centre() );
// Take scrollbars into account
VECTOR2D worldScrollbarSize = view->ToWorld( scrollbarSize, false );
view->SetCenter( view->GetCenter() + worldScrollbarSize / 2.0 );
return 0;
}
int COMMON_TOOLS::CenterContents( const TOOL_EVENT& aEvent )
{
EDA_DRAW_PANEL_GAL* galCanvas = m_frame->GetGalCanvas();
BOX2I bBox = getModel<EDA_ITEM>()->ViewBBox();
if( bBox.GetWidth() == 0 || bBox.GetHeight() == 0 )
bBox = galCanvas->GetDefaultViewBBox();
getView()->SetCenter( bBox.Centre() );
// Take scrollbars into account
VECTOR2D scrollbarSize = VECTOR2D( galCanvas->GetSize() - galCanvas->GetClientSize() );
VECTOR2D worldScrollbarSize = getView()->ToWorld( scrollbarSize, false );
getView()->SetCenter( getView()->GetCenter() + worldScrollbarSize / 2.0 );
return 0;
}
int COMMON_TOOLS::ZoomPreset( const TOOL_EVENT& aEvent )
{
unsigned int idx = aEvent.Parameter<intptr_t>();
return doZoomToPreset( idx, false );
}
// Note: idx == 0 is Auto; idx == 1 is first entry in zoomList
int COMMON_TOOLS::doZoomToPreset( int idx, bool aCenterOnCursor )
{
std::vector<double>& zoomList = m_frame->GetScreen()->m_ZoomList;
KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView();
KIGFX::GAL* gal = m_frame->GetGalCanvas()->GetGAL();
m_frame->SetPresetZoom( idx );
if( idx == 0 ) // Zoom Auto
{
TOOL_EVENT dummy;
return ZoomFitScreen( dummy );
}
else
idx--;
double selectedZoom = zoomList[idx];
double zoomFactor = gal->GetWorldScale() / gal->GetZoomFactor();
double scale = 1.0 / ( zoomFactor * selectedZoom );
if( aCenterOnCursor )
{
view->SetScale( scale, getViewControls()->GetCursorPosition() );
if( getViewControls()->IsCursorWarpingEnabled() )
getViewControls()->CenterOnCursor();
}
else
view->SetScale( scale );
return 0;
}
// Grid control
int COMMON_TOOLS::GridNext( const TOOL_EVENT& aEvent )
{
m_frame->SetNextGrid();
updateGrid();
return 0;
}
int COMMON_TOOLS::GridPrev( const TOOL_EVENT& aEvent )
{
m_frame->SetPrevGrid();
updateGrid();
return 0;
}
int COMMON_TOOLS::GridPreset( const TOOL_EVENT& aEvent )
{
long idx = aEvent.Parameter<intptr_t>();
m_frame->SetPresetGrid( idx );
updateGrid();
return 0;
}
int COMMON_TOOLS::ToggleCursor( const TOOL_EVENT& aEvent )
{
auto& galOpts = m_frame->GetGalDisplayOptions();
galOpts.m_forceDisplayCursor = !galOpts.m_forceDisplayCursor;
galOpts.NotifyChanged();
return 0;
}
void COMMON_TOOLS::setTransitions()
{
// Cursor control
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorUp.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorDown.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorLeft.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorRight.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorUpFast.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorDownFast.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorLeftFast.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorRightFast.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorClick.MakeEvent() );
Go( &COMMON_TOOLS::CursorControl, ACTIONS::cursorDblClick.MakeEvent() );
// Pan control
Go( &COMMON_TOOLS::PanControl, ACTIONS::panUp.MakeEvent() );
Go( &COMMON_TOOLS::PanControl, ACTIONS::panDown.MakeEvent() );
Go( &COMMON_TOOLS::PanControl, ACTIONS::panLeft.MakeEvent() );
Go( &COMMON_TOOLS::PanControl, ACTIONS::panRight.MakeEvent() );
// Zoom control
Go( &COMMON_TOOLS::ZoomInOut, ACTIONS::zoomIn.MakeEvent() );
Go( &COMMON_TOOLS::ZoomInOut, ACTIONS::zoomOut.MakeEvent() );
Go( &COMMON_TOOLS::ZoomInOutCenter, ACTIONS::zoomInCenter.MakeEvent() );
Go( &COMMON_TOOLS::ZoomInOutCenter, ACTIONS::zoomOutCenter.MakeEvent() );
Go( &COMMON_TOOLS::ZoomCenter, ACTIONS::zoomCenter.MakeEvent() );
Go( &COMMON_TOOLS::ZoomFitScreen, ACTIONS::zoomFitScreen.MakeEvent() );
Go( &COMMON_TOOLS::ZoomPreset, ACTIONS::zoomPreset.MakeEvent() );
Go( &COMMON_TOOLS::CenterContents, ACTIONS::centerContents.MakeEvent() );
Go( &COMMON_TOOLS::GridNext, ACTIONS::gridNext.MakeEvent() );
Go( &COMMON_TOOLS::GridPrev, ACTIONS::gridPrev.MakeEvent() );
Go( &COMMON_TOOLS::GridPreset, ACTIONS::gridPreset.MakeEvent() );
Go( &COMMON_TOOLS::ToggleCursor, ACT_toggleCursor.MakeEvent() );
}
void COMMON_TOOLS::updateGrid()
{
BASE_SCREEN* screen = m_frame->GetScreen();
getView()->GetGAL()->SetGridSize( VECTOR2D( screen->GetGridSize() ) );
getView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED );
}