kicad/pcbnew/swap_layers.cpp

417 lines
14 KiB
C++
Raw Normal View History

/**
* @file swap_layers.cpp
* @brief Dialog to swap layers.
*/
#include <fctsys.h>
#include <class_drawpanel.h>
#include <confirm.h>
#include <wxPcbStruct.h>
#include <dialog_shim.h>
#include <class_board.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <pcbnew.h>
#include <wx/statline.h>
#define LAYER_NO_CHANGE NB_LAYERS
static LAYER_NUM New_Layer[NB_PCB_LAYERS];
wxStaticText* layer_list[NB_PCB_LAYERS];
enum swap_layer_id {
ID_WINEDA_SWAPLAYERFRAME = 1800,
ID_BUTTON_0,
ID_TEXT_0 = ID_BUTTON_0 + NB_PCB_LAYERS
};
class SWAP_LAYERS_DIALOG : public DIALOG_SHIM
{
private:
PCB_BASE_FRAME* m_Parent;
wxBoxSizer* OuterBoxSizer;
wxBoxSizer* MainBoxSizer;
wxFlexGridSizer* FlexColumnBoxSizer;
wxStaticText* label;
wxButton* Button;
wxStaticText* text;
wxStaticLine* Line;
wxStdDialogButtonSizer* StdDialogButtonSizer;
public:
SWAP_LAYERS_DIALOG( PCB_BASE_FRAME* parent );
~SWAP_LAYERS_DIALOG() { };
private:
void Sel_Layer( wxCommandEvent& event );
void OnOkClick( wxCommandEvent& event );
void OnCancelClick( wxCommandEvent& event );
2007-08-23 04:28:46 +00:00
DECLARE_EVENT_TABLE()
};
2007-10-07 03:08:24 +00:00
BEGIN_EVENT_TABLE( SWAP_LAYERS_DIALOG, wxDialog )
EVT_COMMAND_RANGE( ID_BUTTON_0, ID_BUTTON_0 + NB_PCB_LAYERS - 1,
wxEVT_COMMAND_BUTTON_CLICKED,
SWAP_LAYERS_DIALOG::Sel_Layer )
EVT_BUTTON( wxID_OK, SWAP_LAYERS_DIALOG::OnOkClick )
EVT_BUTTON( wxID_CANCEL, SWAP_LAYERS_DIALOG::OnCancelClick )
END_EVENT_TABLE()
SWAP_LAYERS_DIALOG::SWAP_LAYERS_DIALOG( PCB_BASE_FRAME* parent ) :
DIALOG_SHIM( parent, -1, _( "Swap Layers:" ), wxPoint( -1, -1 ),
wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
{
BOARD* board = parent->GetBoard();
2008-03-04 04:22:27 +00:00
OuterBoxSizer = NULL;
MainBoxSizer = NULL;
FlexColumnBoxSizer = NULL;
label = NULL;
Button = NULL;
text = NULL;
Line = NULL;
StdDialogButtonSizer = NULL;
2007-08-23 04:28:46 +00:00
m_Parent = parent;
int item_ID;
wxSize goodSize;
/* Experimentation has shown that buttons in the Windows version can be
* 20 pixels wide and 20 pixels high, but that they need to be 26 pixels
* wide and 26 pixels high in the Linux version. (And although the
* dimensions of those buttons could be set to 26 pixels wide and 26
* pixels high in both of those versions, that would result in a dialog
* box which would be excessively high in the Windows version.)
*/
#ifdef __WINDOWS__
int w = 20;
int h = 20;
#else
int w = 26;
int h = 26;
#endif
/* As currently implemented, the dimensions of the buttons in the Mac
* version are also 26 pixels wide and 26 pixels high. If appropriate,
* the above code should be modified as required in the event that those
* buttons should be some other size in that version.
*/
OuterBoxSizer = new wxBoxSizer( wxVERTICAL );
SetSizer( OuterBoxSizer );
MainBoxSizer = new wxBoxSizer( wxHORIZONTAL );
OuterBoxSizer->Add( MainBoxSizer, 1, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
for( LAYER_NUM ii = FIRST_LAYER; ii < NB_PCB_LAYERS; ++ii )
2007-08-23 04:28:46 +00:00
{
// Provide a vertical line to separate the two FlexGrid sizers
if( ii == 16 )
{
Line = new wxStaticLine( this,
-1,
wxDefaultPosition,
wxDefaultSize,
wxLI_VERTICAL );
MainBoxSizer->Add( Line, 0, wxGROW | wxLEFT | wxRIGHT, 5 );
}
// Provide a separate FlexGrid sizer for every sixteen sets of controls
if( ii % 16 == 0 )
{
/* Each layer has an associated static text string (to identify
* that layer), a button (for invoking a child dialog box to
* change which layer that the layer is mapped to), and a second
* static text string (to depict which layer that the layer has
* been mapped to). Each of those items are placed into the left
* hand column, middle column, and right hand column (respectively)
* of the Flexgrid sizer, and the color of the second text string
* is set to fuchsia or blue (to respectively indicate whether the
* layer has been swapped to another layer or is not being swapped
* at all). (Experimentation has shown that if a text control is
* used to depict which layer that each layer is mapped to (instead
* of a static text string), then those controls do not behave in
* a fully satisfactory manner in the Linux version. Even when the
* read-only attribute is specified for all of those controls, they
* can still be selected when the arrow keys or Tab key is used
* to step through all of the controls within the dialog box, and
* directives to set the foreground color of the text of each such
* control to blue (to indicate that the text is of a read-only
* nature) are disregarded.)
*
* Specify a FlexGrid sizer with sixteen rows and three columns.
*/
FlexColumnBoxSizer = new wxFlexGridSizer( 16, 3, 0, 0 );
// Specify that all of the rows can be expanded.
for( int jj = 0; jj < 16; jj++ )
{
FlexColumnBoxSizer->AddGrowableRow( jj );
}
// Specify that (just) the right-hand column can be expanded.
FlexColumnBoxSizer->AddGrowableCol( 2 );
MainBoxSizer->Add( FlexColumnBoxSizer, 1, wxGROW | wxTOP, 5 );
}
2007-08-23 04:28:46 +00:00
/* Provide a text string to identify this layer (with trailing spaces
* within that string being purged).
*/
2008-03-04 04:22:27 +00:00
label = new wxStaticText( this, wxID_STATIC, board->GetLayerName( ii ),
wxDefaultPosition, wxDefaultSize,
wxALIGN_RIGHT );
FlexColumnBoxSizer->Add( label, 0,
wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL |
wxLEFT | wxBOTTOM,
5 );
2007-08-23 04:28:46 +00:00
// Provide a button for this layer (which will invoke a child dialog box)
item_ID = ID_BUTTON_0 + ii;
2007-08-23 04:28:46 +00:00
Button = new wxButton( this, item_ID, wxT( "..." ), wxDefaultPosition,
wxSize( w, h ), 0 );
FlexColumnBoxSizer->Add( Button, 0,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
wxLEFT | wxBOTTOM, 5 );
/* Provide another text string to specify which layer that this layer
* is mapped to, set the initial text to "No Change" (to indicate that
* this layer is currently unmapped to any other layer), and set the
* foreground color of the text to blue (which also indicates that the
* layer is currently unmapped to any other layer).
*/
item_ID = ID_TEXT_0 + ii;
2007-08-23 04:28:46 +00:00
/* When the first of these text strings is being added, determine
* what size is necessary to to be able to display the longest
* string without truncation. Then use that size as the
* minimum size for all text strings. (If the minimum
* size is not this size, strings can be truncated after
* some other layer is selected.)
*/
if( ii == 0 )
{
text = new wxStaticText( this, item_ID, board->GetLayerName( FIRST_LAYER ),
wxDefaultPosition, wxDefaultSize, 0 );
goodSize = text->GetSize();
for( LAYER_NUM jj = LAYER_N_2; jj < NB_PCB_LAYERS; ++jj )
{
2008-03-04 04:22:27 +00:00
text->SetLabel( board->GetLayerName( jj ) );
if( goodSize.x < text->GetSize().x )
goodSize.x = text->GetSize().x;
}
text->SetLabel( _( "No Change" ) );
if( goodSize.x < text->GetSize().x )
goodSize.x = text->GetSize().x;
}
else
{
text = new wxStaticText( this, item_ID, _( "No Change" ),
wxDefaultPosition, wxDefaultSize, 0 );
}
text->SetMinSize( goodSize );
FlexColumnBoxSizer->Add( text, 1,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL |
wxLEFT | wxRIGHT | wxBOTTOM, 5 );
layer_list[ii] = text;
}
/* Provide spacers to occupy otherwise blank cells within the second
* FlexGrid sizer. (Becuse there are three columns, three spacers
* are thus required for each unused row.)
*/
for( int ii = 3 * NB_PCB_LAYERS; ii < 96; ii++ )
{
FlexColumnBoxSizer->Add( 5, h, 0, wxALIGN_CENTER_HORIZONTAL |
wxALIGN_CENTER_VERTICAL | wxLEFT |
wxRIGHT | wxBOTTOM, 5 );
}
2007-08-23 04:28:46 +00:00
// Provide a line to separate the controls which have been provided so far
// from the OK and Cancel buttons (which will be provided after this line)
Line = new wxStaticLine( this, -1, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
OuterBoxSizer->Add( Line, 0, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
2007-08-23 04:28:46 +00:00
// Provide a StdDialogButtonSizer to accommodate the OK and Cancel buttons;
// using that type of sizer results in those buttons being automatically
// located in positions appropriate for each (OS) version of KiCad.
StdDialogButtonSizer = new wxStdDialogButtonSizer;
OuterBoxSizer->Add( StdDialogButtonSizer, 0, wxGROW | wxALL, 10 );
2007-08-23 04:28:46 +00:00
Button = new wxButton( this, wxID_OK, _( "&OK" ), wxDefaultPosition, wxDefaultSize, 0 );
Button->SetDefault();
StdDialogButtonSizer->AddButton( Button );
2007-08-23 04:28:46 +00:00
Button = new wxButton( this, wxID_CANCEL, _( "&Cancel" ),
wxDefaultPosition, wxDefaultSize, 0 );
StdDialogButtonSizer->AddButton( Button );
StdDialogButtonSizer->Realize();
2007-08-23 04:28:46 +00:00
// Resize the dialog
if( GetSizer() )
{
GetSizer()->SetSizeHints( this );
}
Center();
}
void SWAP_LAYERS_DIALOG::Sel_Layer( wxCommandEvent& event )
{
int ii;
2007-08-23 04:28:46 +00:00
ii = event.GetId();
if( ii < ID_BUTTON_0 || ii >= ID_BUTTON_0 + NB_PCB_LAYERS )
return;
2007-08-23 04:28:46 +00:00
ii = event.GetId() - ID_BUTTON_0;
LAYER_NUM layer = New_Layer[ii];
if( (layer < 0) || (layer > NB_PCB_LAYERS) )
layer = LAYER_NO_CHANGE; // (Defaults to "No Change".)
LAYER_MSK notallowed_mask = ii < NB_COPPER_LAYERS ?
ALL_NO_CU_LAYERS : ALL_CU_LAYERS;
layer = m_Parent->SelectLayer( layer == LAYER_NO_CHANGE ? ii : layer,
notallowed_mask );
2008-03-04 04:22:27 +00:00
if( !IsValidLayer( layer ) )
return;
if( layer != New_Layer[ii] )
{
New_Layer[ii] = layer;
if( layer >= LAYER_NO_CHANGE || layer == ii )
{
layer_list[ii]->SetLabel( _( "No Change" ) );
// Change the text color to blue (to highlight
// that this layer is *not* being swapped)
layer_list[ii]->SetForegroundColour( *wxBLUE );
}
else
{
layer_list[ii]->SetLabel( m_Parent->GetBoard()->GetLayerName( layer ) );
// Change the text color to fuchsia (to highlight
// that this layer *is* being swapped)
layer_list[ii]->SetForegroundColour( wxColour( 255, 0, 128 ) );
}
2007-08-23 04:28:46 +00:00
}
}
2007-08-23 04:28:46 +00:00
void SWAP_LAYERS_DIALOG::OnCancelClick( wxCommandEvent& event )
{
2007-08-23 04:28:46 +00:00
EndModal( -1 );
}
2007-08-23 04:28:46 +00:00
void SWAP_LAYERS_DIALOG::OnOkClick( wxCommandEvent& event )
{
2007-08-23 04:28:46 +00:00
EndModal( 1 );
}
void PCB_EDIT_FRAME::Swap_Layers( wxCommandEvent& event )
{
int ii, jj;
TRACK* pt_segm;
DRAWSEGMENT* pt_drawsegm;
EDA_ITEM* PtStruct;
2007-08-23 04:28:46 +00:00
/* Init default values */
for( ii = FIRST_LAYER; ii < NB_PCB_LAYERS; ii++ )
New_Layer[ii] = LAYER_NO_CHANGE;
2007-08-23 04:28:46 +00:00
SWAP_LAYERS_DIALOG dlg( this );
2007-08-23 04:28:46 +00:00
ii = dlg.ShowModal();
2007-08-23 04:28:46 +00:00
if( ii != 1 )
return; // (Canceled dialog box returns -1 instead)
2007-08-23 04:28:46 +00:00
/* Change traces. */
pt_segm = GetBoard()->m_Track;
for( ; pt_segm != NULL; pt_segm = pt_segm->Next() )
2007-08-23 04:28:46 +00:00
{
OnModify();
if( pt_segm->Type() == PCB_VIA_T )
2007-08-23 04:28:46 +00:00
{
SEGVIA* Via = (SEGVIA*) pt_segm;
2011-12-14 04:29:25 +00:00
if( Via->GetShape() == VIA_THROUGH )
2007-08-23 04:28:46 +00:00
continue;
LAYER_NUM top_layer, bottom_layer;
* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
Via->LayerPair( &top_layer, &bottom_layer );
if( New_Layer[bottom_layer] >= 0 && New_Layer[bottom_layer] < LAYER_NO_CHANGE )
2007-08-23 04:28:46 +00:00
bottom_layer = New_Layer[bottom_layer];
if( New_Layer[top_layer] >= 0 && New_Layer[top_layer] < LAYER_NO_CHANGE )
2007-08-23 04:28:46 +00:00
top_layer = New_Layer[top_layer];
2007-08-23 04:28:46 +00:00
Via->SetLayerPair( top_layer, bottom_layer );
}
else
{
jj = pt_segm->GetLayer();
if( New_Layer[jj] >= 0 && New_Layer[jj] < LAYER_NO_CHANGE )
2007-08-23 04:28:46 +00:00
pt_segm->SetLayer( New_Layer[jj] );
}
}
/* Change zones. */
for( pt_segm = GetBoard()->m_Zone; pt_segm; pt_segm = pt_segm->Next() )
2007-08-23 04:28:46 +00:00
{
OnModify();
2007-08-23 04:28:46 +00:00
jj = pt_segm->GetLayer();
if( New_Layer[jj] >= 0 && New_Layer[jj] < LAYER_NO_CHANGE )
2007-08-23 04:28:46 +00:00
pt_segm->SetLayer( New_Layer[jj] );
}
/* Change other segments. */
PtStruct = GetBoard()->m_Drawings;
for( ; PtStruct != NULL; PtStruct = PtStruct->Next() )
2007-08-23 04:28:46 +00:00
{
if( PtStruct->Type() == PCB_LINE_T )
2007-08-23 04:28:46 +00:00
{
OnModify();
2007-08-23 04:28:46 +00:00
pt_drawsegm = (DRAWSEGMENT*) PtStruct;
jj = pt_drawsegm->GetLayer();
if( New_Layer[jj] >= 0 && New_Layer[jj] < LAYER_NO_CHANGE )
2007-08-23 04:28:46 +00:00
pt_drawsegm->SetLayer( New_Layer[jj] );
}
}
m_canvas->Refresh( true );
}