GerbView GAL support part 2: New files for GAL
- New draw panel - New painter - GerbView-specific tools
This commit is contained in:
parent
915e51e1f0
commit
050489d719
|
@ -41,6 +41,7 @@ Mateusz Skowroński <skowri[at]gmail-dot-com>
|
||||||
Cheng Sheng <chengsheng[at]google-dot-com> Google Inc.
|
Cheng Sheng <chengsheng[at]google-dot-com> Google Inc.
|
||||||
Kristoffer Ödmark <kristoffer.odmark90[at]gmail-dot-com>
|
Kristoffer Ödmark <kristoffer.odmark90[at]gmail-dot-com>
|
||||||
Oliver Walters <oliver.henry.walters[at]gmail-dot-com>
|
Oliver Walters <oliver.henry.walters[at]gmail-dot-com>
|
||||||
|
Jon Evans <jon[at]craftyjon-dot-com>
|
||||||
|
|
||||||
See also CHANGELOG.txt for contributors.
|
See also CHANGELOG.txt for contributors.
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,14 @@ set( GERBVIEW_SRCS
|
||||||
rs274x.cpp
|
rs274x.cpp
|
||||||
select_layers_to_pcb.cpp
|
select_layers_to_pcb.cpp
|
||||||
toolbars_gerber.cpp
|
toolbars_gerber.cpp
|
||||||
|
|
||||||
|
gerbview_draw_panel_gal.cpp
|
||||||
|
gerbview_painter.cpp
|
||||||
|
|
||||||
|
tools/gerbview_actions.cpp
|
||||||
|
tools/selection_tool.cpp
|
||||||
|
tools/gerbview_control.cpp
|
||||||
|
gerber_collectors.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set( GERBVIEW_EXTRA_SRCS
|
set( GERBVIEW_EXTRA_SRCS
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gerber_collectors.h"
|
||||||
|
|
||||||
|
const KICAD_T GERBER_COLLECTOR::AllItems[] = {
|
||||||
|
GERBER_IMAGE_LIST_T,
|
||||||
|
GERBER_IMAGE_T,
|
||||||
|
GERBER_DRAW_ITEM_T,
|
||||||
|
EOT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Inspect
|
||||||
|
* is the examining function within the INSPECTOR which is passed to the
|
||||||
|
* Iterate function. Searches and collects all the objects that the old
|
||||||
|
* function PcbGeneralLocateAndDisplay() would find, except that it keeps all
|
||||||
|
* that it finds and does not do any displaying.
|
||||||
|
*
|
||||||
|
* @param testItem An EDA_ITEM to examine.
|
||||||
|
* @param testData not used here.
|
||||||
|
* @return SEARCH_RESULT - SEARCH_QUIT if the Iterator is to stop the scan,
|
||||||
|
* else SCAN_CONTINUE;
|
||||||
|
*/
|
||||||
|
SEARCH_RESULT GERBER_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
|
||||||
|
{
|
||||||
|
if( testItem->HitTest( m_RefPos ) )
|
||||||
|
Append( testItem );
|
||||||
|
|
||||||
|
return SEARCH_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBER_COLLECTOR::Collect( EDA_ITEM* aItem, const KICAD_T aScanList[],
|
||||||
|
const wxPoint& aRefPos/*, const COLLECTORS_GUIDE& aGuide*/ )
|
||||||
|
{
|
||||||
|
Empty(); // empty the collection, primary criteria list
|
||||||
|
|
||||||
|
// remember guide, pass it to Inspect()
|
||||||
|
//SetGuide( &aGuide );
|
||||||
|
|
||||||
|
SetScanTypes( aScanList );
|
||||||
|
|
||||||
|
// remember where the snapshot was taken from and pass refPos to
|
||||||
|
// the Inspect() function.
|
||||||
|
SetRefPos( aRefPos );
|
||||||
|
|
||||||
|
aItem->Visit( m_inspector, NULL, m_ScanTypes );
|
||||||
|
|
||||||
|
SetTimeNow(); // when snapshot was taken
|
||||||
|
|
||||||
|
// record the length of the primary list before concatenating on to it.
|
||||||
|
m_PrimaryLength = m_List.size();
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GERBER_COLLECTORS_H
|
||||||
|
#define GERBER_COLLECTORS_H
|
||||||
|
|
||||||
|
#include <class_collector.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GERBER_COLLECTOR
|
||||||
|
* is intended for use when the right click button is pressed, or when the
|
||||||
|
* plain "arrow" tool is in effect.
|
||||||
|
*/
|
||||||
|
class GERBER_COLLECTOR : public COLLECTOR
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* A place to hold collected objects which don't match precisely the search
|
||||||
|
* criteria, but would be acceptable if nothing else is found.
|
||||||
|
* "2nd" choice, which will be appended to the end of COLLECTOR's prime
|
||||||
|
* "list" at the end of the search.
|
||||||
|
*/
|
||||||
|
std::vector<EDA_ITEM*> m_List2nd;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines which items are to be collected by Inspect()
|
||||||
|
*/
|
||||||
|
//const COLLECTORS_GUIDE* m_Guide;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of items that were originally in the primary list before the
|
||||||
|
* m_List2nd was concatenated onto the end of it.
|
||||||
|
*/
|
||||||
|
int m_PrimaryLength;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A scan list for all selectable gerber items
|
||||||
|
*/
|
||||||
|
static const KICAD_T AllItems[];
|
||||||
|
|
||||||
|
GERBER_COLLECTOR()
|
||||||
|
{
|
||||||
|
//m_Guide = NULL;
|
||||||
|
m_PrimaryLength = 0;
|
||||||
|
SetScanTypes( AllItems );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Empty2nd()
|
||||||
|
{
|
||||||
|
m_List2nd.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*void Append2nd( BOARD_ITEM* item )
|
||||||
|
{
|
||||||
|
m_List2nd.push_back( item );
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetGuide
|
||||||
|
* records which COLLECTORS_GUIDE to use.
|
||||||
|
* @param aGuide Which guide to use in the collection.
|
||||||
|
*/
|
||||||
|
//void SetGuide( const COLLECTORS_GUIDE* aGuide ) { m_Guide = aGuide; }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function operator[int]
|
||||||
|
* overloads COLLECTOR::operator[](int) to return a EDA_ITEM* instead of
|
||||||
|
* an EDA_ITEM* type.
|
||||||
|
* @param ndx The index into the list.
|
||||||
|
* @return EDA_ITEM* - or something derived from it, or NULL.
|
||||||
|
*/
|
||||||
|
EDA_ITEM* operator[]( int ndx ) const
|
||||||
|
{
|
||||||
|
if( (unsigned)ndx < (unsigned)GetCount() )
|
||||||
|
return (EDA_ITEM*) m_List[ ndx ];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetPrimaryCount
|
||||||
|
* @return int - The number if items which met the primary search criteria
|
||||||
|
*/
|
||||||
|
int GetPrimaryCount() { return m_PrimaryLength; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Inspect
|
||||||
|
* is the examining function within the INSPECTOR which is passed to the
|
||||||
|
* Iterate function.
|
||||||
|
*
|
||||||
|
* @param testItem An EDA_ITEM to examine.
|
||||||
|
* @param testData is not used in this class.
|
||||||
|
* @return SEARCH_RESULT - SEARCH_QUIT if the Iterator is to stop the scan,
|
||||||
|
* else SCAN_CONTINUE;
|
||||||
|
*/
|
||||||
|
SEARCH_RESULT Inspect( EDA_ITEM* testItem, void* testData ) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Collect
|
||||||
|
* scans an EDA_ITEM using this class's Inspector method, which does the collection.
|
||||||
|
* @param aItem An EDA_ITEM to scan
|
||||||
|
* @param aScanList A list of KICAD_Ts with a terminating EOT, that specs
|
||||||
|
* what is to be collected and the priority order of the resultant
|
||||||
|
* collection in "m_List".
|
||||||
|
* @param aRefPos A wxPoint to use in hit-testing.
|
||||||
|
* @param aGuide The COLLECTORS_GUIDE to use in collecting items.
|
||||||
|
*/
|
||||||
|
void Collect( EDA_ITEM* aItem, const KICAD_T aScanList[],
|
||||||
|
const wxPoint& aRefPos/*, const COLLECTORS_GUIDE& aGuide */);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gerbview_draw_panel_gal.h"
|
||||||
|
#include <view/view.h>
|
||||||
|
#include <view/wx_view_controls.h>
|
||||||
|
#include <gerbview_painter.h>
|
||||||
|
|
||||||
|
#include <class_colors_design_settings.h>
|
||||||
|
#include <gerbview_frame.h>
|
||||||
|
#include <class_gbr_display_options.h>
|
||||||
|
#include <gal/graphics_abstraction_layer.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
|
||||||
|
GERBVIEW_DRAW_PANEL_GAL::GERBVIEW_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWindowId,
|
||||||
|
const wxPoint& aPosition, const wxSize& aSize,
|
||||||
|
KIGFX::GAL_DISPLAY_OPTIONS& aOptions, GAL_TYPE aGalType ) :
|
||||||
|
EDA_DRAW_PANEL_GAL( aParentWindow, aWindowId, aPosition, aSize, aOptions, aGalType )
|
||||||
|
{
|
||||||
|
setDefaultLayerDeps();
|
||||||
|
|
||||||
|
m_painter = new KIGFX::GERBVIEW_PAINTER( m_gal );
|
||||||
|
m_view->SetPainter( m_painter );
|
||||||
|
|
||||||
|
// Load display options (such as filled/outline display of items).
|
||||||
|
auto frame = static_cast< GERBVIEW_FRAME* >( GetParentEDAFrame() );
|
||||||
|
|
||||||
|
if( frame )
|
||||||
|
{
|
||||||
|
auto displ_opts = (GBR_DISPLAY_OPTIONS*) frame->GetDisplayOptions();
|
||||||
|
static_cast<KIGFX::GERBVIEW_RENDER_SETTINGS*>( m_view->GetPainter()->GetSettings() )->LoadDisplayOptions( displ_opts );
|
||||||
|
UseColorScheme( frame->m_colorsSettings );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GERBVIEW_DRAW_PANEL_GAL::~GERBVIEW_DRAW_PANEL_GAL()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_DRAW_PANEL_GAL::UseColorScheme( const COLORS_DESIGN_SETTINGS* aSettings )
|
||||||
|
{
|
||||||
|
KIGFX::GERBVIEW_RENDER_SETTINGS* rs;
|
||||||
|
rs = static_cast<KIGFX::GERBVIEW_RENDER_SETTINGS*>( m_view->GetPainter()->GetSettings() );
|
||||||
|
rs->ImportLegacyColors( aSettings );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_DRAW_PANEL_GAL::SetHighContrastLayer( int aLayer )
|
||||||
|
{
|
||||||
|
// Set display settings for high contrast mode
|
||||||
|
KIGFX::RENDER_SETTINGS* rSettings = m_view->GetPainter()->GetSettings();
|
||||||
|
|
||||||
|
SetTopLayer( aLayer );
|
||||||
|
|
||||||
|
rSettings->ClearActiveLayers();
|
||||||
|
rSettings->SetActiveLayer( aLayer );
|
||||||
|
rSettings->SetActiveLayer( GERBER_DCODE_LAYER( aLayer ) );
|
||||||
|
|
||||||
|
m_view->UpdateAllLayersColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_DRAW_PANEL_GAL::GetMsgPanelInfo( std::vector<MSG_PANEL_ITEM>& aList )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_DRAW_PANEL_GAL::OnShow()
|
||||||
|
{
|
||||||
|
GERBVIEW_FRAME* frame = dynamic_cast<GERBVIEW_FRAME*>( GetParent() );
|
||||||
|
|
||||||
|
if( frame )
|
||||||
|
{
|
||||||
|
SetTopLayer( frame->GetActiveLayer() );
|
||||||
|
GBR_DISPLAY_OPTIONS* displ_opts = (GBR_DISPLAY_OPTIONS*) frame->GetDisplayOptions();
|
||||||
|
static_cast<KIGFX::GERBVIEW_RENDER_SETTINGS*>(
|
||||||
|
m_view->GetPainter()->GetSettings() )->LoadDisplayOptions( displ_opts );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_view->RecacheAllItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_DRAW_PANEL_GAL::SwitchBackend( GAL_TYPE aGalType )
|
||||||
|
{
|
||||||
|
bool rv = EDA_DRAW_PANEL_GAL::SwitchBackend( aGalType );
|
||||||
|
setDefaultLayerDeps();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_DRAW_PANEL_GAL::setDefaultLayerDeps()
|
||||||
|
{
|
||||||
|
// caching makes no sense for Cairo and other software renderers
|
||||||
|
auto target = m_backend == GAL_TYPE_OPENGL ? KIGFX::TARGET_CACHED : KIGFX::TARGET_NONCACHED;
|
||||||
|
|
||||||
|
for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; i++ )
|
||||||
|
m_view->SetLayerTarget( i, target );
|
||||||
|
|
||||||
|
// for( int i = GERBVIEW_LAYER_ID_START; i < GERBVIEW_LAYER_ID_RESERVED; i++ )
|
||||||
|
// m_view->SetLayerDisplayOnly( i );
|
||||||
|
|
||||||
|
m_view->SetLayerDisplayOnly( LAYER_DCODES );
|
||||||
|
m_view->SetLayerDisplayOnly( LAYER_NEGATIVE_OBJECTS );
|
||||||
|
m_view->SetLayerDisplayOnly( LAYER_GERBVIEW_GRID );
|
||||||
|
m_view->SetLayerDisplayOnly( LAYER_GERBVIEW_AXES );
|
||||||
|
m_view->SetLayerDisplayOnly( LAYER_GERBVIEW_BACKGROUND );
|
||||||
|
|
||||||
|
m_view->SetLayerTarget( LAYER_GP_OVERLAY , KIGFX::TARGET_OVERLAY );
|
||||||
|
m_view->SetLayerDisplayOnly( LAYER_GP_OVERLAY );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_DRAW_PANEL_GAL::SetTopLayer( int aLayer )
|
||||||
|
{
|
||||||
|
m_view->ClearTopLayers();
|
||||||
|
|
||||||
|
for( int i = 0; i < GERBER_DRAWLAYERS_COUNT; ++i )
|
||||||
|
{
|
||||||
|
m_view->SetLayerOrder( GERBER_DCODE_LAYER( GERBER_DRAW_LAYER( i ) ), 2 * i );
|
||||||
|
m_view->SetLayerOrder( i, ( 2 * i ) + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_view->SetTopLayer( aLayer );
|
||||||
|
|
||||||
|
// Move DCODE layer to the top
|
||||||
|
m_view->SetTopLayer( GERBER_DCODE_LAYER( aLayer ) );
|
||||||
|
|
||||||
|
m_view->SetTopLayer( LAYER_GP_OVERLAY );
|
||||||
|
|
||||||
|
m_view->UpdateAllLayersOrder();
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GERBVIEW_DRAW_PANEL_GAL_H_
|
||||||
|
#define GERBVIEW_DRAW_PANEL_GAL_H_
|
||||||
|
|
||||||
|
#include <class_draw_panel_gal.h>
|
||||||
|
|
||||||
|
class COLORS_DESIGN_SETTINGS;
|
||||||
|
|
||||||
|
|
||||||
|
class GERBVIEW_DRAW_PANEL_GAL : public EDA_DRAW_PANEL_GAL
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GERBVIEW_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWindowId, const wxPoint& aPosition,
|
||||||
|
const wxSize& aSize, KIGFX::GAL_DISPLAY_OPTIONS& aOptions,
|
||||||
|
GAL_TYPE aGalType = GAL_TYPE_OPENGL );
|
||||||
|
|
||||||
|
virtual ~GERBVIEW_DRAW_PANEL_GAL();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function UseColorScheme
|
||||||
|
* Applies layer color settings.
|
||||||
|
* @param aSettings are the new settings.
|
||||||
|
*/
|
||||||
|
void UseColorScheme( const COLORS_DESIGN_SETTINGS* aSettings );
|
||||||
|
|
||||||
|
///> @copydoc EDA_DRAW_PANEL_GAL::SetHighContrastLayer()
|
||||||
|
virtual void SetHighContrastLayer( int aLayer ) override;
|
||||||
|
|
||||||
|
///> @copydoc EDA_DRAW_PANEL_GAL::GetMsgPanelInfo()
|
||||||
|
void GetMsgPanelInfo( std::vector<MSG_PANEL_ITEM>& aList ) override;
|
||||||
|
|
||||||
|
///> @copydoc EDA_DRAW_PANEL_GAL::OnShow()
|
||||||
|
void OnShow() override;
|
||||||
|
|
||||||
|
bool SwitchBackend( GAL_TYPE aGalType ) override;
|
||||||
|
|
||||||
|
///> @copydoc EDA_DRAW_PANEL_GAL::SetTopLayer
|
||||||
|
virtual void SetTopLayer( int aLayer ) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
///> Sets rendering targets & dependencies for layers.
|
||||||
|
void setDefaultLayerDeps();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* GERBVIEW_DRAW_PANEL_GAL_H_ */
|
|
@ -0,0 +1,563 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <class_colors_design_settings.h>
|
||||||
|
|
||||||
|
#include <gerbview_painter.h>
|
||||||
|
#include <gal/graphics_abstraction_layer.h>
|
||||||
|
#include <convert_basic_shapes_to_polygon.h>
|
||||||
|
#include <convert_to_biu.h>
|
||||||
|
#include <gerbview.h>
|
||||||
|
|
||||||
|
#include <class_gerber_draw_item.h>
|
||||||
|
#include <class_gerber_file_image.h>
|
||||||
|
|
||||||
|
using namespace KIGFX;
|
||||||
|
|
||||||
|
GERBVIEW_RENDER_SETTINGS::GERBVIEW_RENDER_SETTINGS()
|
||||||
|
{
|
||||||
|
m_backgroundColor = COLOR4D( 0.0, 0.0, 0.0, 1.0 );
|
||||||
|
|
||||||
|
m_spotFill = true;
|
||||||
|
m_lineFill = true;
|
||||||
|
m_polygonFill = true;
|
||||||
|
m_showNegativeItems = false;
|
||||||
|
m_showCodes = false;
|
||||||
|
m_diffMode = true;
|
||||||
|
|
||||||
|
m_componentHighlightString = "";
|
||||||
|
m_netHighlightString = "";
|
||||||
|
m_attributeHighlightString = "";
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_RENDER_SETTINGS::ImportLegacyColors( const COLORS_DESIGN_SETTINGS* aSettings )
|
||||||
|
{
|
||||||
|
for( int i = GERBVIEW_LAYER_ID_START;
|
||||||
|
i < GERBVIEW_LAYER_ID_START + GERBER_DRAWLAYERS_COUNT; i++ )
|
||||||
|
{
|
||||||
|
COLOR4D baseColor = aSettings->GetLayerColor( i );
|
||||||
|
m_layerColors[i] = baseColor;
|
||||||
|
m_layerColorsHi[i] = baseColor.Brightened( 0.5 );
|
||||||
|
m_layerColorsSel[i] = baseColor.Brightened( 0.8 );
|
||||||
|
m_layerColorsDark[i] = baseColor.Darkened( 0.25 );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = LAYER_DCODES; i < GERBVIEW_LAYER_ID_END; i++ )
|
||||||
|
m_layerColors[i] = aSettings->GetLayerColor( i );
|
||||||
|
|
||||||
|
for( int i = GAL_LAYER_ID_START; i < GAL_LAYER_ID_END; i++ )
|
||||||
|
m_layerColors[i] = aSettings->GetLayerColor( i );
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_RENDER_SETTINGS::LoadDisplayOptions( const GBR_DISPLAY_OPTIONS* aOptions )
|
||||||
|
{
|
||||||
|
if( aOptions == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_spotFill = aOptions->m_DisplayFlashedItemsFill;
|
||||||
|
m_lineFill = aOptions->m_DisplayLinesFill;
|
||||||
|
m_polygonFill = aOptions->m_DisplayPolygonsFill;
|
||||||
|
m_showNegativeItems = aOptions->m_DisplayNegativeObjects;
|
||||||
|
m_showCodes = aOptions->m_DisplayDCodes;
|
||||||
|
m_diffMode = aOptions->m_DiffMode;
|
||||||
|
m_hiContrastEnabled = aOptions->m_HighContrastMode;
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const COLOR4D& GERBVIEW_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const
|
||||||
|
{
|
||||||
|
const GERBER_DRAW_ITEM* item = static_cast<const GERBER_DRAW_ITEM*>( aItem );
|
||||||
|
|
||||||
|
// All DCODE layers stored under a single color setting
|
||||||
|
if( IsDCodeLayer( aLayer ) )
|
||||||
|
return m_layerColors[ LAYER_DCODES ];
|
||||||
|
|
||||||
|
if( item )
|
||||||
|
{
|
||||||
|
if( item->IsSelected() )
|
||||||
|
return m_layerColorsSel[aLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !m_netHighlightString.IsEmpty() &&
|
||||||
|
m_netHighlightString == item->GetNetAttributes().m_Netname )
|
||||||
|
return m_layerColorsHi[aLayer];
|
||||||
|
|
||||||
|
if( !m_componentHighlightString.IsEmpty() &&
|
||||||
|
m_componentHighlightString == item->GetNetAttributes().m_Cmpref )
|
||||||
|
return m_layerColorsHi[aLayer];
|
||||||
|
|
||||||
|
if( !m_attributeHighlightString.IsEmpty() && item->GetDcodeDescr() &&
|
||||||
|
m_attributeHighlightString == item->GetDcodeDescr()->m_AperFunction )
|
||||||
|
return m_layerColorsHi[aLayer];
|
||||||
|
|
||||||
|
// Return grayish color for non-highlighted layers in the high contrast mode
|
||||||
|
if( m_hiContrastEnabled && m_activeLayers.count( aLayer ) == 0)
|
||||||
|
return m_hiContrastColor;
|
||||||
|
|
||||||
|
// Catch the case when highlight and high-contraste modes are enabled
|
||||||
|
// and we are drawing a not highlighted track
|
||||||
|
if( m_highlightEnabled )
|
||||||
|
return m_layerColorsDark[aLayer];
|
||||||
|
|
||||||
|
// No special modificators enabled
|
||||||
|
return m_layerColors[aLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GERBVIEW_PAINTER::GERBVIEW_PAINTER( GAL* aGal ) :
|
||||||
|
PAINTER( aGal )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(JE): Pull up to PAINTER?
|
||||||
|
int GERBVIEW_PAINTER::getLineThickness( int aActualThickness ) const
|
||||||
|
{
|
||||||
|
// if items have 0 thickness, draw them with the outline
|
||||||
|
// width, otherwise respect the set value (which, no matter
|
||||||
|
// how small will produce something)
|
||||||
|
if( aActualThickness == 0 )
|
||||||
|
return m_gerbviewSettings.m_outlineWidth;
|
||||||
|
|
||||||
|
return aActualThickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
|
||||||
|
{
|
||||||
|
const EDA_ITEM* item = static_cast<const EDA_ITEM*>( aItem );
|
||||||
|
|
||||||
|
// the "cast" applied in here clarifies which overloaded draw() is called
|
||||||
|
switch( item->Type() )
|
||||||
|
{
|
||||||
|
case GERBER_DRAW_ITEM_T:
|
||||||
|
draw( static_cast<GERBER_DRAW_ITEM*>( const_cast<EDA_ITEM*>( item ) ), aLayer );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Painter does not know how to draw the object
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(JE) aItem can't be const because of GetDcodeDescr()
|
||||||
|
// Probably that can be refactored in GERBER_DRAW_ITEM to allow const here.
|
||||||
|
void GERBVIEW_PAINTER::draw( /*const*/ GERBER_DRAW_ITEM* aItem, int aLayer )
|
||||||
|
{
|
||||||
|
VECTOR2D start( aItem->GetABPosition( aItem->m_Start ) ); // TODO(JE) Getter
|
||||||
|
VECTOR2D end( aItem->GetABPosition( aItem->m_End ) ); // TODO(JE) Getter
|
||||||
|
int width = aItem->m_Size.x; // TODO(JE) Getter
|
||||||
|
bool isFilled = true;
|
||||||
|
COLOR4D color;
|
||||||
|
// TODO(JE) This doesn't actually work properly for ImageNegative
|
||||||
|
bool isNegative = (aItem->GetLayerPolarity() ^ aItem->m_GerberImageFile->m_ImageNegative);
|
||||||
|
|
||||||
|
// Draw DCODEs if enabled
|
||||||
|
if( IsDCodeLayer( aLayer ) )
|
||||||
|
{
|
||||||
|
if( !m_gerbviewSettings.m_showCodes )
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxString codeText;
|
||||||
|
VECTOR2D textPosition;
|
||||||
|
double textSize;
|
||||||
|
|
||||||
|
if( aItem->GetDcodeDescr() )
|
||||||
|
textSize = aItem->GetDcodeDescr()->GetShapeDim( aItem ) / 3.0;
|
||||||
|
else
|
||||||
|
textSize = std::min( aItem->m_Size.x, aItem->m_Size.y ) / 2.0;
|
||||||
|
|
||||||
|
if( aItem->m_Shape == GBR_ARC )
|
||||||
|
{
|
||||||
|
textPosition = start;
|
||||||
|
}
|
||||||
|
else if( aItem->m_Flashed )
|
||||||
|
{
|
||||||
|
BOX2I bb = aItem->ViewBBox();
|
||||||
|
textPosition = bb.Centre();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
textPosition.x = (start.x + end.x) / 2;
|
||||||
|
textPosition.y = (start.y + end.y) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = m_gerbviewSettings.GetColor( aItem, aLayer );
|
||||||
|
codeText.Printf( wxT( "D%d" ), aItem->m_DCode );
|
||||||
|
|
||||||
|
m_gal->SetIsStroke( true );
|
||||||
|
m_gal->SetIsFill( false );
|
||||||
|
m_gal->SetStrokeColor( color );
|
||||||
|
m_gal->SetFillColor( COLOR4D( 0, 0, 0, 0 ) );
|
||||||
|
m_gal->SetLineWidth( 2 );
|
||||||
|
m_gal->SetFontBold( false );
|
||||||
|
m_gal->SetFontItalic( false );
|
||||||
|
m_gal->SetTextMirrored( false );
|
||||||
|
m_gal->SetGlyphSize( VECTOR2D( textSize, textSize) );
|
||||||
|
m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
|
||||||
|
m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
|
||||||
|
m_gal->BitmapText( codeText, textPosition, 0 );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = m_gerbviewSettings.GetColor( aItem, aLayer );
|
||||||
|
|
||||||
|
if( isNegative )
|
||||||
|
{
|
||||||
|
if( m_gerbviewSettings.m_showNegativeItems )
|
||||||
|
color = m_gerbviewSettings.GetLayerColor( LAYER_NEGATIVE_OBJECTS );
|
||||||
|
else
|
||||||
|
color = COLOR4D( 0, 0, 0, 0 );
|
||||||
|
}
|
||||||
|
else if( m_gerbviewSettings.m_diffMode )
|
||||||
|
{
|
||||||
|
color.a = 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_gal->SetNegativeDrawMode( isNegative );
|
||||||
|
m_gal->SetStrokeColor( color );
|
||||||
|
m_gal->SetFillColor( color );
|
||||||
|
m_gal->SetIsFill( isFilled );
|
||||||
|
m_gal->SetIsStroke( !isFilled );
|
||||||
|
|
||||||
|
switch( aItem->m_Shape )
|
||||||
|
{
|
||||||
|
case GBR_POLYGON:
|
||||||
|
{
|
||||||
|
isFilled = m_gerbviewSettings.m_polygonFill;
|
||||||
|
m_gal->SetIsFill( isFilled );
|
||||||
|
m_gal->SetIsStroke( !isFilled );
|
||||||
|
|
||||||
|
if( isNegative && !isFilled )
|
||||||
|
{
|
||||||
|
m_gal->SetNegativeDrawMode( false );
|
||||||
|
m_gal->SetStrokeColor( GetSettings()->GetColor( aItem, aLayer ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !isFilled )
|
||||||
|
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
|
||||||
|
|
||||||
|
SHAPE_POLY_SET absolutePolygon = aItem->m_Polygon;
|
||||||
|
|
||||||
|
for( auto it = absolutePolygon.Iterate( 0 ); it; ++it )
|
||||||
|
*it = aItem->GetABPosition( *it );
|
||||||
|
|
||||||
|
if( !isFilled )
|
||||||
|
m_gal->DrawPolyline( absolutePolygon.COutline( 0 ) );
|
||||||
|
else
|
||||||
|
m_gal->DrawPolygon( absolutePolygon );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_CIRCLE:
|
||||||
|
{
|
||||||
|
isFilled = m_gerbviewSettings.m_lineFill;
|
||||||
|
double radius = GetLineLength( aItem->m_Start, aItem->m_End );
|
||||||
|
m_gal->DrawCircle( start, radius );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_ARC:
|
||||||
|
{
|
||||||
|
isFilled = m_gerbviewSettings.m_lineFill;
|
||||||
|
|
||||||
|
// Gerber arcs are 3-point (start, center, end)
|
||||||
|
// GAL needs center, radius, start angle, end angle
|
||||||
|
double radius = GetLineLength( aItem->m_Start, aItem->m_ArcCentre );
|
||||||
|
VECTOR2D center = aItem->GetABPosition( aItem->m_ArcCentre );
|
||||||
|
VECTOR2D startVec = VECTOR2D( aItem->GetABPosition( aItem->m_Start ) ) - center;
|
||||||
|
VECTOR2D endVec = VECTOR2D( aItem->GetABPosition( aItem->m_End ) ) - center;
|
||||||
|
|
||||||
|
m_gal->SetIsFill( isFilled );
|
||||||
|
m_gal->SetIsStroke( !isFilled );
|
||||||
|
m_gal->SetLineWidth( isFilled ? width : m_gerbviewSettings.m_outlineWidth );
|
||||||
|
|
||||||
|
double startAngle = startVec.Angle();
|
||||||
|
double endAngle = endVec.Angle();
|
||||||
|
|
||||||
|
if( endAngle >= M_PI )
|
||||||
|
endAngle *= -1;
|
||||||
|
|
||||||
|
// 360-degree arcs are stored in the file with start equal to end
|
||||||
|
if( aItem->m_Start == aItem->m_End )
|
||||||
|
{
|
||||||
|
startAngle = 0;
|
||||||
|
endAngle = 2 * M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_gal->DrawArcSegment( center, radius, startAngle, endAngle, width );
|
||||||
|
|
||||||
|
// Arc Debugging
|
||||||
|
// m_gal->SetLineWidth( 5 );
|
||||||
|
// m_gal->SetStrokeColor( COLOR4D( 0.0, 1.0, 0.0, 1.0 ) );
|
||||||
|
// m_gal->DrawLine( center, aItem->GetABPosition( aItem->m_Start ) );
|
||||||
|
// m_gal->SetStrokeColor( COLOR4D( 1.0, 0.0, 0.0, 1.0 ) );
|
||||||
|
// m_gal->DrawLine( center, aItem->GetABPosition( aItem->m_End ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_SPOT_CIRCLE:
|
||||||
|
case GBR_SPOT_RECT:
|
||||||
|
case GBR_SPOT_OVAL:
|
||||||
|
case GBR_SPOT_POLY:
|
||||||
|
case GBR_SPOT_MACRO:
|
||||||
|
{
|
||||||
|
isFilled = m_gerbviewSettings.m_spotFill;
|
||||||
|
drawFlashedShape( aItem, isFilled );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_SEGMENT:
|
||||||
|
{
|
||||||
|
/* Plot a line from m_Start to m_End.
|
||||||
|
* Usually, a round pen is used, but some gerber files use a rectangular pen
|
||||||
|
* In fact, any aperture can be used to plot a line.
|
||||||
|
* currently: only a square pen is handled (I believe using a polygon gives a strange plot).
|
||||||
|
*/
|
||||||
|
isFilled = m_gerbviewSettings.m_lineFill;
|
||||||
|
m_gal->SetIsFill( isFilled );
|
||||||
|
m_gal->SetIsStroke( !isFilled );
|
||||||
|
|
||||||
|
if( isNegative && !isFilled )
|
||||||
|
m_gal->SetStrokeColor( GetSettings()->GetColor( aItem, aLayer ) );
|
||||||
|
|
||||||
|
// TODO(JE) Refactor this to allow const aItem
|
||||||
|
D_CODE* code = aItem->GetDcodeDescr();
|
||||||
|
if( code && code->m_Shape == APT_RECT )
|
||||||
|
{
|
||||||
|
if( aItem->m_Polygon.OutlineCount() == 0 )
|
||||||
|
aItem->ConvertSegmentToPolygon();
|
||||||
|
drawPolygon( aItem, aItem->m_Polygon, isFilled );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !isFilled )
|
||||||
|
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
|
||||||
|
|
||||||
|
m_gal->DrawSegment( start, end, width );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxASSERT_MSG( false, wxT( "GERBER_DRAW_ITEM shape is unknown!" ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable for bounding box debugging
|
||||||
|
#if 0
|
||||||
|
const BOX2I& bb = aItem->ViewBBox();
|
||||||
|
m_gal->SetIsStroke( true );
|
||||||
|
m_gal->SetIsFill( true );
|
||||||
|
m_gal->SetLineWidth( 3 );
|
||||||
|
m_gal->SetStrokeColor( COLOR4D(0.9, 0.9, 0, 0.4) );
|
||||||
|
m_gal->SetFillColor( COLOR4D(0.9, 0.9, 0, 0.1) );
|
||||||
|
m_gal->DrawRectangle( bb.GetOrigin(), bb.GetEnd() );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_PAINTER::drawPolygon( GERBER_DRAW_ITEM* aParent,
|
||||||
|
SHAPE_POLY_SET aPolygon,
|
||||||
|
bool aFilled )
|
||||||
|
{
|
||||||
|
for( auto it = aPolygon.Iterate( 0 ); it; ++it )
|
||||||
|
*it = aParent->GetABPosition( *it );
|
||||||
|
|
||||||
|
if( !m_gerbviewSettings.m_polygonFill )
|
||||||
|
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
|
||||||
|
|
||||||
|
if( !aFilled )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < aPolygon.OutlineCount(); i++ )
|
||||||
|
m_gal->DrawPolyline( aPolygon.COutline( i ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_gal->DrawPolygon( aPolygon );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_PAINTER::drawFlashedShape( GERBER_DRAW_ITEM* aItem, bool aFilled )
|
||||||
|
{
|
||||||
|
D_CODE* code = aItem->GetDcodeDescr();
|
||||||
|
|
||||||
|
wxASSERT_MSG( code, wxT( "drawFlashedShape: Item has no D_CODE!" ) );
|
||||||
|
|
||||||
|
m_gal->SetIsFill( aFilled );
|
||||||
|
m_gal->SetIsStroke( !aFilled );
|
||||||
|
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
|
||||||
|
|
||||||
|
switch( aItem->m_Shape )
|
||||||
|
{
|
||||||
|
case GBR_SPOT_CIRCLE:
|
||||||
|
{
|
||||||
|
int radius = code->m_Size.x >> 1;
|
||||||
|
VECTOR2D start( aItem->GetABPosition( aItem->m_Start ) );
|
||||||
|
|
||||||
|
if( !aFilled )
|
||||||
|
{
|
||||||
|
m_gal->DrawCircle( start, radius );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( code->m_DrillShape == APT_DEF_NO_HOLE )
|
||||||
|
{
|
||||||
|
m_gal->DrawCircle( start, radius );
|
||||||
|
}
|
||||||
|
else // rectangular hole
|
||||||
|
{
|
||||||
|
if( code->m_Polygon.OutlineCount() == 0 )
|
||||||
|
code->ConvertShapeToPolygon();
|
||||||
|
|
||||||
|
SHAPE_POLY_SET poly = code->m_Polygon;
|
||||||
|
poly.Move( aItem->m_Start );
|
||||||
|
|
||||||
|
drawPolygon( aItem, poly, aFilled );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_SPOT_RECT:
|
||||||
|
{
|
||||||
|
wxPoint codeStart;
|
||||||
|
wxPoint aShapePos = aItem->m_Start;
|
||||||
|
codeStart.x = aShapePos.x - code->m_Size.x / 2;
|
||||||
|
codeStart.y = aShapePos.y - code->m_Size.y / 2;
|
||||||
|
wxPoint codeEnd = codeStart + code->m_Size;
|
||||||
|
codeStart = aItem->GetABPosition( codeStart );
|
||||||
|
codeEnd = aItem->GetABPosition( codeEnd );
|
||||||
|
|
||||||
|
if( !aFilled || code->m_DrillShape == APT_DEF_NO_HOLE )
|
||||||
|
{
|
||||||
|
m_gal->DrawRectangle( VECTOR2D( codeStart ), VECTOR2D( codeEnd ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( code->m_Polygon.OutlineCount() == 0 )
|
||||||
|
code->ConvertShapeToPolygon();
|
||||||
|
|
||||||
|
SHAPE_POLY_SET poly = code->m_Polygon;
|
||||||
|
poly.Move( aItem->m_Start );
|
||||||
|
|
||||||
|
drawPolygon( aItem, poly, aFilled );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_SPOT_OVAL:
|
||||||
|
{
|
||||||
|
int radius = 0;
|
||||||
|
|
||||||
|
wxPoint codeStart = aItem->m_Start;
|
||||||
|
wxPoint codeEnd = aItem->m_Start;
|
||||||
|
|
||||||
|
if( code->m_Size.x > code->m_Size.y ) // horizontal oval
|
||||||
|
{
|
||||||
|
int delta = (code->m_Size.x - code->m_Size.y) / 2;
|
||||||
|
codeStart.x -= delta;
|
||||||
|
codeEnd.x += delta;
|
||||||
|
radius = code->m_Size.y;
|
||||||
|
}
|
||||||
|
else // horizontal oval
|
||||||
|
{
|
||||||
|
int delta = (code->m_Size.y - code->m_Size.x) / 2;
|
||||||
|
codeStart.y -= delta;
|
||||||
|
codeEnd.y += delta;
|
||||||
|
radius = code->m_Size.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
codeStart = aItem->GetABPosition( codeStart );
|
||||||
|
codeEnd = aItem->GetABPosition( codeEnd );
|
||||||
|
|
||||||
|
if( !aFilled || code->m_DrillShape == APT_DEF_NO_HOLE )
|
||||||
|
{
|
||||||
|
m_gal->DrawSegment( codeStart, codeEnd, radius );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( code->m_Polygon.OutlineCount() == 0 )
|
||||||
|
code->ConvertShapeToPolygon();
|
||||||
|
|
||||||
|
SHAPE_POLY_SET poly = code->m_Polygon;
|
||||||
|
poly.Move( aItem->m_Start );
|
||||||
|
|
||||||
|
drawPolygon( aItem, poly, aFilled );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_SPOT_POLY:
|
||||||
|
{
|
||||||
|
if( code->m_Polygon.OutlineCount() == 0 )
|
||||||
|
code->ConvertShapeToPolygon();
|
||||||
|
|
||||||
|
SHAPE_POLY_SET poly = code->m_Polygon;
|
||||||
|
poly.Move( aItem->m_Start );
|
||||||
|
|
||||||
|
drawPolygon( aItem, poly, aFilled );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GBR_SPOT_MACRO:
|
||||||
|
drawApertureMacro( aItem, aFilled );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxASSERT_MSG( false, wxT( "Unknown Gerber flashed shape!" ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_PAINTER::drawApertureMacro( GERBER_DRAW_ITEM* aParent, bool aFilled )
|
||||||
|
{
|
||||||
|
D_CODE* code = aParent->GetDcodeDescr();
|
||||||
|
APERTURE_MACRO* macro = code->GetMacro();
|
||||||
|
|
||||||
|
SHAPE_POLY_SET* macroShape = macro->GetApertureMacroShape( aParent, aParent->m_Start );
|
||||||
|
|
||||||
|
if( !m_gerbviewSettings.m_polygonFill )
|
||||||
|
m_gal->SetLineWidth( m_gerbviewSettings.m_outlineWidth );
|
||||||
|
|
||||||
|
if( !aFilled )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < macroShape->OutlineCount(); i++ )
|
||||||
|
m_gal->DrawPolyline( macroShape->COutline( i ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_gal->DrawPolygon( *macroShape );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const double GERBVIEW_RENDER_SETTINGS::MAX_FONT_SIZE = Millimeter2iu( 10.0 );
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GERBVIEW_PAINTER_H
|
||||||
|
#define __GERBVIEW_PAINTER_H
|
||||||
|
|
||||||
|
#include <layers_id_colors_and_visibility.h>
|
||||||
|
#include <painter.h>
|
||||||
|
#include <class_gbr_display_options.h>
|
||||||
|
#include <geometry/shape_poly_set.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
class EDA_ITEM;
|
||||||
|
class COLORS_DESIGN_SETTINGS;
|
||||||
|
|
||||||
|
class GERBER_DRAW_ITEM;
|
||||||
|
class GERBER_FILE_IMAGE;
|
||||||
|
|
||||||
|
|
||||||
|
namespace KIGFX
|
||||||
|
{
|
||||||
|
class GAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GERBVIEW_RENDER_SETTINGS
|
||||||
|
* Stores GerbView specific render settings.
|
||||||
|
*/
|
||||||
|
class GERBVIEW_RENDER_SETTINGS : public RENDER_SETTINGS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class GERBVIEW_PAINTER;
|
||||||
|
|
||||||
|
GERBVIEW_RENDER_SETTINGS();
|
||||||
|
|
||||||
|
/// @copydoc RENDER_SETTINGS::ImportLegacyColors()
|
||||||
|
void ImportLegacyColors( const COLORS_DESIGN_SETTINGS* aSettings ) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function LoadDisplayOptions
|
||||||
|
* Loads settings related to display options
|
||||||
|
* @param aOptions are settings that you want to use for displaying items.
|
||||||
|
*/
|
||||||
|
void LoadDisplayOptions( const GBR_DISPLAY_OPTIONS* aOptions );
|
||||||
|
|
||||||
|
/// @copydoc RENDER_SETTINGS::GetColor()
|
||||||
|
virtual const COLOR4D& GetColor( const VIEW_ITEM* aItem, int aLayer ) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetLayerColor
|
||||||
|
* Returns the color used to draw a layer.
|
||||||
|
* @param aLayer is the layer number.
|
||||||
|
*/
|
||||||
|
inline const COLOR4D& GetLayerColor( int aLayer ) const
|
||||||
|
{
|
||||||
|
return m_layerColors[aLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetLayerColor
|
||||||
|
* Changes the color used to draw a layer.
|
||||||
|
* @param aLayer is the layer number.
|
||||||
|
* @param aColor is the new color.
|
||||||
|
*/
|
||||||
|
inline void SetLayerColor( int aLayer, const COLOR4D& aColor )
|
||||||
|
{
|
||||||
|
m_layerColors[aLayer] = aColor;
|
||||||
|
|
||||||
|
update(); // recompute other shades of the color
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsSpotFill() const
|
||||||
|
{
|
||||||
|
return m_spotFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsLineFill() const
|
||||||
|
{
|
||||||
|
return m_lineFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsPolygonFill() const
|
||||||
|
{
|
||||||
|
return m_polygonFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsShowNegativeItems() const
|
||||||
|
{
|
||||||
|
return m_showNegativeItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsShowCodes() const
|
||||||
|
{
|
||||||
|
return m_showCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsDiffMode() const
|
||||||
|
{
|
||||||
|
return m_diffMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If set to anything but an empty string, will highlight items with matching component
|
||||||
|
wxString m_componentHighlightString;
|
||||||
|
|
||||||
|
/// If set to anything but an empty string, will highlight items with matching net
|
||||||
|
wxString m_netHighlightString;
|
||||||
|
|
||||||
|
/// If set to anything but an empty string, will highlight items with matching attribute
|
||||||
|
wxString m_attributeHighlightString;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Flag determining if spots should be drawn with fill
|
||||||
|
bool m_spotFill;
|
||||||
|
|
||||||
|
/// Flag determining if lines should be drawn with fill
|
||||||
|
bool m_lineFill;
|
||||||
|
|
||||||
|
/// Flag determining if polygons should be drawn with fill
|
||||||
|
bool m_polygonFill;
|
||||||
|
|
||||||
|
/// Flag determining if negative items should be drawn with a "ghost" color
|
||||||
|
bool m_showNegativeItems;
|
||||||
|
|
||||||
|
/// Flag determining if D-Codes should be drawn
|
||||||
|
bool m_showCodes;
|
||||||
|
|
||||||
|
/// Flag determining if layers should be rendered in "diff" mode
|
||||||
|
bool m_diffMode;
|
||||||
|
|
||||||
|
/// Maximum font size for D-Codes and other strings
|
||||||
|
static const double MAX_FONT_SIZE;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GERBVIEW_PAINTER
|
||||||
|
* Contains methods for drawing GerbView-specific items.
|
||||||
|
*/
|
||||||
|
class GERBVIEW_PAINTER : public PAINTER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GERBVIEW_PAINTER( GAL* aGal );
|
||||||
|
|
||||||
|
/// @copydoc PAINTER::ApplySettings()
|
||||||
|
virtual void ApplySettings( const RENDER_SETTINGS* aSettings ) override
|
||||||
|
{
|
||||||
|
m_gerbviewSettings = *static_cast<const GERBVIEW_RENDER_SETTINGS*>( aSettings );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc PAINTER::GetSettings()
|
||||||
|
virtual GERBVIEW_RENDER_SETTINGS* GetSettings() override
|
||||||
|
{
|
||||||
|
return &m_gerbviewSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @copydoc PAINTER::Draw()
|
||||||
|
virtual bool Draw( const VIEW_ITEM* aItem, int aLayer ) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GERBVIEW_RENDER_SETTINGS m_gerbviewSettings;
|
||||||
|
|
||||||
|
// Drawing functions
|
||||||
|
void draw( /*const*/ GERBER_DRAW_ITEM* aVia, int aLayer );
|
||||||
|
|
||||||
|
/// Helper routine to draw a polygon
|
||||||
|
void drawPolygon( GERBER_DRAW_ITEM* aParent, SHAPE_POLY_SET aPolygon, bool aFilled );
|
||||||
|
|
||||||
|
/// Helper to draw a flashed shape (aka spot)
|
||||||
|
void drawFlashedShape( GERBER_DRAW_ITEM* aItem, bool aFilled );
|
||||||
|
|
||||||
|
/// Helper to draw an aperture macro shape
|
||||||
|
void drawApertureMacro( GERBER_DRAW_ITEM* aParent, bool aFilled );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function getLineThickness()
|
||||||
|
* Get the thickness to draw for a line (e.g. 0 thickness lines
|
||||||
|
* get a minimum value).
|
||||||
|
* @param aActualThickness line own thickness
|
||||||
|
* @return the thickness to draw
|
||||||
|
*/
|
||||||
|
int getLineThickness( int aActualThickness ) const;
|
||||||
|
};
|
||||||
|
} // namespace KIGFX
|
||||||
|
|
||||||
|
#endif /* __GERBVIEW_PAINTER_H */
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tool/tool_manager.h>
|
||||||
|
#include <tool/common_tools.h>
|
||||||
|
#include <tool/zoom_tool.h>
|
||||||
|
#include <gerbview_id.h>
|
||||||
|
|
||||||
|
#include "gerbview_actions.h"
|
||||||
|
#include "selection_tool.h"
|
||||||
|
#include "gerbview_control.h"
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_ACTIONS::RegisterAllTools( TOOL_MANAGER* aToolManager )
|
||||||
|
{
|
||||||
|
aToolManager->RegisterTool( new COMMON_TOOLS );
|
||||||
|
aToolManager->RegisterTool( new GERBVIEW_SELECTION_TOOL );
|
||||||
|
aToolManager->RegisterTool( new GERBVIEW_CONTROL );
|
||||||
|
aToolManager->RegisterTool( new ZOOM_TOOL );
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<TOOL_EVENT> GERBVIEW_ACTIONS::TranslateLegacyId( int aId )
|
||||||
|
{
|
||||||
|
switch( aId )
|
||||||
|
{
|
||||||
|
case ID_ZOOM_IN: // toolbar button "Zoom In"
|
||||||
|
return ACTIONS::zoomInCenter.MakeEvent();
|
||||||
|
|
||||||
|
case ID_ZOOM_OUT: // toolbar button "Zoom In"
|
||||||
|
return ACTIONS::zoomOutCenter.MakeEvent();
|
||||||
|
|
||||||
|
case ID_ZOOM_PAGE: // toolbar button "Fit on Screen"
|
||||||
|
return ACTIONS::zoomFitScreen.MakeEvent();
|
||||||
|
|
||||||
|
case ID_ZOOM_SELECTION:
|
||||||
|
return ACTIONS::zoomTool.MakeEvent();
|
||||||
|
|
||||||
|
case ID_TB_MEASUREMENT_TOOL:
|
||||||
|
return GERBVIEW_ACTIONS::measureTool.MakeEvent();
|
||||||
|
|
||||||
|
case ID_NO_TOOL_SELECTED:
|
||||||
|
return GERBVIEW_ACTIONS::selectionTool.MakeEvent();
|
||||||
|
|
||||||
|
case ID_HIGHLIGHT_REMOVE_ALL:
|
||||||
|
return GERBVIEW_ACTIONS::highlightClear.MakeEvent();
|
||||||
|
|
||||||
|
case ID_HIGHLIGHT_CMP_ITEMS:
|
||||||
|
return GERBVIEW_ACTIONS::highlightComponent.MakeEvent();
|
||||||
|
|
||||||
|
case ID_HIGHLIGHT_NET_ITEMS:
|
||||||
|
return GERBVIEW_ACTIONS::highlightNet.MakeEvent();
|
||||||
|
|
||||||
|
case ID_HIGHLIGHT_APER_ATTRIBUTE_ITEMS:
|
||||||
|
return GERBVIEW_ACTIONS::highlightAttribute.MakeEvent();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::optional<TOOL_EVENT>();
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GERBVIEW_ACTIONS_H
|
||||||
|
#define __GERBVIEW_ACTIONS_H
|
||||||
|
|
||||||
|
#include <tool/tool_action.h>
|
||||||
|
#include <tool/actions.h>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
class TOOL_EVENT;
|
||||||
|
class TOOL_MANAGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GERBVIEW_ACTIONS
|
||||||
|
*
|
||||||
|
* Gathers all the actions that are shared by tools. The instance of GERBVIEW_ACTIONS is created
|
||||||
|
* inside of ACTION_MANAGER object that registers the actions.
|
||||||
|
*/
|
||||||
|
class GERBVIEW_ACTIONS : public ACTIONS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Selection Tool
|
||||||
|
/// Activation of the selection tool
|
||||||
|
static TOOL_ACTION selectionActivate;
|
||||||
|
|
||||||
|
/// Select a single item under the cursor position
|
||||||
|
static TOOL_ACTION selectionCursor;
|
||||||
|
|
||||||
|
/// Clears the current selection
|
||||||
|
static TOOL_ACTION selectionClear;
|
||||||
|
|
||||||
|
/// Selects an item (specified as the event parameter).
|
||||||
|
static TOOL_ACTION selectItem;
|
||||||
|
|
||||||
|
/// Unselects an item (specified as the event parameter).
|
||||||
|
static TOOL_ACTION unselectItem;
|
||||||
|
|
||||||
|
/// Activation of the edit tool
|
||||||
|
static TOOL_ACTION properties;
|
||||||
|
|
||||||
|
static TOOL_ACTION measureTool;
|
||||||
|
|
||||||
|
// View controls
|
||||||
|
static TOOL_ACTION zoomIn;
|
||||||
|
static TOOL_ACTION zoomOut;
|
||||||
|
static TOOL_ACTION zoomInCenter;
|
||||||
|
static TOOL_ACTION zoomOutCenter;
|
||||||
|
static TOOL_ACTION zoomCenter;
|
||||||
|
static TOOL_ACTION zoomFitScreen;
|
||||||
|
static TOOL_ACTION zoomPreset;
|
||||||
|
|
||||||
|
// Display modes
|
||||||
|
static TOOL_ACTION zoneDisplayEnable;
|
||||||
|
static TOOL_ACTION zoneDisplayDisable;
|
||||||
|
static TOOL_ACTION zoneDisplayOutlines;
|
||||||
|
static TOOL_ACTION highContrastMode;
|
||||||
|
static TOOL_ACTION highContrastInc;
|
||||||
|
static TOOL_ACTION highContrastDec;
|
||||||
|
|
||||||
|
// Layer control
|
||||||
|
static TOOL_ACTION layerPrev;
|
||||||
|
static TOOL_ACTION layerAlphaInc;
|
||||||
|
static TOOL_ACTION layerAlphaDec;
|
||||||
|
static TOOL_ACTION layerToggle;
|
||||||
|
|
||||||
|
static TOOL_ACTION layerChanged; // notification
|
||||||
|
|
||||||
|
// Grid control
|
||||||
|
static TOOL_ACTION gridFast1;
|
||||||
|
static TOOL_ACTION gridFast2;
|
||||||
|
static TOOL_ACTION gridNext;
|
||||||
|
static TOOL_ACTION gridPrev;
|
||||||
|
static TOOL_ACTION gridSetOrigin;
|
||||||
|
static TOOL_ACTION gridResetOrigin;
|
||||||
|
static TOOL_ACTION gridPreset;
|
||||||
|
|
||||||
|
/// Cursor control with keyboard
|
||||||
|
static TOOL_ACTION cursorUp;
|
||||||
|
static TOOL_ACTION cursorDown;
|
||||||
|
static TOOL_ACTION cursorLeft;
|
||||||
|
static TOOL_ACTION cursorRight;
|
||||||
|
|
||||||
|
static TOOL_ACTION cursorUpFast;
|
||||||
|
static TOOL_ACTION cursorDownFast;
|
||||||
|
static TOOL_ACTION cursorLeftFast;
|
||||||
|
static TOOL_ACTION cursorRightFast;
|
||||||
|
|
||||||
|
static TOOL_ACTION cursorClick;
|
||||||
|
static TOOL_ACTION cursorDblClick;
|
||||||
|
|
||||||
|
// Panning with keyboard
|
||||||
|
static TOOL_ACTION panUp;
|
||||||
|
static TOOL_ACTION panDown;
|
||||||
|
static TOOL_ACTION panLeft;
|
||||||
|
static TOOL_ACTION panRight;
|
||||||
|
|
||||||
|
// Miscellaneous
|
||||||
|
static TOOL_ACTION selectionTool;
|
||||||
|
static TOOL_ACTION zoomTool;
|
||||||
|
static TOOL_ACTION panTool;
|
||||||
|
static TOOL_ACTION pickerTool;
|
||||||
|
static TOOL_ACTION resetCoords;
|
||||||
|
static TOOL_ACTION switchCursor;
|
||||||
|
static TOOL_ACTION switchUnits;
|
||||||
|
static TOOL_ACTION showHelp;
|
||||||
|
static TOOL_ACTION toBeDone;
|
||||||
|
|
||||||
|
// Highlighting
|
||||||
|
static TOOL_ACTION highlightClear;
|
||||||
|
static TOOL_ACTION highlightNet;
|
||||||
|
static TOOL_ACTION highlightComponent;
|
||||||
|
static TOOL_ACTION highlightAttribute;
|
||||||
|
|
||||||
|
///> @copydoc COMMON_ACTIONS::TranslateLegacyId()
|
||||||
|
virtual boost::optional<TOOL_EVENT> TranslateLegacyId( int aId ) override;
|
||||||
|
|
||||||
|
///> @copydoc COMMON_ACTIONS::RegisterAllTools()
|
||||||
|
virtual void RegisterAllTools( TOOL_MANAGER* aToolManager ) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __GERBVIEW_ACTIONS_H
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <view/view.h>
|
||||||
|
#include <gerbview_painter.h>
|
||||||
|
#include <gerbview_frame.h>
|
||||||
|
#include <tool/tool_manager.h>
|
||||||
|
|
||||||
|
#include "gerbview_actions.h"
|
||||||
|
#include "gerbview_control.h"
|
||||||
|
#include "selection_tool.h"
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::selectionTool( "gerbview.Control.selectionTool",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "", NULL, AF_ACTIVATE );
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::layerChanged( "gerbview.Control.layerChanged",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "", NULL, AF_NOTIFY );
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::highlightClear( "gerbview.Control.highlightClear",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
_( "Clear Highlight" ), "" );
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::highlightNet( "gerbview.Control.highlightNet",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
_( "Highlight Net" ), "" );
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::highlightComponent( "gerbview.Control.highlightComponent",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
_( "Highlight Component" ), "" );
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::highlightAttribute( "gerbview.Control.highlightAttribute",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
_( "Highlight Attribute" ), "" );
|
||||||
|
|
||||||
|
GERBVIEW_CONTROL::GERBVIEW_CONTROL() :
|
||||||
|
TOOL_INTERACTIVE( "gerbview.Control" ), m_frame( NULL )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GERBVIEW_CONTROL::~GERBVIEW_CONTROL()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_CONTROL::Reset( RESET_REASON aReason )
|
||||||
|
{
|
||||||
|
m_frame = getEditFrame<GERBVIEW_FRAME>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_CONTROL::HighlightControl( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
auto settings = static_cast<KIGFX::GERBVIEW_PAINTER*>( getView()->GetPainter() )->GetSettings();
|
||||||
|
const auto& selection = m_toolMgr->GetTool<GERBVIEW_SELECTION_TOOL>()->GetSelection();
|
||||||
|
GERBER_DRAW_ITEM* item = NULL;
|
||||||
|
|
||||||
|
if( selection.Size() == 1 )
|
||||||
|
{
|
||||||
|
item = static_cast<GERBER_DRAW_ITEM*>( selection[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aEvent.IsAction( &GERBVIEW_ACTIONS::highlightClear ) )
|
||||||
|
{
|
||||||
|
m_frame->m_SelComponentBox->SetSelection( 0 );
|
||||||
|
m_frame->m_SelNetnameBox->SetSelection( 0 );
|
||||||
|
m_frame->m_SelAperAttributesBox->SetSelection( 0 );
|
||||||
|
|
||||||
|
settings->m_netHighlightString = "";
|
||||||
|
settings->m_componentHighlightString = "";
|
||||||
|
settings->m_attributeHighlightString = "";
|
||||||
|
}
|
||||||
|
else if( item && aEvent.IsAction( &GERBVIEW_ACTIONS::highlightNet ) )
|
||||||
|
{
|
||||||
|
auto string = item->GetNetAttributes().m_Netname;
|
||||||
|
settings->m_netHighlightString = string;
|
||||||
|
m_frame->m_SelNetnameBox->SetStringSelection( string );
|
||||||
|
}
|
||||||
|
else if( item && aEvent.IsAction( &GERBVIEW_ACTIONS::highlightComponent ) )
|
||||||
|
{
|
||||||
|
auto string = item->GetNetAttributes().m_Cmpref;
|
||||||
|
settings->m_componentHighlightString = string;
|
||||||
|
m_frame->m_SelComponentBox->SetStringSelection( string );
|
||||||
|
}
|
||||||
|
else if( item && aEvent.IsAction( &GERBVIEW_ACTIONS::highlightAttribute ) )
|
||||||
|
{
|
||||||
|
D_CODE* apertDescr = item->GetDcodeDescr();
|
||||||
|
if( apertDescr )
|
||||||
|
{
|
||||||
|
auto string = apertDescr->m_AperFunction;
|
||||||
|
settings->m_attributeHighlightString = string;
|
||||||
|
m_frame->m_SelAperAttributesBox->SetStringSelection( string );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_frame->GetGalCanvas()->GetView()->RecacheAllItems();
|
||||||
|
m_frame->GetGalCanvas()->Refresh();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_CONTROL::setTransitions()
|
||||||
|
{
|
||||||
|
Go( &GERBVIEW_CONTROL::HighlightControl, GERBVIEW_ACTIONS::highlightClear.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_CONTROL::HighlightControl, GERBVIEW_ACTIONS::highlightNet.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_CONTROL::HighlightControl, GERBVIEW_ACTIONS::highlightComponent.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_CONTROL::HighlightControl, GERBVIEW_ACTIONS::highlightAttribute.MakeEvent() );
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GERBVIEW_CONTROL_H
|
||||||
|
#define GERBVIEW_CONTROL_H
|
||||||
|
|
||||||
|
#include <tool/tool_interactive.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PCBNEW_CONTROL
|
||||||
|
*
|
||||||
|
* Handles actions that are shared between different frames in pcbnew.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GERBVIEW_CONTROL : public TOOL_INTERACTIVE
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GERBVIEW_CONTROL();
|
||||||
|
~GERBVIEW_CONTROL();
|
||||||
|
|
||||||
|
/// @copydoc TOOL_INTERACTIVE::Reset()
|
||||||
|
void Reset( RESET_REASON aReason ) override;
|
||||||
|
|
||||||
|
// Display modes
|
||||||
|
int HighContrastMode( const TOOL_EVENT& aEvent );
|
||||||
|
int HighContrastInc( const TOOL_EVENT& aEvent );
|
||||||
|
int HighContrastDec( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
// Layer control
|
||||||
|
int LayerSwitch( const TOOL_EVENT& aEvent );
|
||||||
|
int LayerNext( const TOOL_EVENT& aEvent );
|
||||||
|
int LayerPrev( const TOOL_EVENT& aEvent );
|
||||||
|
int LayerToggle( const TOOL_EVENT& aEvent );
|
||||||
|
int LayerAlphaInc( const TOOL_EVENT& aEvent );
|
||||||
|
int LayerAlphaDec( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
// Highlight control
|
||||||
|
int HighlightControl( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Sets up handlers for various events.
|
||||||
|
void setTransitions() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GERBVIEW_FRAME* m_frame;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,959 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
#include <base_struct.h>
|
||||||
|
|
||||||
|
#include <gerber_collectors.h>
|
||||||
|
//#include <confirm.h>
|
||||||
|
|
||||||
|
#include <class_draw_panel_gal.h>
|
||||||
|
#include <view/view.h>
|
||||||
|
#include <view/view_controls.h>
|
||||||
|
#include <view/view_group.h>
|
||||||
|
#include <painter.h>
|
||||||
|
#include <bitmaps.h>
|
||||||
|
#include <hotkeys.h>
|
||||||
|
|
||||||
|
#include <tool/tool_event.h>
|
||||||
|
#include <tool/tool_manager.h>
|
||||||
|
#include <preview_items/bright_box.h>
|
||||||
|
#include <preview_items/ruler_item.h>
|
||||||
|
#include <preview_items/selection_area.h>
|
||||||
|
|
||||||
|
#include <gerbview_id.h>
|
||||||
|
#include <gerbview_painter.h>
|
||||||
|
|
||||||
|
#include "selection_tool.h"
|
||||||
|
#include "gerbview_actions.h"
|
||||||
|
|
||||||
|
// Selection tool actions
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::selectionActivate( "gerbview.InteractiveSelection",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "", NULL, AF_ACTIVATE ); // No description, it is not supposed to be shown anywhere
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::selectionCursor( "gerbview.InteractiveSelection.Cursor",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "" ); // No description, it is not supposed to be shown anywhere
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::selectItem( "gerbview.InteractiveSelection.SelectItem",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "" ); // No description, it is not supposed to be shown anywhere
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::unselectItem( "gerbview.InteractiveSelection.UnselectItem",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "" ); // No description, it is not supposed to be shown anywhere
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::selectionClear( "gerbview.InteractiveSelection.Clear",
|
||||||
|
AS_GLOBAL, 0,
|
||||||
|
"", "" ); // No description, it is not supposed to be shown anywhere
|
||||||
|
|
||||||
|
TOOL_ACTION GERBVIEW_ACTIONS::measureTool( "gerbview.InteractiveSelection.measureTool",
|
||||||
|
AS_GLOBAL, MD_CTRL + MD_SHIFT + 'M',
|
||||||
|
_( "Measure tool" ), _( "Interactively measure distance between points" ),
|
||||||
|
nullptr, AF_ACTIVATE );
|
||||||
|
|
||||||
|
|
||||||
|
class HIGHLIGHT_MENU: public CONTEXT_MENU
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HIGHLIGHT_MENU()
|
||||||
|
{
|
||||||
|
SetTitle( _( "Highlight..." ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void update() override
|
||||||
|
{
|
||||||
|
const auto& selection = getToolManager()->GetTool<GERBVIEW_SELECTION_TOOL>()->GetSelection();
|
||||||
|
|
||||||
|
if( selection.Size() == 1 )
|
||||||
|
{
|
||||||
|
auto item = static_cast<GERBER_DRAW_ITEM*>( selection[0] );
|
||||||
|
const auto& net_attr = item->GetNetAttributes();
|
||||||
|
|
||||||
|
if( ( net_attr.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) ||
|
||||||
|
( net_attr.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) )
|
||||||
|
{
|
||||||
|
auto menuEntry = Add( GERBVIEW_ACTIONS::highlightComponent );
|
||||||
|
menuEntry->SetItemLabel( wxString::Format( _( "Highlight items of component '%s'" ),
|
||||||
|
GetChars( net_attr.m_Cmpref ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( net_attr.m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_NET ) )
|
||||||
|
{
|
||||||
|
auto menuEntry = Add( GERBVIEW_ACTIONS::highlightNet );
|
||||||
|
menuEntry->SetItemLabel( wxString::Format( _( "Highlight items of net '%s'" ),
|
||||||
|
GetChars( net_attr.m_Netname ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
D_CODE* apertDescr = item->GetDcodeDescr();
|
||||||
|
|
||||||
|
if( apertDescr && !apertDescr->m_AperFunction.IsEmpty() )
|
||||||
|
{
|
||||||
|
auto menuEntry = Add( GERBVIEW_ACTIONS::highlightAttribute );
|
||||||
|
menuEntry->SetItemLabel( wxString::Format( _( "Highlight aperture type '%s'" ),
|
||||||
|
GetChars( apertDescr->m_AperFunction ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Add( GERBVIEW_ACTIONS::highlightClear );
|
||||||
|
}
|
||||||
|
|
||||||
|
CONTEXT_MENU* create() const override
|
||||||
|
{
|
||||||
|
return new HIGHLIGHT_MENU();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GERBVIEW_SELECTION_TOOL::GERBVIEW_SELECTION_TOOL() :
|
||||||
|
TOOL_INTERACTIVE( "gerbview.InteractiveSelection" ),
|
||||||
|
m_frame( NULL ), m_additive( false ), m_subtractive( false ),
|
||||||
|
m_multiple( false ),
|
||||||
|
m_menu( *this )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GERBVIEW_SELECTION_TOOL::~GERBVIEW_SELECTION_TOOL()
|
||||||
|
{
|
||||||
|
getView()->Remove( &m_selection );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_SELECTION_TOOL::Init()
|
||||||
|
{
|
||||||
|
auto selectMenu = std::make_shared<HIGHLIGHT_MENU>();
|
||||||
|
selectMenu->SetTool( this );
|
||||||
|
m_menu.AddSubMenu( selectMenu );
|
||||||
|
|
||||||
|
auto& menu = m_menu.GetMenu();
|
||||||
|
|
||||||
|
menu.AddMenu( selectMenu.get(), false );
|
||||||
|
menu.AddSeparator( SELECTION_CONDITIONS::ShowAlways, 1000 );
|
||||||
|
|
||||||
|
m_menu.AddStandardSubMenus( *getEditFrame<GERBVIEW_FRAME>() );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::Reset( RESET_REASON aReason )
|
||||||
|
{
|
||||||
|
m_frame = getEditFrame<GERBVIEW_FRAME>();
|
||||||
|
m_preliminary = true;
|
||||||
|
|
||||||
|
if( aReason == TOOL_BASE::MODEL_RELOAD )
|
||||||
|
{
|
||||||
|
// Remove pointers to the selected items from containers
|
||||||
|
// without changing their properties (as they are already deleted
|
||||||
|
// while a new file is loaded)
|
||||||
|
m_selection.Clear();
|
||||||
|
getView()->GetPainter()->GetSettings()->SetHighlight( false );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Restore previous properties of selected items and remove them from containers
|
||||||
|
clearSelection();
|
||||||
|
|
||||||
|
// Reinsert the VIEW_GROUP, in case it was removed from the VIEW
|
||||||
|
getView()->Remove( &m_selection );
|
||||||
|
getView()->Add( &m_selection );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
// Main loop: keep receiving events
|
||||||
|
while( OPT_TOOL_EVENT evt = Wait() )
|
||||||
|
{
|
||||||
|
// This is kind of hacky: activate RMB drag on any event.
|
||||||
|
// There doesn't seem to be any other good way to tell when another tool
|
||||||
|
// is canceled and control returns to the selection tool, except by the
|
||||||
|
// fact that the selection tool starts to get events again.
|
||||||
|
if( m_frame->GetToolId() == ID_NO_TOOL_SELECTED)
|
||||||
|
{
|
||||||
|
getViewControls()->SetAdditionalPanButtons( false, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable RMB pan for other tools; they can re-enable if desired
|
||||||
|
if( evt->IsActivate() )
|
||||||
|
{
|
||||||
|
getViewControls()->SetAdditionalPanButtons( false, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
// single click? Select single object
|
||||||
|
if( evt->IsClick( BUT_LEFT ) )
|
||||||
|
{
|
||||||
|
if( !m_additive )
|
||||||
|
clearSelection();
|
||||||
|
|
||||||
|
selectPoint( evt->Position() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// right click? if there is any object - show the context menu
|
||||||
|
else if( evt->IsClick( BUT_RIGHT ) )
|
||||||
|
{
|
||||||
|
if( m_selection.Empty() )
|
||||||
|
{
|
||||||
|
selectPoint( evt->Position() );
|
||||||
|
m_selection.SetIsHover( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_menu.ShowContextMenu( m_selection );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( evt->IsCancel() || evt->Action() == TA_UNDO_REDO_PRE )
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( evt->Action() == TA_CONTEXT_MENU_CLOSED )
|
||||||
|
{
|
||||||
|
m_menu.CloseContextMenu( evt );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tool is supposed to be active forever
|
||||||
|
assert( false );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SELECTION& GERBVIEW_SELECTION_TOOL::GetSelection()
|
||||||
|
{
|
||||||
|
return m_selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SELECTION& GERBVIEW_SELECTION_TOOL::RequestSelection( int aFlags )
|
||||||
|
{
|
||||||
|
if( m_selection.Empty() )
|
||||||
|
{
|
||||||
|
m_toolMgr->RunAction( GERBVIEW_ACTIONS::selectionCursor, true, 0 );
|
||||||
|
m_selection.SetIsHover( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Be careful with iterators: items can be removed from list
|
||||||
|
// that invalidate iterators.
|
||||||
|
for( unsigned ii = 0; ii < m_selection.GetSize(); ii++ )
|
||||||
|
{
|
||||||
|
EDA_ITEM* item = m_selection[ii];
|
||||||
|
|
||||||
|
if( ( aFlags & SELECTION_EDITABLE ) && item->Type() == PCB_MARKER_T )
|
||||||
|
{
|
||||||
|
unselect( static_cast<EDA_ITEM *>( item ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem )
|
||||||
|
{
|
||||||
|
if( aItem->IsSelected() )
|
||||||
|
{
|
||||||
|
unselect( aItem );
|
||||||
|
|
||||||
|
// Inform other potentially interested tools
|
||||||
|
m_toolMgr->ProcessEvent( UnselectedEvent );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !m_additive )
|
||||||
|
clearSelection();
|
||||||
|
|
||||||
|
// Prevent selection of invisible or inactive items
|
||||||
|
if( selectable( aItem ) )
|
||||||
|
{
|
||||||
|
select( aItem );
|
||||||
|
|
||||||
|
// Inform other potentially interested tools
|
||||||
|
m_toolMgr->ProcessEvent( SelectedEvent );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_frame->GetGalCanvas()->ForceRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag )
|
||||||
|
{
|
||||||
|
EDA_ITEM* item = NULL;
|
||||||
|
GERBER_COLLECTOR collector;
|
||||||
|
EDA_ITEM* model = getModel<EDA_ITEM>();
|
||||||
|
|
||||||
|
collector.Collect( model, GERBER_COLLECTOR::AllItems, wxPoint( aWhere.x, aWhere.y ) );
|
||||||
|
|
||||||
|
bool anyCollected = collector.GetCount() != 0;
|
||||||
|
|
||||||
|
// Remove unselectable items
|
||||||
|
for( int i = collector.GetCount() - 1; i >= 0; --i )
|
||||||
|
{
|
||||||
|
if( !selectable( collector[i] ) )
|
||||||
|
collector.Remove( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( collector.GetCount() )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if( !m_additive && anyCollected )
|
||||||
|
clearSelection();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
toggleSelection( collector[0] );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Let's see if there is still disambiguation in selection..
|
||||||
|
if( collector.GetCount() == 1 )
|
||||||
|
{
|
||||||
|
toggleSelection( collector[0] );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if( collector.GetCount() > 1 )
|
||||||
|
{
|
||||||
|
if( aOnDrag )
|
||||||
|
Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) );
|
||||||
|
|
||||||
|
item = disambiguationMenu( &collector );
|
||||||
|
|
||||||
|
if( item )
|
||||||
|
{
|
||||||
|
toggleSelection( item );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_SELECTION_TOOL::selectCursor( bool aSelectAlways )
|
||||||
|
{
|
||||||
|
if( aSelectAlways || m_selection.Empty() )
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
selectPoint( getViewControls()->GetCursorPosition( false ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return !m_selection.Empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_SELECTION_TOOL::selectMultiple()
|
||||||
|
{
|
||||||
|
bool cancelled = false; // Was the tool cancelled while it was running?
|
||||||
|
m_multiple = true; // Multiple selection mode is active
|
||||||
|
KIGFX::VIEW* view = getView();
|
||||||
|
getViewControls()->SetAutoPan( true );
|
||||||
|
|
||||||
|
KIGFX::PREVIEW::SELECTION_AREA area;
|
||||||
|
view->Add( &area );
|
||||||
|
|
||||||
|
while( OPT_TOOL_EVENT evt = Wait() )
|
||||||
|
{
|
||||||
|
if( evt->IsCancel() )
|
||||||
|
{
|
||||||
|
cancelled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( evt->IsDrag( BUT_LEFT ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
// Start drawing a selection box
|
||||||
|
area.SetOrigin( evt->DragOrigin() );
|
||||||
|
area.SetEnd( evt->Position() );
|
||||||
|
area.SetAdditive( m_additive );
|
||||||
|
area.SetSubtractive( m_subtractive );
|
||||||
|
|
||||||
|
view->SetVisible( &area, true );
|
||||||
|
view->Update( &area );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( evt->IsMouseUp( BUT_LEFT ) )
|
||||||
|
{
|
||||||
|
// End drawing the selection box
|
||||||
|
view->SetVisible( &area, false );
|
||||||
|
|
||||||
|
// Mark items within the selection box as selected
|
||||||
|
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
|
||||||
|
|
||||||
|
// Filter the view items based on the selection box
|
||||||
|
BOX2I selectionBox = area.ViewBBox();
|
||||||
|
view->Query( selectionBox, selectedItems ); // Get the list of selected items
|
||||||
|
|
||||||
|
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
|
||||||
|
|
||||||
|
int width = area.GetEnd().x - area.GetOrigin().x;
|
||||||
|
int height = area.GetEnd().y - area.GetOrigin().y;
|
||||||
|
|
||||||
|
// Construct an EDA_RECT to determine EDA_ITEM selection
|
||||||
|
EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ),
|
||||||
|
wxSize( width, height ) );
|
||||||
|
|
||||||
|
selectionRect.Normalize();
|
||||||
|
|
||||||
|
for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
|
||||||
|
{
|
||||||
|
auto item = static_cast<GERBER_DRAW_ITEM*>( it->first );
|
||||||
|
|
||||||
|
if( !item || !selectable( item ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Selection mode depends on direction of drag-selection:
|
||||||
|
* Left > Right : Select objects that are fully enclosed by selection
|
||||||
|
* Right > Left : Select objects that are crossed by selection
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( width >= 0 )
|
||||||
|
{
|
||||||
|
if( selectionBox.Contains( item->ViewBBox() ) )
|
||||||
|
{
|
||||||
|
if( m_subtractive )
|
||||||
|
unselect( item );
|
||||||
|
else
|
||||||
|
select( item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( item->HitTest( selectionRect ) )
|
||||||
|
{
|
||||||
|
if( m_subtractive )
|
||||||
|
unselect( item );
|
||||||
|
else
|
||||||
|
select( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_selection.Size() == 1 )
|
||||||
|
m_frame->SetCurItem( static_cast<GERBER_DRAW_ITEM*>( m_selection.Front() ) );
|
||||||
|
else
|
||||||
|
m_frame->SetCurItem( NULL );
|
||||||
|
|
||||||
|
// Inform other potentially interested tools
|
||||||
|
if( !m_selection.Empty() )
|
||||||
|
m_toolMgr->ProcessEvent( SelectedEvent );
|
||||||
|
|
||||||
|
break; // Stop waiting for events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop drawing the selection box
|
||||||
|
view->Remove( &area );
|
||||||
|
m_multiple = false; // Multiple selection mode is inactive
|
||||||
|
getViewControls()->SetAutoPan( false );
|
||||||
|
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::setTransitions()
|
||||||
|
{
|
||||||
|
Go( &GERBVIEW_SELECTION_TOOL::Main, GERBVIEW_ACTIONS::selectionActivate.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_SELECTION_TOOL::CursorSelection, GERBVIEW_ACTIONS::selectionCursor.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_SELECTION_TOOL::ClearSelection, GERBVIEW_ACTIONS::selectionClear.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_SELECTION_TOOL::SelectItem, GERBVIEW_ACTIONS::selectItem.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_SELECTION_TOOL::UnselectItem, GERBVIEW_ACTIONS::unselectItem.MakeEvent() );
|
||||||
|
Go( &GERBVIEW_SELECTION_TOOL::MeasureTool, GERBVIEW_ACTIONS::measureTool.MakeEvent() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::CursorSelection( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
if( m_selection.Empty() ) // Try to find an item that could be modified
|
||||||
|
{
|
||||||
|
selectCursor( true );
|
||||||
|
|
||||||
|
clearSelection();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::ClearSelection( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::SelectItems( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
std::vector<EDA_ITEM*>* items = aEvent.Parameter<std::vector<EDA_ITEM*>*>();
|
||||||
|
|
||||||
|
if( items )
|
||||||
|
{
|
||||||
|
// Perform individual selection of each item
|
||||||
|
// before processing the event.
|
||||||
|
for( auto item : *items )
|
||||||
|
{
|
||||||
|
select( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_toolMgr->ProcessEvent( SelectedEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::SelectItem( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
// Check if there is an item to be selected
|
||||||
|
EDA_ITEM* item = aEvent.Parameter<EDA_ITEM*>();
|
||||||
|
|
||||||
|
if( item )
|
||||||
|
{
|
||||||
|
select( item );
|
||||||
|
|
||||||
|
// Inform other potentially interested tools
|
||||||
|
m_toolMgr->ProcessEvent( SelectedEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::UnselectItems( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
std::vector<EDA_ITEM*>* items = aEvent.Parameter<std::vector<EDA_ITEM*>*>();
|
||||||
|
|
||||||
|
if( items )
|
||||||
|
{
|
||||||
|
// Perform individual unselection of each item
|
||||||
|
// before processing the event
|
||||||
|
for( auto item : *items )
|
||||||
|
{
|
||||||
|
unselect( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_toolMgr->ProcessEvent( UnselectedEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::UnselectItem( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
// Check if there is an item to be selected
|
||||||
|
EDA_ITEM* item = aEvent.Parameter<EDA_ITEM*>();
|
||||||
|
|
||||||
|
if( item )
|
||||||
|
{
|
||||||
|
unselect( item );
|
||||||
|
|
||||||
|
// Inform other potentially interested tools
|
||||||
|
m_toolMgr->ProcessEvent( UnselectedEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::clearSelection()
|
||||||
|
{
|
||||||
|
if( m_selection.Empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for( auto item : m_selection )
|
||||||
|
unselectVisually( static_cast<EDA_ITEM*>( item ) );
|
||||||
|
|
||||||
|
m_selection.Clear();
|
||||||
|
|
||||||
|
m_frame->SetCurItem( NULL );
|
||||||
|
|
||||||
|
// Inform other potentially interested tools
|
||||||
|
m_toolMgr->ProcessEvent( ClearedEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::zoomFitSelection( void )
|
||||||
|
{
|
||||||
|
//Should recalculate the view to zoom in on the selection
|
||||||
|
auto selectionBox = m_selection.ViewBBox();
|
||||||
|
auto canvas = m_frame->GetGalCanvas();
|
||||||
|
auto view = getView();
|
||||||
|
|
||||||
|
VECTOR2D screenSize = view->ToWorld( canvas->GetClientSize(), false );
|
||||||
|
|
||||||
|
if( !( selectionBox.GetWidth() == 0 ) || !( selectionBox.GetHeight() == 0 ) )
|
||||||
|
{
|
||||||
|
VECTOR2D vsize = selectionBox.GetSize();
|
||||||
|
double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
|
||||||
|
fabs( vsize.y / screenSize.y ) );
|
||||||
|
view->SetScale( scale );
|
||||||
|
view->SetCenter( selectionBox.Centre() );
|
||||||
|
view->Add( &m_selection );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_frame->GetGalCanvas()->ForceRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollector )
|
||||||
|
{
|
||||||
|
EDA_ITEM* current = NULL;
|
||||||
|
BRIGHT_BOX brightBox;
|
||||||
|
CONTEXT_MENU menu;
|
||||||
|
|
||||||
|
getView()->Add( &brightBox );
|
||||||
|
|
||||||
|
int limit = std::min( 10, aCollector->GetCount() );
|
||||||
|
|
||||||
|
for( int i = 0; i < limit; ++i )
|
||||||
|
{
|
||||||
|
wxString text;
|
||||||
|
EDA_ITEM* item = ( *aCollector )[i];
|
||||||
|
text = item->GetSelectMenuText();
|
||||||
|
menu.Add( text, i + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.SetTitle( _( "Clarify selection" ) );
|
||||||
|
menu.DisplayTitle( true );
|
||||||
|
SetContextMenu( &menu, CMENU_NOW );
|
||||||
|
|
||||||
|
while( OPT_TOOL_EVENT evt = Wait() )
|
||||||
|
{
|
||||||
|
if( evt->Action() == TA_CONTEXT_MENU_UPDATE )
|
||||||
|
{
|
||||||
|
if( current )
|
||||||
|
current->ClearBrightened();
|
||||||
|
|
||||||
|
int id = *evt->GetCommandId();
|
||||||
|
|
||||||
|
// User has pointed an item, so show it in a different way
|
||||||
|
if( id > 0 && id <= limit )
|
||||||
|
{
|
||||||
|
current = ( *aCollector )[id - 1];
|
||||||
|
current->SetBrightened();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( evt->Action() == TA_CONTEXT_MENU_CHOICE )
|
||||||
|
{
|
||||||
|
boost::optional<int> id = evt->GetCommandId();
|
||||||
|
|
||||||
|
// User has selected an item, so this one will be returned
|
||||||
|
if( id && ( *id > 0 ) )
|
||||||
|
current = ( *aCollector )[*id - 1];
|
||||||
|
else
|
||||||
|
current = NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a mark to show which item is available to be selected
|
||||||
|
if( current && current->IsBrightened() )
|
||||||
|
{
|
||||||
|
brightBox.SetItem( current );
|
||||||
|
getView()->SetVisible( &brightBox, true );
|
||||||
|
// getView()->Hide( &brightBox, false );
|
||||||
|
getView()->Update( &brightBox, KIGFX::GEOMETRY );
|
||||||
|
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getView()->Remove( &brightBox );
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_SELECTION_TOOL::selectable( const EDA_ITEM* aItem ) const
|
||||||
|
{
|
||||||
|
auto item = static_cast<const GERBER_DRAW_ITEM*>( aItem );
|
||||||
|
|
||||||
|
if( item->GetLayerPolarity() )
|
||||||
|
{
|
||||||
|
// Don't allow selection of invisible negative items
|
||||||
|
auto rs = static_cast<KIGFX::GERBVIEW_RENDER_SETTINGS*>( getView()->GetPainter()->GetSettings() );
|
||||||
|
if( !rs->IsShowNegativeItems() )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getEditFrame<GERBVIEW_FRAME>()->IsLayerVisible( item->GetLayer() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::select( EDA_ITEM* aItem )
|
||||||
|
{
|
||||||
|
if( aItem->IsSelected() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectVisually( aItem );
|
||||||
|
m_selection.Add( aItem );
|
||||||
|
getView()->Add( &m_selection );
|
||||||
|
|
||||||
|
if( m_selection.Size() == 1 )
|
||||||
|
{
|
||||||
|
// Set as the current item, so the information about selection is displayed
|
||||||
|
m_frame->SetCurItem( static_cast<GERBER_DRAW_ITEM*>( aItem ), true );
|
||||||
|
}
|
||||||
|
else if( m_selection.Size() == 2 ) // Check only for 2, so it will not be
|
||||||
|
{ // called for every next selected item
|
||||||
|
// If multiple items are selected, do not show the information about the selected item
|
||||||
|
m_frame->SetCurItem( NULL, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::unselect( EDA_ITEM* aItem )
|
||||||
|
{
|
||||||
|
if( !aItem->IsSelected() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
unselectVisually( aItem );
|
||||||
|
m_selection.Remove( aItem );
|
||||||
|
|
||||||
|
if( m_selection.Empty() )
|
||||||
|
{
|
||||||
|
m_frame->SetCurItem( NULL );
|
||||||
|
getView()->Remove( &m_selection );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::selectVisually( EDA_ITEM* aItem ) const
|
||||||
|
{
|
||||||
|
// Move the item's layer to the front
|
||||||
|
int layer = static_cast<GERBER_DRAW_ITEM*>( aItem )->GetLayer();
|
||||||
|
m_frame->GetGalCanvas()->SetTopLayer( GERBER_DRAW_LAYER( layer ) );
|
||||||
|
|
||||||
|
// Hide the original item, so it is shown only on overlay
|
||||||
|
aItem->SetSelected();
|
||||||
|
getView()->Hide( aItem, true );
|
||||||
|
getView()->Update( aItem, KIGFX::GEOMETRY );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GERBVIEW_SELECTION_TOOL::unselectVisually( EDA_ITEM* aItem ) const
|
||||||
|
{
|
||||||
|
// Restore original item visibility
|
||||||
|
aItem->ClearSelected();
|
||||||
|
getView()->Hide( aItem, false );
|
||||||
|
getView()->Update( aItem, KIGFX::ALL );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GERBVIEW_SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const
|
||||||
|
{
|
||||||
|
const unsigned GRIP_MARGIN = 20;
|
||||||
|
VECTOR2D margin = getView()->ToWorld( VECTOR2D( GRIP_MARGIN, GRIP_MARGIN ), false );
|
||||||
|
|
||||||
|
// Check if the point is located within any of the currently selected items bounding boxes
|
||||||
|
for( auto item : m_selection )
|
||||||
|
{
|
||||||
|
BOX2I itemBox = item->ViewBBox();
|
||||||
|
itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item
|
||||||
|
|
||||||
|
if( itemBox.Contains( aPoint ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GERBVIEW_SELECTION_TOOL::MeasureTool( const TOOL_EVENT& aEvent )
|
||||||
|
{
|
||||||
|
auto& view = *getView();
|
||||||
|
auto& controls = *getViewControls();
|
||||||
|
|
||||||
|
Activate();
|
||||||
|
getEditFrame<GERBVIEW_FRAME>()->SetToolID( ID_TB_MEASUREMENT_TOOL,
|
||||||
|
wxCURSOR_PENCIL, _( "Measure distance between two points" ) );
|
||||||
|
|
||||||
|
KIGFX::PREVIEW::TWO_POINT_GEOMETRY_MANAGER twoPtMgr;
|
||||||
|
KIGFX::PREVIEW::RULER_ITEM ruler( twoPtMgr );
|
||||||
|
|
||||||
|
view.Add( &ruler );
|
||||||
|
view.SetVisible( &ruler, false );
|
||||||
|
|
||||||
|
bool originSet = false;
|
||||||
|
|
||||||
|
controls.ShowCursor( true );
|
||||||
|
controls.SetSnapping( true );
|
||||||
|
getViewControls()->SetAdditionalPanButtons( false, true );
|
||||||
|
|
||||||
|
while( auto evt = Wait() )
|
||||||
|
{
|
||||||
|
const VECTOR2I cursorPos = controls.GetCursorPosition();
|
||||||
|
|
||||||
|
if( evt->IsCancel() || evt->IsActivate() )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// click or drag starts
|
||||||
|
else if( !originSet &&
|
||||||
|
( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) )
|
||||||
|
{
|
||||||
|
if( !evt->IsDrag( BUT_LEFT ) )
|
||||||
|
{
|
||||||
|
twoPtMgr.SetOrigin( cursorPos );
|
||||||
|
twoPtMgr.SetEnd( cursorPos );
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.CaptureCursor( true );
|
||||||
|
controls.SetAutoPan( true );
|
||||||
|
|
||||||
|
originSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !originSet && evt->IsMotion() )
|
||||||
|
{
|
||||||
|
// make sure the origin is set before a drag starts
|
||||||
|
// otherwise you can miss a step
|
||||||
|
twoPtMgr.SetOrigin( cursorPos );
|
||||||
|
twoPtMgr.SetEnd( cursorPos );
|
||||||
|
}
|
||||||
|
|
||||||
|
// second click or mouse up after drag ends
|
||||||
|
else if( originSet &&
|
||||||
|
( evt->IsClick( BUT_LEFT ) || evt->IsMouseUp( BUT_LEFT ) ) )
|
||||||
|
{
|
||||||
|
originSet = false;
|
||||||
|
|
||||||
|
controls.SetAutoPan( false );
|
||||||
|
controls.CaptureCursor( false );
|
||||||
|
|
||||||
|
view.SetVisible( &ruler, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
// move or drag when origin set updates rules
|
||||||
|
else if( originSet &&
|
||||||
|
( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
|
||||||
|
{
|
||||||
|
twoPtMgr.SetAngleSnap( evt->Modifier( MD_CTRL ) );
|
||||||
|
twoPtMgr.SetEnd( cursorPos );
|
||||||
|
|
||||||
|
view.SetVisible( &ruler, true );
|
||||||
|
view.Update( &ruler, KIGFX::GEOMETRY );
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( evt->IsClick( BUT_RIGHT ) )
|
||||||
|
{
|
||||||
|
m_menu.ShowContextMenu( m_selection );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.SetVisible( &ruler, false );
|
||||||
|
view.Remove( &ruler );
|
||||||
|
getViewControls()->SetAdditionalPanButtons( false, false );
|
||||||
|
|
||||||
|
getEditFrame<GERBVIEW_FRAME>()->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VECTOR2I SELECTION::GetCenter() const
|
||||||
|
{
|
||||||
|
VECTOR2I centre;
|
||||||
|
|
||||||
|
if( Size() == 1 )
|
||||||
|
{
|
||||||
|
centre = static_cast<GERBER_DRAW_ITEM*>( Front() )->GetPosition();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EDA_RECT bbox = Front()->GetBoundingBox();
|
||||||
|
auto i = m_items.begin();
|
||||||
|
++i;
|
||||||
|
|
||||||
|
for( ; i != m_items.end(); ++i )
|
||||||
|
{
|
||||||
|
bbox.Merge( (*i)->GetBoundingBox() );
|
||||||
|
}
|
||||||
|
|
||||||
|
centre = bbox.Centre();
|
||||||
|
}
|
||||||
|
|
||||||
|
return centre;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BOX2I SELECTION::ViewBBox() const
|
||||||
|
{
|
||||||
|
EDA_RECT eda_bbox;
|
||||||
|
|
||||||
|
if( Size() == 1 )
|
||||||
|
{
|
||||||
|
eda_bbox = Front()->GetBoundingBox();
|
||||||
|
}
|
||||||
|
else if( Size() > 1 )
|
||||||
|
{
|
||||||
|
eda_bbox = Front()->GetBoundingBox();
|
||||||
|
auto i = m_items.begin();
|
||||||
|
++i;
|
||||||
|
|
||||||
|
for( ; i != m_items.end(); ++i )
|
||||||
|
{
|
||||||
|
eda_bbox.Merge( (*i)->GetBoundingBox() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BOX2I( eda_bbox.GetOrigin(), eda_bbox.GetSize() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const KIGFX::VIEW_GROUP::ITEMS SELECTION::updateDrawList() const
|
||||||
|
{
|
||||||
|
std::vector<VIEW_ITEM*> items;
|
||||||
|
|
||||||
|
for( auto item : m_items )
|
||||||
|
items.push_back( item );
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const TOOL_EVENT GERBVIEW_SELECTION_TOOL::SelectedEvent( TC_MESSAGE, TA_ACTION, "gerbview.InteractiveSelection.selected" );
|
||||||
|
const TOOL_EVENT GERBVIEW_SELECTION_TOOL::UnselectedEvent( TC_MESSAGE, TA_ACTION, "gerbview.InteractiveSelection.unselected" );
|
||||||
|
const TOOL_EVENT GERBVIEW_SELECTION_TOOL::ClearedEvent( TC_MESSAGE, TA_ACTION, "gerbview.InteractiveSelection.cleared" );
|
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jon Evans <jon@craftyjon.com>
|
||||||
|
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GERBVIEW_SELECTION_TOOL_H
|
||||||
|
#define __GERBVIEW_SELECTION_TOOL_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
|
||||||
|
#include <tool/tool_interactive.h>
|
||||||
|
#include <tool/context_menu.h>
|
||||||
|
#include <tool/selection.h>
|
||||||
|
#include <tool/selection_conditions.h>
|
||||||
|
#include <tool/tool_menu.h>
|
||||||
|
|
||||||
|
#include <gerbview_frame.h>
|
||||||
|
|
||||||
|
class SELECTION_AREA;
|
||||||
|
class GERBER_COLLECTOR;
|
||||||
|
|
||||||
|
namespace KIGFX
|
||||||
|
{
|
||||||
|
class GAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GERBVIEW_SELECTION_TOOL
|
||||||
|
*
|
||||||
|
* Selection tool for GerbView, based on the one in PcbNew
|
||||||
|
*/
|
||||||
|
class GERBVIEW_SELECTION_TOOL : public TOOL_INTERACTIVE
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GERBVIEW_SELECTION_TOOL();
|
||||||
|
~GERBVIEW_SELECTION_TOOL();
|
||||||
|
|
||||||
|
/// @copydoc TOOL_BASE::Init()
|
||||||
|
bool Init() override;
|
||||||
|
|
||||||
|
/// @copydoc TOOL_BASE::Reset()
|
||||||
|
void Reset( RESET_REASON aReason ) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Main()
|
||||||
|
*
|
||||||
|
* The main loop.
|
||||||
|
*/
|
||||||
|
int Main( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetSelection()
|
||||||
|
*
|
||||||
|
* Returns the set of currently selected items.
|
||||||
|
*/
|
||||||
|
SELECTION& GetSelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function RequestSelection()
|
||||||
|
*
|
||||||
|
* Returns the current selection set, filtered according to aFlags.
|
||||||
|
* If the set is empty, performs the legacy-style hover selection.
|
||||||
|
*/
|
||||||
|
SELECTION& RequestSelection( int aFlags = SELECTION_DEFAULT );
|
||||||
|
|
||||||
|
inline TOOL_MENU& GetToolMenu()
|
||||||
|
{
|
||||||
|
return m_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
///> Select a single item under cursor event handler.
|
||||||
|
int CursorSelection( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Clear current selection event handler.
|
||||||
|
int ClearSelection( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Item selection event handler.
|
||||||
|
int SelectItem( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Multiple item selection event handler
|
||||||
|
int SelectItems( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Item unselection event handler.
|
||||||
|
int UnselectItem( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Multiple item unselection event handler
|
||||||
|
int UnselectItems( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Launches a tool to measure between points
|
||||||
|
int MeasureTool( const TOOL_EVENT& aEvent );
|
||||||
|
|
||||||
|
///> Event sent after an item is selected.
|
||||||
|
static const TOOL_EVENT SelectedEvent;
|
||||||
|
|
||||||
|
///> Event sent after an item is unselected.
|
||||||
|
static const TOOL_EVENT UnselectedEvent;
|
||||||
|
|
||||||
|
///> Event sent after selection is cleared.
|
||||||
|
static const TOOL_EVENT ClearedEvent;
|
||||||
|
|
||||||
|
///> Sets up handlers for various events.
|
||||||
|
void setTransitions() override;
|
||||||
|
|
||||||
|
///> Zooms the screen to center and fit the current selection.
|
||||||
|
void zoomFitSelection( void );
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Function selectPoint()
|
||||||
|
* Selects an item pointed by the parameter aWhere. If there is more than one item at that
|
||||||
|
* place, there is a menu displayed that allows to choose the item.
|
||||||
|
*
|
||||||
|
* @param aWhere is the place where the item should be selected.
|
||||||
|
* @param aAllowDisambiguation decides what to do in case of disambiguation. If true, then
|
||||||
|
* a menu is shown, otherise function finishes without selecting anything.
|
||||||
|
* @return True if an item was selected, false otherwise.
|
||||||
|
*/
|
||||||
|
bool selectPoint( const VECTOR2I& aWhere, bool aOnDrag = false );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function selectCursor()
|
||||||
|
* Selects an item under the cursor unless there is something already selected or aSelectAlways
|
||||||
|
* is true.
|
||||||
|
* @param aSelectAlways forces to select an item even if there is an item already selected.
|
||||||
|
* @return true if eventually there is an item selected, false otherwise.
|
||||||
|
*/
|
||||||
|
bool selectCursor( bool aSelectAlways = false );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function selectMultiple()
|
||||||
|
* Handles drawing a selection box that allows to select many items at the same time.
|
||||||
|
*
|
||||||
|
* @return true if the function was cancelled (i.e. CancelEvent was received).
|
||||||
|
*/
|
||||||
|
bool selectMultiple();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function clearSelection()
|
||||||
|
* Clears the current selection.
|
||||||
|
*/
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function disambiguationMenu()
|
||||||
|
* Handles the menu that allows to select one of many items in case there is more than one
|
||||||
|
* item at the selected point (@see selectCursor()).
|
||||||
|
*
|
||||||
|
* @param aItems contains list of items that are displayed to the user.
|
||||||
|
*/
|
||||||
|
EDA_ITEM* disambiguationMenu( GERBER_COLLECTOR* aItems );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function toggleSelection()
|
||||||
|
* Changes selection status of a given item.
|
||||||
|
*
|
||||||
|
* @param aItem is the item to have selection status changed.
|
||||||
|
*/
|
||||||
|
void toggleSelection( EDA_ITEM* aItem );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function selectable()
|
||||||
|
* Checks conditions for an item to be selected.
|
||||||
|
*
|
||||||
|
* @return True if the item fulfills conditions to be selected.
|
||||||
|
*/
|
||||||
|
bool selectable( const EDA_ITEM* aItem ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function select()
|
||||||
|
* Takes necessary action mark an item as selected.
|
||||||
|
*
|
||||||
|
* @param aItem is an item to be selected.
|
||||||
|
*/
|
||||||
|
void select( EDA_ITEM* aItem );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function unselect()
|
||||||
|
* Takes necessary action mark an item as unselected.
|
||||||
|
*
|
||||||
|
* @param aItem is an item to be unselected.
|
||||||
|
*/
|
||||||
|
void unselect( EDA_ITEM* aItem );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function selectVisually()
|
||||||
|
* Marks item as selected, but does not add it to the ITEMS_PICKED_LIST.
|
||||||
|
* @param aItem is an item to be be marked.
|
||||||
|
*/
|
||||||
|
void selectVisually( EDA_ITEM* aItem ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function unselectVisually()
|
||||||
|
* Marks item as selected, but does not add it to the ITEMS_PICKED_LIST.
|
||||||
|
* @param aItem is an item to be be marked.
|
||||||
|
*/
|
||||||
|
void unselectVisually( EDA_ITEM* aItem ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function selectionContains()
|
||||||
|
* Checks if the given point is placed within any of selected items' bounding box.
|
||||||
|
*
|
||||||
|
* @return True if the given point is contained in any of selected items' bouding box.
|
||||||
|
*/
|
||||||
|
bool selectionContains( const VECTOR2I& aPoint ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function guessSelectionCandidates()
|
||||||
|
* Tries to guess best selection candidates in case multiple items are clicked, by
|
||||||
|
* doing some braindead heuristics.
|
||||||
|
* @param aCollector is the collector that has a list of items to be queried.
|
||||||
|
*/
|
||||||
|
void guessSelectionCandidates( GERBER_COLLECTOR& aCollector ) const;
|
||||||
|
|
||||||
|
/// Pointer to the parent frame.
|
||||||
|
GERBVIEW_FRAME* m_frame;
|
||||||
|
|
||||||
|
/// Current state of selection.
|
||||||
|
SELECTION m_selection;
|
||||||
|
|
||||||
|
/// Flag saying if items should be added to the current selection or rather replace it.
|
||||||
|
bool m_additive;
|
||||||
|
|
||||||
|
/// Flag saying if items should be removed from the current selection
|
||||||
|
bool m_subtractive;
|
||||||
|
|
||||||
|
/// Flag saying if multiple selection mode is active.
|
||||||
|
bool m_multiple;
|
||||||
|
|
||||||
|
/// Determines if the selection is preliminary or final.
|
||||||
|
bool m_preliminary;
|
||||||
|
|
||||||
|
/// Menu model displayed by the tool.
|
||||||
|
TOOL_MENU m_menu;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue