74 changed files with 4388 additions and 533 deletions
-
1AUTHORS.txt
-
43common/draw_frame.cpp
-
4common/draw_panel_gal.cpp
-
6common/gal/cairo/cairo_gal.cpp
-
50common/view/view.cpp
-
8gerbview/CMakeLists.txt
-
58gerbview/class_aperture_macro.cpp
-
20gerbview/class_aperture_macro.h
-
4gerbview/class_gbr_display_options.h
-
2gerbview/class_gbr_layer_box_selector.cpp
-
67gerbview/class_gbr_layout.cpp
-
27gerbview/class_gbr_layout.h
-
253gerbview/class_gerber_draw_item.cpp
-
41gerbview/class_gerber_draw_item.h
-
59gerbview/class_gerber_file_image.cpp
-
30gerbview/class_gerber_file_image.h
-
4gerbview/class_gerber_file_image_list.cpp
-
13gerbview/class_gerber_file_image_list.h
-
89gerbview/class_gerbview_layer_widget.cpp
-
2gerbview/class_gerbview_layer_widget.h
-
10gerbview/clear_gbr_drawlayers.cpp
-
121gerbview/dcode.cpp
-
11gerbview/dcode.h
-
52gerbview/dialogs/gerbview_dialog_display_options_frame.cpp
-
45gerbview/dialogs/gerbview_dialog_display_options_frame_base.cpp
-
129gerbview/dialogs/gerbview_dialog_display_options_frame_base.fbp
-
8gerbview/dialogs/gerbview_dialog_display_options_frame_base.h
-
13gerbview/draw_gerber_screen.cpp
-
155gerbview/events_called_functions.cpp
-
28gerbview/excellon_read_drill_file.cpp
-
25gerbview/files.cpp
-
71gerbview/gerber_collectors.cpp
-
134gerbview/gerber_collectors.h
-
7gerbview/gerbview_config.cpp
-
154gerbview/gerbview_draw_panel_gal.cpp
-
64gerbview/gerbview_draw_panel_gal.h
-
230gerbview/gerbview_frame.cpp
-
50gerbview/gerbview_frame.h
-
6gerbview/gerbview_id.h
-
566gerbview/gerbview_painter.cpp
-
203gerbview/gerbview_painter.h
-
47gerbview/hotkeys.cpp
-
5gerbview/hotkeys.h
-
4gerbview/job_file_reader.cpp
-
2gerbview/locate.cpp
-
28gerbview/menubar.cpp
-
4gerbview/onleftclick.cpp
-
2gerbview/onrightclick.cpp
-
20gerbview/readgerb.cpp
-
27gerbview/rs274d.cpp
-
2gerbview/rs274x.cpp
-
94gerbview/toolbars_gerber.cpp
-
76gerbview/tools/gerbview_actions.cpp
-
139gerbview/tools/gerbview_actions.h
-
128gerbview/tools/gerbview_control.cpp
-
66gerbview/tools/gerbview_control.h
-
968gerbview/tools/selection_tool.cpp
-
253gerbview/tools/selection_tool.h
-
5include/core/typeinfo.h
-
20include/draw_frame.h
-
3include/gal/cairo/cairo_gal.h
-
13include/gal/graphics_abstraction_layer.h
-
7include/gal/opengl/opengl_gal.h
-
18include/layers_id_colors_and_visibility.h
-
0include/tool/zoom_tool.h
-
22include/view/view.h
-
3include/view/view_item.h
-
13include/wxBasePcbFrame.h
-
7include/wxPcbStruct.h
-
40pcbnew/basepcbframe.cpp
-
7pcbnew/pcb_painter.cpp
-
3pcbnew/pcb_painter.h
-
2pcbnew/pcbframe.cpp
-
30pcbnew/tools/selection_tool.cpp
@ -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,566 @@ |
|||
/*
|
|||
* 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 ); |
|||
|
|||
// TODO: Should brightened color be a preference?
|
|||
if( aItem->IsBrightened() ) |
|||
color = COLOR4D( 0.0, 1.0, 0.0, 0.75 ); |
|||
|
|||
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,968 @@ |
|||
/*
|
|||
* 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; |
|||
KIGFX::VIEW_GROUP highlightGroup; |
|||
CONTEXT_MENU menu; |
|||
|
|||
highlightGroup.SetLayer( LAYER_GP_OVERLAY ); |
|||
getView()->Add( &highlightGroup ); |
|||
|
|||
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(); |
|||
getView()->Hide( current, false ); |
|||
highlightGroup.Remove( current ); |
|||
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); |
|||
} |
|||
|
|||
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(); |
|||
getView()->Hide( current, true ); |
|||
highlightGroup.Add( current ); |
|||
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); |
|||
} |
|||
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; |
|||
} |
|||
} |
|||
|
|||
if( current && current->IsBrightened() ) |
|||
{ |
|||
current->ClearBrightened(); |
|||
getView()->Hide( current, false ); |
|||
getView()->MarkTargetDirty( KIGFX::TARGET_OVERLAY ); |
|||
} |
|||
|
|||
getView()->Remove( &highlightGroup ); |
|||
|
|||
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; |
|||
} |
|||
|
|||
m_selection.Add( aItem ); |
|||
getView()->Add( &m_selection ); |
|||
selectVisually( aItem ); |
|||
|
|||
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 ) |
|||
{ |
|||
// Move the item's layer to the front
|
|||
int layer = static_cast<GERBER_DRAW_ITEM*>( aItem )->GetLayer(); |
|||
m_frame->SetActiveLayer( layer, true ); |
|||
|
|||
// Hide the original item, so it is shown only on overlay
|
|||
aItem->SetSelected(); |
|||
getView()->Hide( aItem, true ); |
|||
|
|||
getView()->Update( &m_selection ); |
|||
} |
|||
|
|||
|
|||
void GERBVIEW_SELECTION_TOOL::unselectVisually( EDA_ITEM* aItem ) |
|||
{ |
|||
// Restore original item visibility
|
|||
aItem->ClearSelected(); |
|||
getView()->Hide( aItem, false ); |
|||
getView()->Update( aItem, KIGFX::ALL ); |
|||
|
|||
getView()->Update( &m_selection ); |
|||
} |
|||
|
|||
|
|||
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 ); |
|||
|
|||
/** |
|||
* 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 ); |
|||
|
|||
/** |
|||
* 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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue