From 339dd0daf2d6d73900f44337ab0e25aa6110570a Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Thu, 6 Mar 2014 13:38:39 -0500 Subject: [PATCH 01/46] Coding policy fixes. --- pcbnew/exporters/gen_drill_report_files.cpp | 166 ++++++------------ pcbnew/exporters/gendrill_Excellon_writer.cpp | 89 ++++------ pcbnew/exporters/gendrill_Excellon_writer.h | 90 ++++++++-- 3 files changed, 163 insertions(+), 182 deletions(-) diff --git a/pcbnew/exporters/gen_drill_report_files.cpp b/pcbnew/exporters/gen_drill_report_files.cpp index 2c4f9b8c7c..c378353e11 100644 --- a/pcbnew/exporters/gen_drill_report_files.cpp +++ b/pcbnew/exporters/gen_drill_report_files.cpp @@ -55,12 +55,6 @@ inline double diameter_in_mm( double ius ) } -/* Creates a hole map of the board in HPGL, POSTSCRIPT or other supported formats - * Each hole size has a the drill mark symbol (circle, cross X, cross + ...) up to - * PLOTTER::MARKER_COUNT different values. - * If more than PLOTTER::MARKER_COUNT different values, - * these other vaules share the same mark - */ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, const PAGE_INFO& aSheet, PlotFormat aFormat ) @@ -87,15 +81,15 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, break; case PLOT_FORMAT_HPGL: // Scale for HPGL format. - { - HPGL_PLOTTER* hpgl_plotter = new HPGL_PLOTTER; - plotter = hpgl_plotter; - hpgl_plotter->SetPenNumber( plot_opts.GetHPGLPenNum() ); - hpgl_plotter->SetPenSpeed( plot_opts.GetHPGLPenSpeed() ); - hpgl_plotter->SetPenOverlap( 0 ); - plotter->SetPageSettings( aSheet ); - plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); - } + { + HPGL_PLOTTER* hpgl_plotter = new HPGL_PLOTTER; + plotter = hpgl_plotter; + hpgl_plotter->SetPenNumber( plot_opts.GetHPGLPenNum() ); + hpgl_plotter->SetPenSpeed( plot_opts.GetHPGLPenSpeed() ); + hpgl_plotter->SetPenOverlap( 0 ); + plotter->SetPageSettings( aSheet ); + plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); + } break; @@ -104,59 +98,59 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, // fall through case PLOT_FORMAT_PDF: case PLOT_FORMAT_POST: - { - PAGE_INFO pageA4( wxT( "A4" ) ); - wxSize pageSizeIU = pageA4.GetSizeIU(); + { + PAGE_INFO pageA4( wxT( "A4" ) ); + wxSize pageSizeIU = pageA4.GetSizeIU(); - // Reserve a margin around the page. - int margin = KiROUND( 20 * IU_PER_MM ); + // Reserve a margin around the page. + int margin = KiROUND( 20 * IU_PER_MM ); - // Calculate a scaling factor to print the board on the sheet - double Xscale = double( pageSizeIU.x - ( 2 * margin ) ) / bbbox.GetWidth(); + // Calculate a scaling factor to print the board on the sheet + double Xscale = double( pageSizeIU.x - ( 2 * margin ) ) / bbbox.GetWidth(); - // We should print the list of drill sizes, so reserve room for it - // 60% height for board 40% height for list - int ypagesize_for_board = KiROUND( pageSizeIU.y * 0.6 ); - double Yscale = double( ypagesize_for_board - margin ) / bbbox.GetHeight(); + // We should print the list of drill sizes, so reserve room for it + // 60% height for board 40% height for list + int ypagesize_for_board = KiROUND( pageSizeIU.y * 0.6 ); + double Yscale = double( ypagesize_for_board - margin ) / bbbox.GetHeight(); - scale = std::min( Xscale, Yscale ); + scale = std::min( Xscale, Yscale ); - // Experience shows the scale should not to large, because texts - // create problem (can be to big or too small). - // So the scale is clipped at 3.0; - scale = std::min( scale, 3.0 ); + // Experience shows the scale should not to large, because texts + // create problem (can be to big or too small). + // So the scale is clipped at 3.0; + scale = std::min( scale, 3.0 ); - offset.x = KiROUND( double( bbbox.Centre().x ) - - ( pageSizeIU.x / 2.0 ) / scale ); - offset.y = KiROUND( double( bbbox.Centre().y ) - - ( ypagesize_for_board / 2.0 ) / scale ); + offset.x = KiROUND( double( bbbox.Centre().x ) - + ( pageSizeIU.x / 2.0 ) / scale ); + offset.y = KiROUND( double( bbbox.Centre().y ) - + ( ypagesize_for_board / 2.0 ) / scale ); - if( aFormat == PLOT_FORMAT_PDF ) - plotter = new PDF_PLOTTER; - else - plotter = new PS_PLOTTER; + if( aFormat == PLOT_FORMAT_PDF ) + plotter = new PDF_PLOTTER; + else + plotter = new PS_PLOTTER; - plotter->SetPageSettings( pageA4 ); - plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); - } + plotter->SetPageSettings( pageA4 ); + plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); + } break; case PLOT_FORMAT_DXF: - { - DXF_PLOTTER* dxf_plotter = new DXF_PLOTTER; - plotter = dxf_plotter; - plotter->SetPageSettings( aSheet ); - plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); - } + { + DXF_PLOTTER* dxf_plotter = new DXF_PLOTTER; + plotter = dxf_plotter; + plotter->SetPageSettings( aSheet ); + plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); + } break; case PLOT_FORMAT_SVG: - { - SVG_PLOTTER* svg_plotter = new SVG_PLOTTER; - plotter = svg_plotter; - plotter->SetPageSettings( aSheet ); - plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); - } + { + SVG_PLOTTER* svg_plotter = new SVG_PLOTTER; + plotter = svg_plotter; + plotter->SetPageSettings( aSheet ); + plotter->SetViewport( offset, IU_PER_DECIMILS, scale, false ); + } break; } @@ -239,8 +233,7 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, plotY += intervalle; plot_diam = KiROUND( m_toolListBuffer[ii].m_Diameter ); - x = KiROUND( plotX - textmarginaftersymbol * charScale - - plot_diam / 2.0 ); + x = KiROUND( plotX - textmarginaftersymbol * charScale - plot_diam / 2.0 ); y = KiROUND( plotY + charSize * charScale ); plotter->Marker( wxPoint( x, y ), plot_diam, ii ); @@ -267,10 +260,9 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, m_toolListBuffer[ii].m_OvalCount ); msg += FROM_UTF8( line ); - plotter->Text( wxPoint( plotX, y ), UNSPECIFIED_COLOR, - msg, - 0, wxSize( KiROUND( charSize * charScale ), - KiROUND( charSize * charScale ) ), + plotter->Text( wxPoint( plotX, y ), UNSPECIFIED_COLOR, msg, 0, + wxSize( KiROUND( charSize * charScale ), + KiROUND( charSize * charScale ) ), GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_CENTER, TextWidth, false, false ); @@ -287,52 +279,6 @@ bool EXCELLON_WRITER::GenDrillMapFile( const wxString& aFullFileName, } -/* - * Create a plain text report file giving a list of drill values and drill count - * for through holes, oblong holes, and for buried vias, - * drill values and drill count per layer pair - */ -/* Here is a sample created by this function: - * Drill report for F:/tmp/interf_u/interf_u.brd - * Created on 04/10/2012 20:48:38 - * Selected Drill Unit: Imperial (inches) - * - * Drill report for plated through holes : - * T1 0,025" 0,64mm (88 holes) - * T2 0,031" 0,79mm (120 holes) - * T3 0,032" 0,81mm (151 holes) (with 1 slot) - * T4 0,040" 1,02mm (43 holes) - * T5 0,079" 2,00mm (1 hole) (with 1 slot) - * T6 0,120" 3,05mm (1 hole) (with 1 slot) - * - * Total plated holes count 404 - * - * - * Drill report for buried and blind vias : - * - * Drill report for holes from layer Soudure to layer Interne1 : - * - * Total plated holes count 0 - * - * - * Drill report for holes from layer Interne1 to layer Interne2 : - * T1 0,025" 0,64mm (3 holes) - * - * Total plated holes count 3 - * - * - * Drill report for holes from layer Interne2 to layer Composant : - * T1 0,025" 0,64mm (1 hole) - * - * Total plated holes count 1 - * - * - * Drill report for unplated through holes : - * T1 0,120" 3,05mm (1 hole) (with 1 slot) - * - * Total unplated holes count 1 - * - */ bool EXCELLON_WRITER::GenDrillReportFile( const wxString& aFullFileName ) { unsigned totalHoleCount; @@ -360,7 +306,7 @@ bool EXCELLON_WRITER::GenDrillReportFile( const wxString& aFullFileName ) for( ; ; ) { BuildHolesList( layer1, layer2, - gen_through_holes ? false : true, gen_NPTH_holes, false); + gen_through_holes ? false : true, gen_NPTH_holes, false); totalHoleCount = 0; @@ -461,17 +407,17 @@ bool EXCELLON_WRITER::GenDrillReportFile( const wxString& aFullFileName ) return true; } -// Helper function to plot drill marks: + bool EXCELLON_WRITER::PlotDrillMarks( PLOTTER* aPlotter ) { // Plot the drill map: wxPoint pos; + for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) { pos = m_holeListBuffer[ii].m_Hole_Pos; - /* Always plot the drill symbol (for slots identifies the needed - * cutter!) */ + // Always plot the drill symbol (for slots identifies the needed cutter! aPlotter->Marker( pos, m_holeListBuffer[ii].m_Hole_Diameter, m_holeListBuffer[ii].m_Tool_Reference - 1 ); diff --git a/pcbnew/exporters/gendrill_Excellon_writer.cpp b/pcbnew/exporters/gendrill_Excellon_writer.cpp index 91b486c4ad..8f7ebea875 100644 --- a/pcbnew/exporters/gendrill_Excellon_writer.cpp +++ b/pcbnew/exporters/gendrill_Excellon_writer.cpp @@ -69,11 +69,7 @@ */ -/* - * Create the drill file in EXCELLON format - * return hole count - */ -int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) +int EXCELLON_WRITER::CreateDrillFile( FILE* aFile ) { m_file = aFile; @@ -100,7 +96,8 @@ int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) fputs( "G90\n", m_file ); // Absolute mode fputs( "G05\n", m_file ); // Drill mode - /* Units : */ + + // Units : if( !m_minimalHeader ) { if( m_unitsDecimal ) @@ -112,12 +109,14 @@ int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) /* Read the hole file and generate lines for normal holes (oblong * holes will be created later) */ int tool_reference = -2; + for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) { HOLE_INFO& hole_descr = m_holeListBuffer[ii]; if( hole_descr.m_Hole_Shape ) continue; // oblong holes will be created later + if( tool_reference != hole_descr.m_Tool_Reference ) { tool_reference = hole_descr.m_Tool_Reference; @@ -145,16 +144,18 @@ int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ ) { HOLE_INFO& hole_descr = m_holeListBuffer[ii]; + if( hole_descr.m_Hole_Shape == 0 ) continue; // wait for oblong holes + if( tool_reference != hole_descr.m_Tool_Reference ) { tool_reference = hole_descr.m_Tool_Reference; fprintf( m_file, "T%d\n", tool_reference ); } - diam = std::min( hole_descr.m_Hole_Size.x, - hole_descr.m_Hole_Size.y ); + diam = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y ); + if( diam == 0 ) continue; @@ -166,20 +167,23 @@ int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) if( hole_descr.m_Hole_Size.x < hole_descr.m_Hole_Size.y ) { int delta = ( hole_descr.m_Hole_Size.y - hole_descr.m_Hole_Size.x ) / 2; - y0 -= delta; yf += delta; + y0 -= delta; + yf += delta; } else { int delta = ( hole_descr.m_Hole_Size.x - hole_descr.m_Hole_Size.y ) / 2; - x0 -= delta; xf += delta; + x0 -= delta; + xf += delta; } + RotatePoint( &x0, &y0, xc, yc, hole_descr.m_Hole_Orient ); RotatePoint( &xf, &yf, xc, yc, hole_descr.m_Hole_Orient ); - if( !m_mirror ) { - y0 *= -1; yf *= -1; + y0 *= -1; + yf *= -1; } xt = x0 * m_conversionUnits; @@ -189,11 +193,12 @@ int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) /* remove the '\n' from end of line, because we must add the "G85" * command to the line: */ for( int kk = 0; line[kk] != 0; kk++ ) + { if( line[kk] == '\n' || line[kk] =='\r' ) line[kk] = 0; + } fputs( line, m_file ); - fputs( "G85", m_file ); // add the "G85" command xt = xf * m_conversionUnits; @@ -213,14 +218,6 @@ int EXCELLON_WRITER::CreateDrillFile( FILE * aFile ) } -/** - * SetFormat - * Initialize internal parameters to match the given format - * @param aMetric = true for metric coordinates, false for imperial units - * @param aZerosFmt = DECIMAL_FORMAT, SUPPRESS_LEADING, SUPPRESS_TRAILING, KEEP_ZEROS - * @param aLeftDigits = number of digits for integer part of coordinates - * @param aRightDigits = number of digits for mantissa part of coordinates - */ void EXCELLON_WRITER::SetFormat( bool aMetric, zeros_fmt aZerosFmt, int aLeftDigits, @@ -240,10 +237,6 @@ void EXCELLON_WRITER::SetFormat( bool aMetric, } -/* Created a line like: - * X48000Y19500 - * According to the selected format - */ void EXCELLON_WRITER::WriteCoordinates( char* aLine, double aCoordX, double aCoordY ) { wxString xs, ys; @@ -277,8 +270,10 @@ void EXCELLON_WRITER::WriteCoordinates( char* aLine, double aCoordX, double aCoo //Remove useless trailing 0 while( xs.Last() == '0' ) xs.RemoveLast(); + while( ys.Last() == '0' ) ys.RemoveLast(); + sprintf( aLine, "X%sY%s\n", TO_UTF8( xs ), TO_UTF8( ys ) ); break; @@ -301,6 +296,7 @@ void EXCELLON_WRITER::WriteCoordinates( char* aLine, double aCoordX, double aCoo if( aCoordX < 0 ) xpad++; + if( aCoordY < 0 ) ypad++; @@ -308,10 +304,12 @@ void EXCELLON_WRITER::WriteCoordinates( char* aLine, double aCoordX, double aCoo ys.Printf( wxT( "%0*d" ), ypad, KiROUND( aCoordY ) ); size_t j = xs.Len() - 1; + while( xs[j] == '0' && j ) xs.Truncate( j-- ); j = ys.Len() - 1; + while( ys[j] == '0' && j ) ys.Truncate( j-- ); @@ -327,8 +325,10 @@ void EXCELLON_WRITER::WriteCoordinates( char* aLine, double aCoordX, double aCoo if( aCoordX < 0 ) xpad++; + if( aCoordY < 0 ) ypad++; + xs.Printf( wxT( "%0*d" ), xpad, KiROUND( aCoordX ) ); ys.Printf( wxT( "%0*d" ), ypad, KiROUND( aCoordY ) ); sprintf( aLine, "X%sY%s\n", TO_UTF8( xs ), TO_UTF8( ys ) ); @@ -337,13 +337,6 @@ void EXCELLON_WRITER::WriteCoordinates( char* aLine, double aCoordX, double aCoo } -/* Print the DRILL file header. The full header is: - * M48 - * ;DRILL file {PCBNEW (2007-11-29-b)} date 17/1/2008-21:02:35 - * ;FORMAT={ / absolute / / } - * FMAT,2 - * INCH,TZ - */ void EXCELLON_WRITER::WriteEXCELLONHeader() { fputs( "M48\n", m_file ); // The beginning of a header @@ -361,13 +354,14 @@ void EXCELLON_WRITER::WriteEXCELLONHeader() msg << m_precision.GetPrecisionString(); else msg << wxT( "-:-" ); // in decimal format the precision is irrelevant + msg << wxT( "/ absolute / " ); msg << ( m_unitsDecimal ? wxT( "metric" ) : wxT( "inch" ) ); /* Adding numbers notation format. * this is same as m_Choice_Zeros_Format strings, but NOT translated - * because some EXCELLON parsers do not like non ascii values - * so we use ONLY english (ascii) strings. + * because some EXCELLON parsers do not like non ASCII values + * so we use ONLY English (ASCII) strings. * if new options are added in m_Choice_Zeros_Format, they must also * be added here */ @@ -432,18 +426,6 @@ static bool CmpHoleDiameterValue( const HOLE_INFO& a, const HOLE_INFO& b ) } -/* - * Create the list of holes and tools for a given board - * The list is sorted by increasing drill values - * Only holes from aFirstLayer to aLastLayer copper layers are listed (for vias, because pad holes are always through holes) - * param aFirstLayer = first layer to consider. if < 0 aFirstLayer is ignored (used to creates report file) - * param aLastLayer = last layer to consider. if < 0 aLastLayer is ignored - * param aExcludeThroughHoles : if true, exclude through holes ( pads and vias through ) - * param aGenerateNPTH_list : - * true to create NPTH only list (with no plated holes) - * false to created plated holes list (with no NPTH ) - * param aMergePTHNPTH : if true, merge PTH and NPTH holes into one file by treating all holes as PTH - */ void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, int aLastLayer, bool aExcludeThroughHoles, @@ -467,8 +449,7 @@ void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, return; } - /* build hole list for vias - */ + // build hole list for vias if( ! aGenerateNPTH_list ) // vias are always plated ! { for( TRACK* track = m_pcb->m_Track; track; track = track->Next() ) @@ -526,15 +507,15 @@ void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, new_hole.m_Hole_NotPlated = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED); new_hole.m_Tool_Reference = -1; // Flag is: Not initialized new_hole.m_Hole_Orient = pad->GetOrientation(); - new_hole.m_Hole_Shape = 0; // hole shape: round - new_hole.m_Hole_Diameter = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y ); + new_hole.m_Hole_Shape = 0; // hole shape: round + new_hole.m_Hole_Diameter = std::min( pad->GetDrillSize().x, pad->GetDrillSize().y ); new_hole.m_Hole_Size.x = new_hole.m_Hole_Size.y = new_hole.m_Hole_Diameter; if( pad->GetDrillShape() != PAD_DRILL_CIRCLE ) new_hole.m_Hole_Shape = 1; // oval flag set - new_hole.m_Hole_Size = pad->GetDrillSize(); - new_hole.m_Hole_Pos = pad->GetPosition(); // hole position + new_hole.m_Hole_Size = pad->GetDrillSize(); + new_hole.m_Hole_Pos = pad->GetPosition(); // hole position new_hole.m_Hole_Bottom_Layer = LAYER_N_BACK; new_hole.m_Hole_Top_Layer = LAYER_N_FRONT;// pad holes are through holes m_holeListBuffer.push_back( new_hole ); @@ -546,7 +527,7 @@ void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, sort( m_holeListBuffer.begin(), m_holeListBuffer.end(), CmpHoleDiameterValue ); // build the tool list - int LastHole = -1; /* Set to not initialised (this is a value not used + int LastHole = -1; /* Set to not initialized (this is a value not used * for m_holeListBuffer[ii].m_Hole_Diameter) */ DRILL_TOOL new_tool( 0 ); unsigned jj; @@ -563,7 +544,7 @@ void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, jj = m_toolListBuffer.size(); if( jj == 0 ) - continue; // Should not occurs + continue; // Should not occurs m_holeListBuffer[ii].m_Tool_Reference = jj; // Tool value Initialized (value >= 1) diff --git a/pcbnew/exporters/gendrill_Excellon_writer.h b/pcbnew/exporters/gendrill_Excellon_writer.h index e62501e80a..d198187711 100644 --- a/pcbnew/exporters/gendrill_Excellon_writer.h +++ b/pcbnew/exporters/gendrill_Excellon_writer.h @@ -60,7 +60,7 @@ public: * So we must generate a drill file for each layer pair (adjacent layers) * Not plated holes are always through holes, and must be output on a specific drill file * because they are drilled after the Pcb process is finished. -*/ + */ class HOLE_INFO { public: @@ -74,6 +74,7 @@ public: LAYER_NUM m_Hole_Top_Layer; // hole ending layer (usually front layer): // m_Hole_First_Layer < m_Hole_Last_Layer bool m_Hole_NotPlated; // hole not plated. Must be in a specific drill file + public: HOLE_INFO() { @@ -88,7 +89,7 @@ class DRILL_PRECISION { public: int m_lhs; // Left digit number (integer value of coordinates) - int m_rhs; // Right digit number (deciam value of coordinates) + int m_rhs; // Right digit number (decimal value of coordinates) public: DRILL_PRECISION( int l = 2, int r = 4 ) { @@ -120,26 +121,28 @@ public: SUPPRESS_TRAILING, KEEP_ZEROS }; - wxPoint m_Offset; // offset coordinates - bool m_ShortHeader; // true to generate the smallest header (strip comments) + + wxPoint m_Offset; // offset coordinates + bool m_ShortHeader; // true to generate the smallest header (strip comments) private: FILE* m_file; // The output file BOARD* m_pcb; - bool m_minimalHeader; // True to use minimal haeder + bool m_minimalHeader; // True to use minimal header // in excellon file (strip comments) bool m_unitsDecimal; // true = decimal, false = inches zeros_fmt m_zeroFormat; // the zero format option for output file - DRILL_PRECISION m_precision; // The current coordinate precision (not used in decimat format) + DRILL_PRECISION m_precision; // The current coordinate precision (not used in decimal format) double m_conversionUnits; // scaling factor to convert the board unites to Excellon units // (i.e inches or mm) bool m_mirror; - wxPoint m_offset; // Drill offset ooordinates + wxPoint m_offset; // Drill offset coordinates bool m_mergePTHNPTH; std::vector m_holeListBuffer; // Buffer containing holes std::vector m_toolListBuffer; // Buffer containing tools -public: EXCELLON_WRITER( BOARD* aPcb, wxPoint aOffset ) +public: + EXCELLON_WRITER( BOARD* aPcb, wxPoint aOffset ) { m_file = NULL; m_pcb = aPcb; @@ -158,7 +161,7 @@ public: EXCELLON_WRITER( BOARD* aPcb, wxPoint aOffset ) /** * Return the plot offset (usually the position - * of the auxiliaty axis + * of the auxiliary axis */ const wxPoint GetOffset() { return m_offset; } @@ -201,17 +204,16 @@ public: EXCELLON_WRITER( BOARD* aPcb, wxPoint aOffset ) * false to created plated holes list (with no NPTH ) */ void BuildHolesList( int aFirstLayer, int aLastLayer, - bool aExcludeThroughHoles, - bool aGenerateNPTH_list, - bool aMergePTHNPTH ); + bool aExcludeThroughHoles, + bool aGenerateNPTH_list, + bool aMergePTHNPTH ); int GetHolesCount() const { return m_holeListBuffer.size(); } /** * Function CreateDrillFile * Creates an Excellon drill file - * @param aFile = an opened file to write to - * will be closed by CreateDrillFile + * @param aFile = an opened file to write to will be closed by CreateDrillFile * @return hole count */ int CreateDrillFile( FILE * aFile ); @@ -222,6 +224,47 @@ public: EXCELLON_WRITER( BOARD* aPcb, wxPoint aOffset ) * for through holes, oblong holes, and for buried vias, * drill values and drill count per layer pair * there is only one report for all drill files even when buried or blinds vias exist + * + * Here is a sample created by this function: + * Drill report for F:/tmp/interf_u/interf_u.brd + * Created on 04/10/2012 20:48:38 + * Selected Drill Unit: Imperial (inches) + * + * Drill report for plated through holes : + * T1 0,025" 0,64mm (88 holes) + * T2 0,031" 0,79mm (120 holes) + * T3 0,032" 0,81mm (151 holes) (with 1 slot) + * T4 0,040" 1,02mm (43 holes) + * T5 0,079" 2,00mm (1 hole) (with 1 slot) + * T6 0,120" 3,05mm (1 hole) (with 1 slot) + * + * Total plated holes count 404 + * + * + * Drill report for buried and blind vias : + * + * Drill report for holes from layer Soudure to layer Interne1 : + * + * Total plated holes count 0 + * + * + * Drill report for holes from layer Interne1 to layer Interne2 : + * T1 0,025" 0,64mm (3 holes) + * + * Total plated holes count 3 + * + * + * Drill report for holes from layer Interne2 to layer Composant : + * T1 0,025" 0,64mm (1 hole) + * + * Total plated holes count 1 + * + * + * Drill report for unplated through holes : + * T1 0,120" 3,05mm (1 hole) (with 1 slot) + * + * Total unplated holes count 1 + * * @param aFullFileName : the name of the file to create * m_unitsDecimal = false tu use inches, true to use mm in report file * @@ -233,16 +276,29 @@ public: EXCELLON_WRITER( BOARD* aPcb, wxPoint aOffset ) * Function GenDrillMapFile * Plot a map of drill marks for holes. * @param aFullFileNameWithoutExt : the full filename of the file to create, - * without extension (will be added accordint ti the format) - * @param aSheet : the paper sheet touse for plot + * without extension (will be added according to the format) + * @param aSheet : the paper sheet to use for plot * @param aFormat : one of the supported plot formats (see enum PlotFormat ) */ bool GenDrillMapFile( const wxString& aFullFileNameWithoutExt, const PAGE_INFO& aSheet, PlotFormat aFormat ); private: + /* Print the DRILL file header. The full header is: + * M48 + * ;DRILL file {PCBNEW (2007-11-29-b)} date 17/1/2008-21:02:35 + * ;FORMAT={ / absolute / / } + * FMAT,2 + * INCH,TZ + */ void WriteEXCELLONHeader(); + void WriteEXCELLONEndOfFile(); + + /* Created a line like: + * X48000Y19500 + * According to the selected format + */ void WriteCoordinates( char* aLine, double aCoordX, double aCoordY ); /** Helper function. @@ -257,6 +313,4 @@ private: }; - - #endif // #ifndef _GENDRILL_EXCELLON_WRITER_ From 04f8d12ae50e3dadebf7576c49447ab81bb15dc4 Mon Sep 17 00:00:00 2001 From: Cirilo Bernardo Date: Thu, 6 Mar 2014 16:44:48 -0500 Subject: [PATCH 02/46] KiCad: improve gerber file extension wildcard so gerbers show up correctly in the file tree pane. --- common/wildcards_and_files_ext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp index 0457830d40..e6a223c708 100644 --- a/common/wildcards_and_files_ext.cpp +++ b/common/wildcards_and_files_ext.cpp @@ -42,7 +42,7 @@ const wxString ProjectFileExtension( wxT( "pro" ) ); const wxString SchematicFileExtension( wxT( "sch" ) ); const wxString NetlistFileExtension( wxT( "net" ) ); const wxString ComponentFileExtension( wxT( "cmp" ) ); -const wxString GerberFileExtension( wxT( "pho" ) ); +const wxString GerberFileExtension( wxT( ".((gbr|(gb|gt)[alops])|pho)" ) ); const wxString LegacyPcbFileExtension( wxT( "brd" ) ); const wxString KiCadPcbFileExtension( wxT( "kicad_pcb" ) ); From c89d52ee1a00ed92bd989eb1fe8f30d349689bf2 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Fri, 7 Mar 2014 17:34:54 -0500 Subject: [PATCH 03/46] Pcbnew: make block rotate honor the rotation angle setting. (fixes lp:1281605) * Make block rotate command honor the rotation angle setting. Thank you Umesh Mohan for the patch. * Change block rotate undo command from UR_ROTATE to UR_CHANGED so consecutive rotations do not lead to round errors and for proper undo in case the user changes the rotation angle setting between block rotations. --- pcbnew/block.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/pcbnew/block.cpp b/pcbnew/block.cpp index bb86e61cfa..d9286c05dc 100644 --- a/pcbnew/block.cpp +++ b/pcbnew/block.cpp @@ -656,8 +656,8 @@ void PCB_EDIT_FRAME::Block_Delete() void PCB_EDIT_FRAME::Block_Rotate() { wxPoint oldpos; - wxPoint centre; // rotation cent-re for the rotation transform - int rotAngle = 900; // rotation angle in 0.1 deg. + wxPoint centre; // rotation cent-re for the rotation transform + int rotAngle = m_rotationAngle; // rotation angle in 0.1 deg. oldpos = GetCrossHairPosition(); centre = GetScreen()->m_BlockLocate.Centre(); @@ -665,14 +665,13 @@ void PCB_EDIT_FRAME::Block_Rotate() OnModify(); PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.GetItems(); - itemsList->m_Status = UR_ROTATED; + itemsList->m_Status = UR_CHANGED; for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ ) { BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii ); wxASSERT( item ); - itemsList->SetPickedItemStatus( UR_ROTATED, ii ); - item->Rotate( centre, rotAngle ); + itemsList->SetPickedItemStatus( UR_CHANGED, ii ); switch( item->Type() ) { @@ -706,7 +705,16 @@ void PCB_EDIT_FRAME::Block_Rotate() } } - SaveCopyInUndoList( *itemsList, UR_ROTATED, centre ); + // Save all the block items in there current state before applying the rotation. + SaveCopyInUndoList( *itemsList, UR_CHANGED, centre ); + + // Now perform the rotation. + for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ ) + { + BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii ); + wxASSERT( item ); + item->Rotate( centre, rotAngle ); + } Compile_Ratsnest( NULL, true ); m_canvas->Refresh( true ); From 63401f3d953e675fa9cd0f2e935ee353a10de364 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 8 Mar 2014 20:04:23 +0100 Subject: [PATCH 04/46] Rework on 3D viewer (work in progress): Disable or enable layers, grid or 3D footprint shapes should be now faster. --- 3d-viewer/3d_canvas.cpp | 27 +- 3d-viewer/3d_canvas.h | 64 +++- 3d-viewer/3d_draw.cpp | 349 ++++++++++++++++++---- 3d-viewer/3d_frame.cpp | 58 ++-- 3d-viewer/3d_toolbar.cpp | 21 +- 3d-viewer/3d_viewer.h | 6 +- 3d-viewer/info3d_visu.h | 1 - include/layers_id_colors_and_visibility.h | 31 +- pcbnew/dialogs/dialog_layers_setup.cpp | 10 +- pcbnew/dialogs/dialog_plot.cpp | 2 +- 10 files changed, 456 insertions(+), 113 deletions(-) diff --git a/3d-viewer/3d_canvas.cpp b/3d-viewer/3d_canvas.cpp index 1764d6faa0..db1ace2851 100644 --- a/3d-viewer/3d_canvas.cpp +++ b/3d-viewer/3d_canvas.cpp @@ -78,7 +78,11 @@ EDA_3D_CANVAS::EDA_3D_CANVAS( EDA_3D_FRAME* parent, int* attribList ) : wxFULL_REPAINT_ON_RESIZE ) { m_init = false; - m_gllist = 0; + + // Clear all gl list identifiers: + for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ ) + m_glLists[ii] = 0; + // Explicitly create a new rendering context instance for this canvas. m_glRC = new wxGLContext( this ); @@ -94,12 +98,25 @@ EDA_3D_CANVAS::~EDA_3D_CANVAS() } -void EDA_3D_CANVAS::ClearLists() +void EDA_3D_CANVAS::ClearLists( GLuint aGlList ) { - if( m_gllist > 0 ) - glDeleteLists( m_gllist, 1 ); + if( aGlList ) + { + if( m_glLists[aGlList] > 0 ) + glDeleteLists( m_glLists[aGlList], 1 ); - m_gllist = 0; + m_glLists[aGlList] = 0; + + return; + } + + for( int ii = GL_ID_BEGIN; ii < GL_ID_END; ii++ ) + { + if( m_glLists[ii] > 0 ) + glDeleteLists( m_glLists[ii], 1 ); + + m_glLists[ii] = 0; + } } diff --git a/3d-viewer/3d_canvas.h b/3d-viewer/3d_canvas.h index cb931c991f..fa84fec602 100644 --- a/3d-viewer/3d_canvas.h +++ b/3d-viewer/3d_canvas.h @@ -50,14 +50,29 @@ class S3D_VERTEX; class SEGVIA; class D_PAD; +// We are using GL lists to store layers and other items +// to draw or not +// GL_LIST_ID are the GL lists indexes in m_glLists +enum GL_LIST_ID +{ + GL_ID_BEGIN = 0, + GL_ID_AXIS = GL_ID_BEGIN, // list id for 3D axis + GL_ID_GRID, // list id for 3D grid + GL_ID_BOARD, // List id for copper layers + GL_ID_TECH_LAYERS, // List id for non copper layers (masks...) + GL_ID_AUX_LAYERS, // List id for user layers (draw, eco, comment) + GL_ID_3DSHAPES_SOLID, // List id for 3D shapes, non transparent entities + GL_ID_3DSHAPES_TRANSP, // List id for 3D shapes, transparent entities + GL_ID_END +}; class EDA_3D_CANVAS : public wxGLCanvas { private: bool m_init; - GLuint m_gllist; + GLuint m_glLists[GL_ID_END]; // GL lists wxGLContext* m_glRC; - wxRealPoint m_draw3dOffset; // offset to draw the 3 mesh. + wxRealPoint m_draw3dOffset; // offset to draw the 3D mesh. double m_ZBottom; // position of the back layer double m_ZTop; // position of the front layer @@ -67,7 +82,15 @@ public: EDA_3D_FRAME* Parent() { return (EDA_3D_FRAME*)GetParent(); } - void ClearLists(); + BOARD* GetBoard() { return Parent()->GetBoard(); } + + /** + * Function ClearLists + * Clear the display list. + * @param aGlList = the list to clear. + * if 0 (default) all lists are cleared + */ + void ClearLists( GLuint aGlList = 0 ); // Event functions: void OnPaint( wxPaintEvent& event ); @@ -92,7 +115,7 @@ public: * Prepares the parameters of the OpenGL draw list * creates the OpenGL draw list items (board, grid ... */ - GLuint CreateDrawGL_List(); + void CreateDrawGL_List(); void InitGL(); void SetLights(); void SetOffset(double aPosX, double aPosY) @@ -104,11 +127,40 @@ public: /** * Function BuildBoard3DView * Called by CreateDrawGL_List() - * Fills the OpenGL draw list with board items draw list. + * Populates the OpenGL GL_ID_BOARD draw list with board items only on copper layers. + * 3D footprint shapes, tech layers and aux layers are not on this list */ void BuildBoard3DView(); - void DrawGrid( double aGriSizeMM ); + /** + * Function BuildTechLayers3DView + * Called by CreateDrawGL_List() + * Populates the OpenGL GL_ID_BOARD draw list with items on tech layers + */ + void BuildTechLayers3DView(); + + /** + * Function BuildFootprintShape3DList + * Called by CreateDrawGL_List() + * Fills the OpenGL GL_ID_3DSHAPES_SOLID and GL_ID_3DSHAPES_TRANSP + * draw lists with 3D footprint shapes + * @param aOpaqueList is the gl list for non transparent items + * @param aTransparentList is the gl list for non transparent items, + * which need to be drawn after all other items + */ + void BuildFootprintShape3DList( GLuint aOpaqueList, + GLuint aTransparentList); + /** + * Function BuildBoard3DAuxLayers + * Called by CreateDrawGL_List() + * Fills the OpenGL GL_ID_AUX_LAYERS draw list + * with items on aux layers only + */ + void BuildBoard3DAuxLayers(); + + void Draw3DGrid( double aGriSizeMM ); + void Draw3DAxis(); + void Draw3DViaHole( SEGVIA * aVia ); void Draw3DPadHole( D_PAD * aPad ); diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index 909d15a4aa..991916294b 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -133,11 +133,45 @@ void EDA_3D_CANVAS::Redraw() glRotatef( g_Parm_3D_Visu.m_Rot[1], 0.0, 1.0, 0.0 ); glRotatef( g_Parm_3D_Visu.m_Rot[2], 0.0, 0.0, 1.0 ); - if( m_gllist ) - glCallList( m_gllist ); - else + if( ! m_glLists[GL_ID_BOARD] || ! m_glLists[GL_ID_TECH_LAYERS] ) CreateDrawGL_List(); + if( g_Parm_3D_Visu.GetFlag( FL_AXIS ) && m_glLists[GL_ID_AXIS] ) + glCallList( m_glLists[GL_ID_AXIS] ); + + // move the board in order to draw it with its center at 0,0 3D coordinates + glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits, + -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits, + 0.0F ); + + + glCallList( m_glLists[GL_ID_BOARD] ); + glCallList( m_glLists[GL_ID_TECH_LAYERS] ); + + if( g_Parm_3D_Visu.GetFlag( FL_COMMENTS ) || g_Parm_3D_Visu.GetFlag( FL_COMMENTS ) ) + { + if( ! m_glLists[GL_ID_AUX_LAYERS] ) + CreateDrawGL_List(); + + glCallList( m_glLists[GL_ID_AUX_LAYERS] ); + } + + if( g_Parm_3D_Visu.GetFlag( FL_GRID ) && m_glLists[GL_ID_GRID] ) + glCallList( m_glLists[GL_ID_GRID] ); + + if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) ) + { + if( ! m_glLists[GL_ID_3DSHAPES_SOLID] ) + CreateDrawGL_List(); + + glCallList( m_glLists[GL_ID_3DSHAPES_SOLID] ); + + // This list must be drawn last, because it contains the + // transparent gl objects, which should be drawn after all + // non tyransparent objects + glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP] ); + } + SwapBuffers(); } @@ -198,8 +232,7 @@ static inline void SetGLTechLayersColor( LAYER_NUM aLayer ) void EDA_3D_CANVAS::BuildBoard3DView() { - PCB_BASE_FRAME* pcbframe = Parent()->Parent(); - BOARD* pcb = pcbframe->GetBoard(); + BOARD* pcb = GetBoard(); bool realistic_mode = g_Parm_3D_Visu.IsRealisticMode(); // Number of segments to draw a circle using segments @@ -456,14 +489,74 @@ void EDA_3D_CANVAS::BuildBoard3DView() Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness/2, board_thickness, g_Parm_3D_Visu.m_BiuTo3Dunits ); } +} + + +void EDA_3D_CANVAS::BuildTechLayers3DView() +{ + BOARD* pcb = GetBoard(); + + // Number of segments to draw a circle using segments + const int segcountforcircle = 16; + double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) ); + const int segcountLowQuality = 12; // segments to draw a circle with low quality + // to reduce time calculations + // for holes and items which do not need + // a fine representation + + CPOLYGONS_LIST bufferPolys; + bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly) + + CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once + allLayerHoles.reserve( 20000 ); + + CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines + // Build a polygon from edge cut items + wxString msg; + if( ! pcb->GetBoardPolygonOutlines( bufferPcbOutlines, + allLayerHoles, &msg ) ) + { + msg << wxT("\n\n") << + _("Unable to calculate the board outlines.\n" + "Therefore use the board boundary box."); + wxMessageBox( msg ); + } + + CPOLYGONS_LIST bufferZonesPolys; + bufferZonesPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly ) + + CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer + + int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU(); + for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() ) + { + // Add via hole + if( track->Type() == PCB_VIA_T ) + { + int shape = track->GetShape(); + int holediameter = track->GetDrillValue(); + int hole_outer_radius = (holediameter + thickness) / 2; + + if( shape == VIA_THROUGH ) + TransformCircleToPolygon( allLayerHoles, + track->GetStart(), hole_outer_radius, + segcountLowQuality ); + } + } + + + // draw graphic items, on technical layers - // draw graphic items, not on copper layers KI_POLYGON_SET brdpolysetHoles; allLayerHoles.ExportTo( brdpolysetHoles ); for( LAYER_NUM layer = FIRST_NON_COPPER_LAYER; layer <= LAST_NON_COPPER_LAYER; layer++ ) { + // Skip user layers, which are not drawn here + if( IsUserLayer( layer) ) + continue; + if( !Is3DLayerEnabled( layer ) ) continue; @@ -481,9 +574,7 @@ void EDA_3D_CANVAS::BuildBoard3DView() { case PCB_LINE_T: ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( - bufferPolys, 0, - segcountforcircle, - correctionFactor ); + bufferPolys, 0, segcountforcircle, correctionFactor ); break; case PCB_TEXT_T: @@ -556,10 +647,8 @@ void EDA_3D_CANVAS::BuildBoard3DView() currLayerPolyset += polyset; } - SetGLTechLayersColor( layer ); int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer ); int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer ); - glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) ); if( layer == EDGE_N ) { @@ -582,38 +671,210 @@ void EDA_3D_CANVAS::BuildBoard3DView() bufferPolys.RemoveAllContours(); bufferPolys.ImportFrom( currLayerPolyset ); + + SetGLTechLayersColor( layer ); + glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) ); Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, thickness, g_Parm_3D_Visu.m_BiuTo3Dunits ); } +} - // draw modules 3D shapes - if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) ) +/** + * Function BuildBoard3DAuxLayers + * Called by CreateDrawGL_List() + * Fills the OpenGL GL_ID_BOARD draw list with items + * on aux layers only + */ +void EDA_3D_CANVAS::BuildBoard3DAuxLayers() +{ + const int segcountforcircle = 16; + double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) ); + BOARD* pcb = GetBoard(); + CPOLYGONS_LIST bufferPolys; + bufferPolys.reserve( 5000 ); // Reserve for items not on board + + for( LAYER_NUM layer = FIRST_USER_LAYER; layer <= LAST_USER_LAYER; + layer++ ) { - for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) - module->ReadAndInsert3DComponentShape( this ); + if( !Is3DLayerEnabled( layer ) ) + continue; + + bufferPolys.RemoveAllContours(); + + for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() ) + { + if( !item->IsOnLayer( layer ) ) + continue; + + switch( item->Type() ) + { + case PCB_LINE_T: + ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( + bufferPolys, 0, segcountforcircle, correctionFactor ); + break; + + case PCB_TEXT_T: + ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( + bufferPolys, 0, segcountforcircle, correctionFactor ); + break; + + default: + break; + } + } + + for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() ) + { + module->TransformPadsShapesWithClearanceToPolygon( layer, + bufferPolys, + 0, + segcountforcircle, + correctionFactor ); + + module->TransformGraphicShapesWithClearanceToPolygonSet( layer, + bufferPolys, + 0, + segcountforcircle, + correctionFactor ); + } + + // bufferPolys contains polygons to merge. Many overlaps . + // Calculate merged polygons and remove pads and vias holes + if( bufferPolys.GetCornersCount() == 0 ) + continue; + KI_POLYGON_SET currLayerPolyset; + KI_POLYGON_SET polyset; + bufferPolys.ExportTo( polyset ); + currLayerPolyset += polyset; + + int thickness = g_Parm_3D_Visu.GetLayerObjectThicknessBIU( layer ); + int zpos = g_Parm_3D_Visu.GetLayerZcoordBIU( layer ); + // for Draw3D_SolidHorizontalPolyPolygons, + // zpos it the middle between bottom and top sides. + // However for top layers, zpos should be the bottom layer pos, + // and for bottom layers, zpos should be the top layer pos. + if( Get3DLayer_Z_Orientation( layer ) > 0 ) + zpos += thickness/2; + else + zpos -= thickness/2 ; + + bufferPolys.RemoveAllContours(); + bufferPolys.ImportFrom( currLayerPolyset ); + + SetGLTechLayersColor( layer ); + glNormal3f( 0.0, 0.0, Get3DLayer_Z_Orientation( layer ) ); + Draw3D_SolidHorizontalPolyPolygons( bufferPolys, zpos, + thickness, g_Parm_3D_Visu.m_BiuTo3Dunits ); } } - -GLuint EDA_3D_CANVAS::CreateDrawGL_List() +void EDA_3D_CANVAS::CreateDrawGL_List() { - PCB_BASE_FRAME* pcbframe = Parent()->Parent(); - BOARD* pcb = pcbframe->GetBoard(); + BOARD* pcb = GetBoard(); wxBusyCursor dummy; - m_gllist = glGenLists( 1 ); - // Build 3D board parameters: g_Parm_3D_Visu.InitSettings( pcb ); - glNewList( m_gllist, GL_COMPILE_AND_EXECUTE ); - glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); - // draw axis - if( g_Parm_3D_Visu.GetFlag( FL_AXIS ) ) + // Create axis gl list (if it is not shown, the list will be not called + Draw3DAxis(); + + // Create grid gl list + if( ! m_glLists[GL_ID_GRID] ) { + m_glLists[GL_ID_GRID] = glGenLists( 1 ); + glNewList( m_glLists[GL_ID_GRID], GL_COMPILE ); + + Draw3DGrid( g_Parm_3D_Visu.m_3D_Grid ); + glEndList(); + } + + // Create Board full gl lists: + +// For testing purpose only, display calculation time to generate 3D data +// #define PRINT_CALCULATION_TIME + +#ifdef PRINT_CALCULATION_TIME + unsigned strtime = GetRunningMicroSecs(); +#endif + + if( ! m_glLists[GL_ID_BOARD] ) + { + m_glLists[GL_ID_BOARD] = glGenLists( 1 ); + glNewList( m_glLists[GL_ID_BOARD], GL_COMPILE ); + BuildBoard3DView(); + glEndList(); + } + + if( ! m_glLists[GL_ID_TECH_LAYERS] ) + { + m_glLists[GL_ID_TECH_LAYERS] = glGenLists( 1 ); + glNewList( m_glLists[GL_ID_TECH_LAYERS], GL_COMPILE ); + BuildTechLayers3DView(); + glEndList(); + } + + if( ! m_glLists[GL_ID_AUX_LAYERS] ) + { + m_glLists[GL_ID_AUX_LAYERS] = glGenLists( 1 ); + glNewList( m_glLists[GL_ID_AUX_LAYERS], GL_COMPILE ); + BuildBoard3DAuxLayers(); + glEndList(); + } + + + // draw modules 3D shapes + if( ! m_glLists[GL_ID_3DSHAPES_SOLID] && g_Parm_3D_Visu.GetFlag( FL_MODULE ) ) + { + m_glLists[GL_ID_3DSHAPES_SOLID] = glGenLists( 1 ); + + // GL_ID_3DSHAPES_TRANSP is an auxiliary list for 3D shapes; + // Ensure it is cleared before rebuilding it + if( m_glLists[GL_ID_3DSHAPES_TRANSP] ) + glDeleteLists( m_glLists[GL_ID_3DSHAPES_TRANSP], 1 ); + + m_glLists[GL_ID_3DSHAPES_TRANSP] = glGenLists( 1 ); + BuildFootprintShape3DList( m_glLists[GL_ID_3DSHAPES_SOLID], + m_glLists[GL_ID_3DSHAPES_TRANSP] ); + } + + // Test for errors + CheckGLError(); + +#ifdef PRINT_CALCULATION_TIME + unsigned endtime = GetRunningMicroSecs(); + wxString msg; + msg.Printf( "Built data %.1f ms", (double) (endtime - strtime) / 1000 ); + Parent()->SetStatusText( msg, 0 ); +#endif +} + +void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, + GLuint aTransparentList) +{ + // aOpaqueList is the gl list for non transparent items + // aTransparentList is the gl list for non transparent items, + // which need to be drawn after all other items + + BOARD* pcb = GetBoard(); + glNewList( m_glLists[GL_ID_3DSHAPES_SOLID], GL_COMPILE ); + + for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) + module->ReadAndInsert3DComponentShape( this ); + + glEndList(); +} + +void EDA_3D_CANVAS::Draw3DAxis() +{ + if( ! m_glLists[GL_ID_AXIS] ) + { + m_glLists[GL_ID_AXIS] = glGenLists( 1 ); + glNewList( m_glLists[GL_ID_AXIS], GL_COMPILE ); + glEnable( GL_COLOR_MATERIAL ); SetGLColor( WHITE ); glBegin( GL_LINES ); @@ -626,46 +887,14 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List() glVertex3f( 0.0f, 0.0f, 0.0f ); glVertex3f( 0.0f, 0.0f, 0.3f ); // Z axis glEnd(); + + glEndList(); } - - // move the board in order to draw it with its center at 0,0 3D coordinates - glTranslatef( -g_Parm_3D_Visu.m_BoardPos.x * g_Parm_3D_Visu.m_BiuTo3Dunits, - -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits, - 0.0F ); - - // Draw Board: -// For testing purpose only, display calculation time to generate 3D data -// #define PRINT_CALCULATION_TIME - -#ifdef PRINT_CALCULATION_TIME - unsigned strtime = GetRunningMicroSecs(); -#endif - - BuildBoard3DView(); - - // Draw grid - if( g_Parm_3D_Visu.GetFlag( FL_GRID ) ) - DrawGrid( g_Parm_3D_Visu.m_3D_Grid ); - - glEndList(); - - // Test for errors - CheckGLError(); - -#ifdef PRINT_CALCULATION_TIME - unsigned endtime = GetRunningMicroSecs(); - wxString msg; - msg.Printf( "Built data %.1f ms", (double) (endtime - strtime) / 1000 ); - Parent()->SetStatusText( msg, 0 ); -#endif - - return m_gllist; } - // draw a 3D grid: an horizontal grid (XY plane and Z = 0, // and a vertical grid (XZ plane and Y = 0) -void EDA_3D_CANVAS::DrawGrid( double aGriSizeMM ) +void EDA_3D_CANVAS::Draw3DGrid( double aGriSizeMM ) { double zpos = 0.0; EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines diff --git a/3d-viewer/3d_frame.cpp b/3d-viewer/3d_frame.cpp index 1b0561bb16..1afa6cb64e 100644 --- a/3d-viewer/3d_frame.cpp +++ b/3d-viewer/3d_frame.cpp @@ -45,6 +45,8 @@ static const wxString keyBgColor_Green( wxT( "BgColor_Green" ) ); static const wxString keyBgColor_Blue( wxT( "BgColor_Blue" ) ); static const wxString keyShowRealisticMode( wxT( "ShowRealisticMode" ) ); static const wxString keyShowAxis( wxT( "ShowAxis" ) ); +static const wxString keyShowGrid( wxT( "ShowGrid3D" ) ); +static const wxString keyShowGridSize( wxT( "Grid3DSize" ) ); static const wxString keyShowZones( wxT( "ShowZones" ) ); static const wxString keyShowFootprints( wxT( "ShowFootprints" ) ); static const wxString keyShowCopperThickness( wxT( "ShowCopperThickness" ) ); @@ -148,9 +150,9 @@ void EDA_3D_FRAME::GetSettings() { EDA_BASE_FRAME::LoadSettings(); - config->Read( keyBgColor_Red, &g_Parm_3D_Visu.m_BgColor.m_Red, 0.0 ); - config->Read( keyBgColor_Green, &g_Parm_3D_Visu.m_BgColor.m_Green, 0.0 ); - config->Read( keyBgColor_Blue, &g_Parm_3D_Visu.m_BgColor.m_Blue, 0.0 ); + config->Read( keyBgColor_Red, &prms.m_BgColor.m_Red, 0.0 ); + config->Read( keyBgColor_Green, &prms.m_BgColor.m_Green, 0.0 ); + config->Read( keyBgColor_Blue, &prms.m_BgColor.m_Blue, 0.0 ); bool tmp; config->Read( keyShowRealisticMode, &tmp, false ); @@ -159,6 +161,12 @@ void EDA_3D_FRAME::GetSettings() config->Read( keyShowAxis, &tmp, true ); prms.SetFlag( FL_AXIS, tmp ); + config->Read( keyShowGrid, &tmp, true ); + prms.SetFlag( FL_GRID, tmp ); + + config->Read( keyShowGridSize, &prms.m_3D_Grid, 10.0 ); + prms.SetFlag( FL_MODULE, tmp ); + config->Read( keyShowFootprints, &tmp, true ); prms.SetFlag( FL_MODULE, tmp ); @@ -201,12 +209,14 @@ void EDA_3D_FRAME::SaveSettings() EDA_BASE_FRAME::SaveSettings(); - config->Write( keyBgColor_Red, g_Parm_3D_Visu.m_BgColor.m_Red ); - config->Write( keyBgColor_Green, g_Parm_3D_Visu.m_BgColor.m_Green ); - config->Write( keyBgColor_Blue, g_Parm_3D_Visu.m_BgColor.m_Blue ); class INFO3D_VISU& prms = g_Parm_3D_Visu; + config->Write( keyBgColor_Red, prms.m_BgColor.m_Red ); + config->Write( keyBgColor_Green, prms.m_BgColor.m_Green ); + config->Write( keyBgColor_Blue, prms.m_BgColor.m_Blue ); config->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) ); config->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) ); + config->Write( keyShowGrid, prms.GetFlag( FL_GRID ) ); + config->Write( keyShowGridSize, prms.m_3D_Grid ); config->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) ); config->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) ); config->Write( keyShowZones, prms.GetFlag( FL_ZONE ) ); @@ -364,52 +374,52 @@ void EDA_3D_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_MENU3D_AXIS_ONOFF: g_Parm_3D_Visu.SetFlag( FL_AXIS, isChecked ); - NewDisplay(); + m_canvas->Refresh(); return; case ID_MENU3D_MODULE_ONOFF: g_Parm_3D_Visu.SetFlag( FL_MODULE, isChecked ); - NewDisplay(); + m_canvas->Refresh(); return; case ID_MENU3D_USE_COPPER_THICKNESS: g_Parm_3D_Visu.SetFlag( FL_USE_COPPER_THICKNESS, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_BOARD); return; case ID_MENU3D_ZONE_ONOFF: g_Parm_3D_Visu.SetFlag( FL_ZONE, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_BOARD); return; case ID_MENU3D_ADHESIVE_ONOFF: g_Parm_3D_Visu.SetFlag( FL_ADHESIVE, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_TECH_LAYERS); return; case ID_MENU3D_SILKSCREEN_ONOFF: g_Parm_3D_Visu.SetFlag( FL_SILKSCREEN, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_TECH_LAYERS); return; case ID_MENU3D_SOLDER_MASK_ONOFF: g_Parm_3D_Visu.SetFlag( FL_SOLDERMASK, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_TECH_LAYERS); return; case ID_MENU3D_SOLDER_PASTE_ONOFF: g_Parm_3D_Visu.SetFlag( FL_SOLDERPASTE, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_TECH_LAYERS); return; case ID_MENU3D_COMMENTS_ONOFF: g_Parm_3D_Visu.SetFlag( FL_COMMENTS, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_AUX_LAYERS); return; case ID_MENU3D_ECO_ONOFF: g_Parm_3D_Visu.SetFlag( FL_ECO, isChecked ); - NewDisplay(); + NewDisplay(GL_ID_AUX_LAYERS); return; default: @@ -434,7 +444,6 @@ void EDA_3D_FRAME::On3DGridSelection( wxCommandEvent& event ) GetMenuBar()->Check( ii, false ); } - switch( id ) { case ID_MENU3D_GRID_NOGRID: @@ -466,18 +475,17 @@ void EDA_3D_FRAME::On3DGridSelection( wxCommandEvent& event ) return; } - NewDisplay(); + NewDisplay( GL_ID_GRID ); } -void EDA_3D_FRAME::NewDisplay() +void EDA_3D_FRAME::NewDisplay( GLuint aGlList ) { m_reloadRequest = false; - m_canvas->ClearLists(); + m_canvas->ClearLists( aGlList ); m_canvas->CreateDrawGL_List(); -// m_canvas->InitGL(); m_canvas->Refresh( true ); m_canvas->DisplayStatus(); } @@ -507,6 +515,9 @@ void EDA_3D_FRAME::Set3DBgColor() newcolor = wxGetColourFromUser( this, oldcolor ); + if( ! newcolor.IsOk() ) // Happens on cancel dialog + return; + if( newcolor != oldcolor ) { g_Parm_3D_Visu.m_BgColor.m_Red = (double) newcolor.Red() / 255.0; @@ -515,3 +526,8 @@ void EDA_3D_FRAME::Set3DBgColor() NewDisplay(); } } + +BOARD* EDA_3D_FRAME::GetBoard() +{ + return Parent()->GetBoard(); +} diff --git a/3d-viewer/3d_toolbar.cpp b/3d-viewer/3d_toolbar.cpp index ed0e3eefbe..a1c7d2c90a 100644 --- a/3d-viewer/3d_toolbar.cpp +++ b/3d-viewer/3d_toolbar.cpp @@ -166,13 +166,22 @@ void EDA_3D_FRAME::CreateMenuBar() wxMenu * gridlistMenu = new wxMenu; AddMenuItem( prefsMenu, gridlistMenu, ID_MENU3D_GRID, _( "3D Grid" ), KiBitmap( grid_xpm ) ); - gridlistMenu->Append( ID_MENU3D_GRID_NOGRID, _( "No 3D Grid" ), wxEmptyString, true ); - gridlistMenu->Check( ID_MENU3D_GRID_NOGRID, true ); + gridlistMenu->Append( ID_MENU3D_GRID_NOGRID, _( "No 3D Grid" ), wxEmptyString, true ); + gridlistMenu->Append( ID_MENU3D_GRID_10_MM, _( "3D Grid 10 mm" ), wxEmptyString, true ); + gridlistMenu->Append( ID_MENU3D_GRID_5_MM, _( "3D Grid 5 mm" ), wxEmptyString, true ); + gridlistMenu->Append( ID_MENU3D_GRID_2P5_MM, _( "3D Grid 2.5 mm" ), wxEmptyString, true ); + gridlistMenu->Append( ID_MENU3D_GRID_1_MM, _( "3D Grid 1 mm" ), wxEmptyString, true ); - gridlistMenu->Append( ID_MENU3D_GRID_10_MM, _( "3D Grid 10 mm" ), wxEmptyString, true ); - gridlistMenu->Append( ID_MENU3D_GRID_5_MM, _( "3D Grid 5 mm" ), wxEmptyString, true ); - gridlistMenu->Append( ID_MENU3D_GRID_2P5_MM, _( "3D Grid 2.5 mm" ), wxEmptyString, true ); - gridlistMenu->Append( ID_MENU3D_GRID_1_MM, _( "3D Grid 1 mm" ), wxEmptyString, true ); + // If the grid is on, check the corresponding menuitem showing the grid size + if( g_Parm_3D_Visu.GetFlag( FL_GRID ) ) + { + gridlistMenu->Check( ID_MENU3D_GRID_10_MM, g_Parm_3D_Visu.m_3D_Grid == 10.0 ); + gridlistMenu->Check( ID_MENU3D_GRID_5_MM, g_Parm_3D_Visu.m_3D_Grid == 5.0 ); + gridlistMenu->Check( ID_MENU3D_GRID_2P5_MM, g_Parm_3D_Visu.m_3D_Grid == 2.5 ); + gridlistMenu->Check( ID_MENU3D_GRID_1_MM, g_Parm_3D_Visu.m_3D_Grid == 1.0 ); + } + else + gridlistMenu->Check( ID_MENU3D_GRID_NOGRID, true ); prefsMenu->AppendSeparator(); diff --git a/3d-viewer/3d_viewer.h b/3d-viewer/3d_viewer.h index dc94f933ef..a1645c1e81 100644 --- a/3d-viewer/3d_viewer.h +++ b/3d-viewer/3d_viewer.h @@ -78,6 +78,8 @@ public: PCB_BASE_FRAME* Parent() { return (PCB_BASE_FRAME*)GetParent(); } + BOARD* GetBoard(); + /** * Function ReloadRequest * must be called when reloading data from Pcbnew is needed @@ -93,8 +95,10 @@ public: * Function NewDisplay * Rebuild the display list. * must be called when 3D opengl data is modified + * @param aGlList = the list to rebuild. + * if 0 (default) all lists are rebuilt */ - void NewDisplay(); + void NewDisplay( GLuint aGlList = 0 ); void SetDefaultFileName(const wxString &aFn) { m_defaultFileName = aFn; } const wxString &GetDefaultFileName() const { return m_defaultFileName; } diff --git a/3d-viewer/info3d_visu.h b/3d-viewer/info3d_visu.h index 00acbbd226..7c7fe02918 100644 --- a/3d-viewer/info3d_visu.h +++ b/3d-viewer/info3d_visu.h @@ -74,7 +74,6 @@ enum DISPLAY3D_FLG { FL_LAST }; - class INFO3D_VISU { public: diff --git a/include/layers_id_colors_and_visibility.h b/include/layers_id_colors_and_visibility.h index 5df67215be..2137c5a1f0 100644 --- a/include/layers_id_colors_and_visibility.h +++ b/include/layers_id_colors_and_visibility.h @@ -63,6 +63,8 @@ typedef int LAYER_NUM; #define NB_COPPER_LAYERS (LAST_COPPER_LAYER - FIRST_COPPER_LAYER + 1) #define FIRST_NON_COPPER_LAYER 16 +#define FIRST_TECHNICAL_LAYER 16 +#define FIRST_USER_LAYER 24 #define ADHESIVE_N_BACK 16 #define ADHESIVE_N_FRONT 17 #define SOLDERPASTE_N_BACK 18 @@ -77,6 +79,8 @@ typedef int LAYER_NUM; #define ECO2_N 27 #define EDGE_N 28 #define LAST_NON_COPPER_LAYER 28 +#define LAST_TECHNICAL_LAYER 23 +#define LAST_USER_LAYER 27 #define NB_PCB_LAYERS (LAST_NON_COPPER_LAYER + 1) #define UNUSED_LAYER_29 29 #define UNUSED_LAYER_30 30 @@ -128,13 +132,16 @@ typedef unsigned LAYER_MSK; #define ALL_CU_LAYERS 0x0000FFFF #define INTERNAL_CU_LAYERS 0x00007FFE #define EXTERNAL_CU_LAYERS 0x00008001 -#define FRONT_AUX_LAYERS (SILKSCREEN_LAYER_FRONT | SOLDERMASK_LAYER_FRONT \ +#define FRONT_TECH_LAYERS (SILKSCREEN_LAYER_FRONT | SOLDERMASK_LAYER_FRONT \ | ADHESIVE_LAYER_FRONT | SOLDERPASTE_LAYER_FRONT) -#define BACK_AUX_LAYERS (SILKSCREEN_LAYER_BACK | SOLDERMASK_LAYER_BACK \ +#define BACK_TECH_LAYERS (SILKSCREEN_LAYER_BACK | SOLDERMASK_LAYER_BACK \ | ADHESIVE_LAYER_BACK | SOLDERPASTE_LAYER_BACK) -#define ALL_AUX_LAYERS (FRONT_AUX_LAYERS | BACK_AUX_LAYERS) -#define BACK_LAYERS (LAYER_BACK | BACK_AUX_LAYERS) -#define FRONT_LAYERS (LAYER_FRONT | FRONT_AUX_LAYERS) +#define ALL_TECH_LAYERS (FRONT_TECH_LAYERS | BACK_TECH_LAYERS) +#define BACK_LAYERS (LAYER_BACK | BACK_TECH_LAYERS) +#define FRONT_LAYERS (LAYER_FRONT | FRONT_TECH_LAYERS) + +#define ALL_USER_LAYERS (DRAW_LAYER | COMMENT_LAYER |\ + ECO1_LAYER | ECO2_LAYER ) #define NO_LAYERS 0x00000000 @@ -329,8 +336,18 @@ inline bool IsCopperLayer( LAYER_NUM aLayer ) */ inline bool IsNonCopperLayer( LAYER_NUM aLayer ) { - return aLayer >= FIRST_NON_COPPER_LAYER - && aLayer <= LAST_NON_COPPER_LAYER; + return aLayer >= FIRST_NON_COPPER_LAYER && aLayer <= LAST_NON_COPPER_LAYER; +} + +/** + * Function IsUserLayer + * tests whether a layer is a non copper and a non tech layer + * @param aLayer = Layer to test + * @return true if aLayer is a user layer + */ +inline bool IsUserLayer( LAYER_NUM aLayer ) +{ + return aLayer >= FIRST_USER_LAYER && aLayer <= LAST_USER_LAYER; } /* IMPORTANT: If a layer is not a front layer not necessarily is true diff --git a/pcbnew/dialogs/dialog_layers_setup.cpp b/pcbnew/dialogs/dialog_layers_setup.cpp index fc26fe399e..82b76e6c63 100644 --- a/pcbnew/dialogs/dialog_layers_setup.cpp +++ b/pcbnew/dialogs/dialog_layers_setup.cpp @@ -176,19 +176,19 @@ static const LAYER_MSK presets[] = NO_LAYERS, // shift the array index up by one, matches with "Custom". // "Two layers, parts on Front only" - EDGE_LAYER | LAYER_FRONT | LAYER_BACK | FRONT_AUX_LAYERS, + EDGE_LAYER | LAYER_FRONT | LAYER_BACK | FRONT_TECH_LAYERS, // "Two layers, parts on Back only", - EDGE_LAYER | LAYER_FRONT | LAYER_BACK | BACK_AUX_LAYERS, + EDGE_LAYER | LAYER_FRONT | LAYER_BACK | BACK_TECH_LAYERS, // "Two layers, parts on Front and Back", - EDGE_LAYER | LAYER_FRONT | LAYER_BACK | ALL_AUX_LAYERS, + EDGE_LAYER | LAYER_FRONT | LAYER_BACK | ALL_TECH_LAYERS, // "Four layers, parts on Front only" - EDGE_LAYER | LAYER_FRONT | LAYER_BACK | LAYER_2 | LAYER_3 | FRONT_AUX_LAYERS, + EDGE_LAYER | LAYER_FRONT | LAYER_BACK | LAYER_2 | LAYER_3 | FRONT_TECH_LAYERS, // "Four layers, parts on Front and Back" - EDGE_LAYER | LAYER_FRONT | LAYER_BACK | LAYER_2 | LAYER_3 | ALL_AUX_LAYERS, + EDGE_LAYER | LAYER_FRONT | LAYER_BACK | LAYER_2 | LAYER_3 | ALL_TECH_LAYERS, // "All layers on", ALL_LAYERS, diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index bc13af8558..4da92e068d 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -246,7 +246,7 @@ void DIALOG_PLOT::OnPopUpLayers( wxCommandEvent& event ) for( i = 0; i < m_layerList.size(); i++ ) { LAYER_MSK layermask = GetLayerMask( m_layerList[ i ] ); - if( layermask & ( ALL_CU_LAYERS | ALL_AUX_LAYERS ) ) + if( layermask & ( ALL_CU_LAYERS | ALL_TECH_LAYERS ) ) m_layerCheckListBox->Check( i, true ); else m_layerCheckListBox->Check( i, false ); From f24bc87a842648b562f45081604f0edf972acaff Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 8 Mar 2014 20:07:35 +0100 Subject: [PATCH 05/46] Pcbnew: fix Bug #1289416 (Broken setting of layer list in D_PAD:: ViewGetLayers() for GAL). --- pcbnew/class_pad.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index d024290e74..405c398db0 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -842,29 +842,40 @@ void D_PAD::ViewGetLayers( int aLayers[], int& aCount ) const // Multi layer pad aLayers[aCount++] = ITEM_GAL_LAYER( PADS_VISIBLE ); aLayers[aCount++] = NETNAMES_GAL_LAYER( PADS_NETNAMES_VISIBLE ); - aLayers[aCount++] = SOLDERMASK_N_FRONT; - aLayers[aCount++] = SOLDERMASK_N_BACK; - aLayers[aCount++] = SOLDERPASTE_N_FRONT; - aLayers[aCount++] = SOLDERPASTE_N_BACK; } else if( IsOnLayer( LAYER_N_FRONT ) ) { aLayers[aCount++] = ITEM_GAL_LAYER( PAD_FR_VISIBLE ); aLayers[aCount++] = NETNAMES_GAL_LAYER( PAD_FR_NETNAMES_VISIBLE ); - aLayers[aCount++] = SOLDERMASK_N_FRONT; - aLayers[aCount++] = SOLDERPASTE_N_FRONT; } else if( IsOnLayer( LAYER_N_BACK ) ) { aLayers[aCount++] = ITEM_GAL_LAYER( PAD_BK_VISIBLE ); aLayers[aCount++] = NETNAMES_GAL_LAYER( PAD_BK_NETNAMES_VISIBLE ); - aLayers[aCount++] = SOLDERMASK_N_BACK; - aLayers[aCount++] = SOLDERPASTE_N_BACK; } + + if( IsOnLayer( SOLDERMASK_N_FRONT ) ) + aLayers[aCount++] = SOLDERMASK_N_FRONT; + + if( IsOnLayer( SOLDERMASK_N_BACK ) ) + aLayers[aCount++] = SOLDERMASK_N_BACK; + + if( IsOnLayer( SOLDERPASTE_N_FRONT ) ) + aLayers[aCount++] = SOLDERPASTE_N_FRONT; + + if( IsOnLayer( SOLDERPASTE_N_BACK ) ) + aLayers[aCount++] = SOLDERPASTE_N_BACK; + + if( IsOnLayer( ADHESIVE_N_BACK ) ) + aLayers[aCount++] = ADHESIVE_N_BACK; + + if( IsOnLayer( ADHESIVE_N_FRONT ) ) + aLayers[aCount++] = ADHESIVE_N_FRONT; + #ifdef __WXDEBUG__ - else // Should not occur + if( aCount == 0 ) // Should not occur { - wxLogWarning( wxT("D_PAD::ViewGetLayers():PAD on layer different than FRONT/BACK") ); + wxLogWarning( wxT("D_PAD::ViewGetLayers():PAD has no layer") ); } #endif } From 4fd3dbb5a5ca160198b9eab12450bca8c33e7c39 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sun, 9 Mar 2014 19:43:53 +0100 Subject: [PATCH 06/46] Finishing work on a better 3D viewer. this also fix bugs like Bug #1129630 . --- 3d-viewer/3d_aux.cpp | 49 ++------------------------ 3d-viewer/3d_canvas.h | 1 - 3d-viewer/3d_class.cpp | 22 +++++++++++- 3d-viewer/3d_draw.cpp | 50 +++++++++++++++++++-------- 3d-viewer/3d_draw_basic_functions.cpp | 4 +-- 3d-viewer/3d_struct.h | 43 ++++++++++++++++++++++- 3d-viewer/modelparsers.h | 2 +- 3d-viewer/vrmlmodelparser.cpp | 8 +++-- 3d-viewer/x3dmodelparser.cpp | 7 ++-- pcbnew/class_module.h | 8 ++++- 10 files changed, 122 insertions(+), 72 deletions(-) diff --git a/3d-viewer/3d_aux.cpp b/3d-viewer/3d_aux.cpp index 0878053869..a8ccab2b8d 100644 --- a/3d-viewer/3d_aux.cpp +++ b/3d-viewer/3d_aux.cpp @@ -45,16 +45,11 @@ #include #include -// Exported function: -void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits ); - -void S3D_MASTER::Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices ) +void S3D_MASTER::ObjectCoordsTo3DUnits( std::vector< S3D_VERTEX >& aVertices ) { - unsigned ii; - /* adjust object scale, rotation and offset position */ - for( ii = 0; ii < aVertices.size(); ii++ ) + for( unsigned ii = 0; ii < aVertices.size(); ii++ ) { aVertices[ii].x *= m_MatScale.x; aVertices[ii].y *= m_MatScale.y; @@ -79,7 +74,7 @@ void S3D_MASTER::Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices ) } -void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits ) +void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits ) { unsigned ii; GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r; @@ -138,44 +133,6 @@ void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits glEnd(); } - -GLuint EDA_3D_CANVAS::DisplayCubeforTest() -{ - GLuint gllist = glGenLists( 1 ); - - glNewList( gllist, GL_COMPILE_AND_EXECUTE ); - /* draw six faces of a cube */ - glBegin( GL_QUADS ); - glNormal3f( 0.0F, 0.0F, 1.0F ); - glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( -0.5F, 0.5F, 0.5F ); - glVertex3f( -0.5F, -0.5F, 0.5F ); glVertex3f( 0.5F, -0.5F, 0.5F ); - - glNormal3f( 0.0F, 0.0F, -1.0F ); - glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( -0.5F, 0.5F, -0.5F ); - glVertex3f( 0.5F, 0.5F, -0.5F ); glVertex3f( 0.5F, -0.5F, -0.5F ); - - glNormal3f( 0.0F, 1.0F, 0.0F ); - glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( 0.5F, 0.5F, -0.5F ); - glVertex3f( -0.5F, 0.5F, -0.5F ); glVertex3f( -0.5F, 0.5F, 0.5F ); - - glNormal3f( 0.0F, -1.0F, 0.0F ); - glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( 0.5F, -0.5F, -0.5F ); - glVertex3f( 0.5F, -0.5F, 0.5F ); glVertex3f( -0.5F, -0.5F, 0.5F ); - - glNormal3f( 1.0F, 0.0F, 0.0F ); - glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( 0.5F, -0.5F, 0.5F ); - glVertex3f( 0.5F, -0.5F, -0.5F ); glVertex3f( 0.5F, 0.5F, -0.5F ); - - glNormal3f( -1.0F, 0.0F, 0.0F ); - glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( -0.5F, -0.5F, 0.5F ); - glVertex3f( -0.5F, 0.5F, 0.5F ); glVertex3f( -0.5F, 0.5F, -0.5F ); - glEnd(); - - glEndList(); - - return gllist; -} - VERTEX_VALUE_CTRL::VERTEX_VALUE_CTRL( wxWindow* aParent, wxBoxSizer* aBoxSizer ) { wxString text; diff --git a/3d-viewer/3d_canvas.h b/3d-viewer/3d_canvas.h index fa84fec602..43a1f7ed85 100644 --- a/3d-viewer/3d_canvas.h +++ b/3d-viewer/3d_canvas.h @@ -104,7 +104,6 @@ public: void OnEnterWindow( wxMouseEvent& event ); // Display functions - GLuint DisplayCubeforTest(); // Just a test function void SetView3D( int keycode ); void DisplayStatus(); void Redraw(); diff --git a/3d-viewer/3d_class.cpp b/3d-viewer/3d_class.cpp index 79ea755b2f..b364d23e5b 100644 --- a/3d-viewer/3d_class.cpp +++ b/3d-viewer/3d_class.cpp @@ -41,9 +41,14 @@ S3D_MATERIAL::S3D_MATERIAL( S3D_MASTER* father, const wxString& name ) : m_Name = name; } - void S3D_MATERIAL::SetMaterial() { + S3D_MASTER * s3dParent = (S3D_MASTER *) GetParent(); + s3dParent->SetLastTransparency( m_Transparency ); + + if( ! s3dParent->IsOpenGlAllowed() ) + return; + glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); glColor4f( m_DiffuseColor.x * m_AmbientIntensity, m_DiffuseColor.y * m_AmbientIntensity, @@ -56,6 +61,20 @@ void S3D_MATERIAL::SetMaterial() #endif } +bool S3D_MASTER::IsOpenGlAllowed() +{ + if( m_loadNonTransparentObjects ) // return true for non transparent objects only + { + if( m_lastTransparency == 0.0 ) + return true; + } + if( m_loadTransparentObjects ) // return true for transparent objects only + if( m_lastTransparency != 0.0 ) + return true; + + return false; +} + void S3D_MASTER::Insert( S3D_MATERIAL* aMaterial ) { @@ -79,6 +98,7 @@ S3D_MASTER::S3D_MASTER( EDA_ITEM* aParent ) : EDA_ITEM( aParent, NOT_USED ) { m_MatScale.x = m_MatScale.y = m_MatScale.z = 1.0; + m_lastTransparency = 0.0; m_3D_Drawings = NULL; m_Materials = NULL; m_ShapeType = FILE3D_NONE; diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index 991916294b..dffd7e17cc 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -356,7 +356,7 @@ void EDA_3D_CANVAS::BuildBoard3DView() } } - // draw graphic items + // draw graphic items on copper layers (texts) for( BOARD_ITEM* item = pcb->m_Drawings; item; item = item->Next() ) { if( !item->IsOnLayer( layer ) ) @@ -364,11 +364,9 @@ void EDA_3D_CANVAS::BuildBoard3DView() switch( item->Type() ) { - case PCB_LINE_T: + case PCB_LINE_T: // should not exist on copper layers ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( - bufferPolys, 0, - segcountforcircle, - correctionFactor ); + bufferPolys, 0, segcountforcircle, correctionFactor ); break; case PCB_TEXT_T: @@ -505,8 +503,7 @@ void EDA_3D_CANVAS::BuildTechLayers3DView() // a fine representation CPOLYGONS_LIST bufferPolys; - bufferPolys.reserve( 200000 ); // Reserve for large board (tracks mainly) - + bufferPolys.reserve( 100000 ); // Reserve for large board CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once allLayerHoles.reserve( 20000 ); @@ -522,11 +519,6 @@ void EDA_3D_CANVAS::BuildTechLayers3DView() wxMessageBox( msg ); } - CPOLYGONS_LIST bufferZonesPolys; - bufferZonesPolys.reserve( 500000 ); // Reserve for large board ( copper zones mainly ) - - CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer - int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU(); for( TRACK* track = pcb->m_Track; track != NULL; track = track->Next() ) { @@ -544,6 +536,16 @@ void EDA_3D_CANVAS::BuildTechLayers3DView() } } + // draw pads holes + for( MODULE* module = pcb->m_Modules; module != NULL; module = module->Next() ) + { + // Add pad hole, if any + D_PAD* pad = module->Pads(); + + for( ; pad != NULL; pad = pad->Next() ) + pad->BuildPadDrillShapePolygon( allLayerHoles, 0, + segcountLowQuality ); + } // draw graphic items, on technical layers @@ -852,6 +854,7 @@ void EDA_3D_CANVAS::CreateDrawGL_List() #endif } + void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, GLuint aTransparentList) { @@ -860,10 +863,21 @@ void EDA_3D_CANVAS::BuildFootprintShape3DList( GLuint aOpaqueList, // which need to be drawn after all other items BOARD* pcb = GetBoard(); - glNewList( m_glLists[GL_ID_3DSHAPES_SOLID], GL_COMPILE ); + glNewList( aOpaqueList, GL_COMPILE ); + bool loadTransparentObjects = false; for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) - module->ReadAndInsert3DComponentShape( this ); + module->ReadAndInsert3DComponentShape( this, !loadTransparentObjects, + loadTransparentObjects ); + + glEndList(); + + glNewList( aTransparentList, GL_COMPILE ); + loadTransparentObjects = true; + + for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) + module->ReadAndInsert3DComponentShape( this, !loadTransparentObjects, + loadTransparentObjects ); glEndList(); } @@ -1055,8 +1069,11 @@ void EDA_3D_CANVAS::Draw3DViaHole( SEGVIA* aVia ) } -void MODULE::ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas ) +void MODULE::ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas, + bool aAllowNonTransparentObjects, + bool aAllowTransparentObjects ) { + // Read from disk and draws the footprint 3D shapes if exists S3D_MASTER* shape3D = m_3D_Drawings; double zpos = g_Parm_3D_Visu.GetModulesZcoord3DIU( IsFlipped() ); @@ -1078,6 +1095,9 @@ void MODULE::ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas ) for( ; shape3D != NULL; shape3D = shape3D->Next() ) { + shape3D->SetLoadNonTransparentObjects( aAllowNonTransparentObjects ); + shape3D->SetLoadTransparentObjects( aAllowTransparentObjects ); + if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) shape3D->ReadData(); } diff --git a/3d-viewer/3d_draw_basic_functions.cpp b/3d-viewer/3d_draw_basic_functions.cpp index ef49a3e4bb..81654c4af7 100644 --- a/3d-viewer/3d_draw_basic_functions.cpp +++ b/3d-viewer/3d_draw_basic_functions.cpp @@ -35,7 +35,7 @@ #include <3d_draw_basic_functions.h> // Imported function: -extern void Set_Object_Data( std::vector& aVertices, double aBiuTo3DUnits ); +extern void TransfertToGLlist( std::vector& aVertices, double aBiuTo3DUnits ); extern void CheckGLError(); // Number of segments to approximate a circle by segments @@ -116,7 +116,7 @@ static void Draw3D_VerticalPolygonalCylinder( const CPOLYGONS_LIST& aPolysList, coords[3].y = coords[2].y; // only z change // Creates the GL_QUAD - Set_Object_Data( coords, aBiuTo3DUnits ); + TransfertToGLlist( coords, aBiuTo3DUnits ); } } diff --git a/3d-viewer/3d_struct.h b/3d-viewer/3d_struct.h index 56a083f8c9..2a82effd93 100644 --- a/3d-viewer/3d_struct.h +++ b/3d-viewer/3d_struct.h @@ -109,6 +109,10 @@ public: private: wxString m_Shape3DName; /* 3D shape name in 3D library */ FILE3D_TYPE m_ShapeType; + double m_lastTransparency; // last transparency value from + // last material in use + bool m_loadTransparentObjects; + bool m_loadNonTransparentObjects; public: S3D_MASTER( EDA_ITEM* aParent ); @@ -117,11 +121,41 @@ public: S3D_MASTER* Next() const { return (S3D_MASTER*) Pnext; } S3D_MASTER* Back() const { return (S3D_MASTER*) Pback; } + // Accessors + void SetLastTransparency( double aValue ) { m_lastTransparency = aValue; } + + void SetLoadTransparentObjects( bool aLoad ) + { m_loadTransparentObjects = aLoad; } + + void SetLoadNonTransparentObjects( bool aLoad ) + { m_loadNonTransparentObjects = aLoad; } + void Insert( S3D_MATERIAL* aMaterial ); + /** + * Function IsOpenGlAllowed + * @return true if opengl current list accepts a gl data + * used to filter transparent objects, which are drawn after + * non transparent objects + */ + bool IsOpenGlAllowed(); + void Copy( S3D_MASTER* pattern ); + + /** + * Function ReadData + * Select the parser to read the 3D data file (vrml, x3d ...) + * and build the description objects list + */ int ReadData(); - void Set_Object_Coords( std::vector< S3D_VERTEX >& aVertices ); + + /** + * Function ObjectCoordsTo3DUnits + * @param aVertices = a list of 3D coordinates in shape units + * to convert to 3D canvas units, according to the + * footprint 3Dshape rotation, offset and scale parameters + */ + void ObjectCoordsTo3DUnits( std::vector< S3D_VERTEX >& aVertices ); #if defined(DEBUG) void Show( int nestLevel, std::ostream& os ) const { ShowDummy( os ); } // override @@ -147,6 +181,13 @@ public: */ const wxString GetShape3DFullFilename(); + /** + * Function SetShape3DName + * @param aShapeName = file name of the data file relative to the 3D shape + * + * Set the filename of the 3D shape, and depending on the file extention + * (vrl, x3d, idf ) the type of file. + */ void SetShape3DName( const wxString& aShapeName ); }; diff --git a/3d-viewer/modelparsers.h b/3d-viewer/modelparsers.h index 147a0fda16..d1c5f23461 100644 --- a/3d-viewer/modelparsers.h +++ b/3d-viewer/modelparsers.h @@ -37,7 +37,7 @@ class S3D_MASTER; class S3D_VERTEX; -extern void Set_Object_Data( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits ); +extern void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUnits ); class S3D_MODEL_PARSER; class X3D_MODEL_PARSER; diff --git a/3d-viewer/vrmlmodelparser.cpp b/3d-viewer/vrmlmodelparser.cpp index fa6367793b..8891a424aa 100644 --- a/3d-viewer/vrmlmodelparser.cpp +++ b/3d-viewer/vrmlmodelparser.cpp @@ -519,8 +519,12 @@ int VRML_MODEL_PARSER::readGeometry( FILE* file, int* LineNum ) vertices.push_back( vertex ); } - GetMaster()->Set_Object_Coords( vertices ); - Set_Object_Data( vertices, vrmlunits_to_3Dunits ); + if( GetMaster()->IsOpenGlAllowed() ) + { + GetMaster()->ObjectCoordsTo3DUnits( vertices ); + TransfertToGLlist( vertices, vrmlunits_to_3Dunits ); + } + vertices.clear(); coordIndex.clear(); } diff --git a/3d-viewer/x3dmodelparser.cpp b/3d-viewer/x3dmodelparser.cpp index 012d3df959..e4f7d283b2 100644 --- a/3d-viewer/x3dmodelparser.cpp +++ b/3d-viewer/x3dmodelparser.cpp @@ -479,8 +479,11 @@ void X3D_MODEL_PARSER::readIndexedFaceSet( wxXmlNode* aFaceNode, vertices.push_back( triplets.at( *id ) ); } - GetMaster()->Set_Object_Coords( vertices ); - Set_Object_Data( vertices, vrmlunits_to_3Dunits ); + if( GetMaster()->IsOpenGlAllowed() ) + { + GetMaster()->ObjectCoordsTo3DUnits( vertices ); + TransfertToGLlist( vertices, vrmlunits_to_3Dunits ); + } vertices.clear(); coordIndex.clear(); diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 184e9e7288..34a8c11788 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -250,8 +250,14 @@ public: * function ReadandInsert3DComponentShape * read the 3D component shape(s) of the footprint (physical shape) * and insert mesh in gl list + * @param glcanvas = the openGL canvas + * @param aAllowNonTransparentObjects = true to load non transparent objects + * @param aAllowTransparentObjects = true to load non transparent objects + * in openGL, transparent objects should be drawn *after* non transparent objects */ - void ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas ); + void ReadAndInsert3DComponentShape( EDA_3D_CANVAS* glcanvas, + bool aAllowNonTransparentObjects, + bool aAllowTransparentObjects ); /** * function TransformPadsShapesWithClearanceToPolygon From 5feddb8cac1440c419e52372b123de4981767e6d Mon Sep 17 00:00:00 2001 From: Marco Serantoni Date: Mon, 10 Mar 2014 23:37:59 +0100 Subject: [PATCH 07/46] [MacOSX] fixes some interations with KicadOSXBuilder --- pcbnew/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 03986fd836..87455ff48e 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -661,9 +661,11 @@ if( KICAD_SCRIPTING_MODULES ) COMMENT "Copying wxPython into pcbnew.app Frameworks" ) - # Tell that we have to run osx_fix_bundles fix after building _pcbnew and migrating wxPython - add_dependencies( osx_fix_bundles pcbnew_copy_wxpython_module ) - add_dependencies( osx_fix_bundles _pcbnew ) + if( KICAD_BUILD_DYNAMIC ) + # Tell that we have to run osx_fix_bundles fix after building _pcbnew and migrating wxPython + add_dependencies( osx_fix_bundles pcbnew_copy_wxpython_module ) + add_dependencies( osx_fix_bundles _pcbnew ) + endif() endif() endif() From 55f9aaabd7ff5215b32a91c9175677a6b9512627 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 12 Mar 2014 14:58:49 +0100 Subject: [PATCH 08/46] Workarounded SWIG problems (does not support nested C++ classes, more on the subject: http://www.swig.org/Doc1.3/SWIGPlus.html#SWIGPlus_nested_classes). --- pcbnew/class_board.h | 2 ++ pcbnew/class_netinfo.h | 15 ++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index cac0f66ffd..92058d0af6 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -871,6 +871,7 @@ public: m_NetInfo.AppendNet( aNewNet ); } +#ifndef SWIG /** * Function BeginNets * @return iterator to the first element of the NETINFO_ITEMs list @@ -888,6 +889,7 @@ public: { return m_NetInfo.end(); } +#endif /** * Function GetNetCount diff --git a/pcbnew/class_netinfo.h b/pcbnew/class_netinfo.h index f566926fcc..64e6e9f8b8 100644 --- a/pcbnew/class_netinfo.h +++ b/pcbnew/class_netinfo.h @@ -145,6 +145,7 @@ public: */ int Translate( int aNetCode ) const; +#ifndef SWIG ///> Wrapper class, so you can iterate through NETINFO_ITEM*s, not ///> std::pair class iterator @@ -212,6 +213,7 @@ public: { return iterator( m_netMapping.end(), this ); } +#endif /** * Function GetSize @@ -329,6 +331,7 @@ public: typedef boost::unordered_map NETNAMES_MAP; typedef boost::unordered_map NETCODES_MAP; +#ifndef SWIG ///> Wrapper class, so you can iterate through NETINFO_ITEM*s, not ///> std::pair class iterator @@ -388,6 +391,7 @@ public: { return iterator( m_netNames.end() ); } +#endif private: /** @@ -438,25 +442,22 @@ class NETINFO_ITEM friend class NETINFO_LIST; private: - const int m_NetCode; ///< A number equivalent to the net name. + int m_NetCode; ///< A number equivalent to the net name. ///< Used for fast comparisons in ratsnest and DRC computations. - const wxString m_Netname; ///< Full net name like /mysheet/mysubsheet/vout - ///< used by Eeschema + wxString m_Netname; ///< Full net name like /mysheet/mysubsheet/vout used by Eeschema - const wxString m_ShortNetname; // short net name, like vout from - // /mysheet/mysubsheet/vout + wxString m_ShortNetname; ///< short net name, like vout from /mysheet/mysubsheet/vout wxString m_NetClassName; // Net Class name. if void this is equivalent // to "default" (the first // item of the net classes list - NETCLASS* m_NetClass; BOARD_ITEM* m_parent; ///< The parent board item object the net belongs to. public: - std::vector m_PadInNetList; // List of pads connected to this net + std::vector m_PadInNetList; ///< List of pads connected to this net unsigned m_RatsnestStartIdx; /* Starting point of ratsnests of this * net (included) in a general buffer of From c7e3887ba47d2c0b9b863e5631e58d0a59ba160f Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 12 Mar 2014 15:00:14 +0100 Subject: [PATCH 09/46] Fixed erroneous hit testing for polygons in ratsnest for GAL. --- pcbnew/ratsnest_data.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 6b9d2b043a..2845e04475 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -356,8 +356,8 @@ bool RN_POLY::HitTest( const RN_NODE_PTR& aNode ) const x2 = xOld; y2 = yOld; } - if( ( xNew < xt ) == ( xt <= xOld ) /* edge "open" at left end */ - && ( yt - y1 ) * ( x2 - x1 ) < ( y2 - y1 ) * ( xt - x1 ) ) + if( ( xNew < xt ) == ( xt <= xOld ) && /* edge "open" at left end */ + (float)( yt - y1 ) * (float)( x2 - x1 ) < (float)( y2 - y1 ) * (float)( xt - x1 ) ) { inside = !inside; } From 52791f2375223ab54c9a278ee5d9aa1cfa0019a2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Wed, 12 Mar 2014 22:42:08 +0100 Subject: [PATCH 10/46] Changed cast from float to double in RN_POLY::HitTest. --- pcbnew/ratsnest_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 2845e04475..97f04e29b0 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -357,7 +357,7 @@ bool RN_POLY::HitTest( const RN_NODE_PTR& aNode ) const } if( ( xNew < xt ) == ( xt <= xOld ) && /* edge "open" at left end */ - (float)( yt - y1 ) * (float)( x2 - x1 ) < (float)( y2 - y1 ) * (float)( xt - x1 ) ) + (double)( yt - y1 ) * (double)( x2 - x1 ) < (double)( y2 - y1 ) * (double)( xt - x1 ) ) { inside = !inside; } From d00fae588a3f8ece309e110623ecf1edf4103c98 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Thu, 13 Mar 2014 08:15:19 +0100 Subject: [PATCH 11/46] Footprint Editor: fix a crash when the dialog to set pad properties is called from the main toolbar (i.e. to define the default setting for new pads, and not to edit an existing pad) --- pcbnew/dialogs/dialog_pad_properties.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 42f75d220c..37d10da7e5 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -149,10 +149,10 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP { m_canUpdate = false; m_parent = aParent; - m_currentPad = aPad; + m_currentPad = aPad; // aPad can be NULL, if the dialog is calleg + // from the modoule editor to set default pad characteristics m_board = m_parent->GetBoard(); - m_dummyPad = new D_PAD( aPad->GetParent() ); - m_padMaster.SetParent( aPad->GetParent() ); + m_dummyPad = new D_PAD( (MODULE*) NULL ); if( aPad ) m_dummyPad->Copy( aPad ); From e76c330aaffd73b53ae9a136bc9d98b34b6f5beb Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Thu, 13 Mar 2014 18:50:52 +0100 Subject: [PATCH 12/46] Fixes build error with the choosy CLANG (Thanks to Maciej Suminski) --- include/ttl/ttl.h | 11 +- include/ttl/ttl_constr.h | 635 --------------------------------------- 2 files changed, 1 insertion(+), 645 deletions(-) delete mode 100644 include/ttl/ttl_constr.h diff --git a/include/ttl/ttl.h b/include/ttl/ttl.h index 7d7c655843..7de2e7b08d 100644 --- a/include/ttl/ttl.h +++ b/include/ttl/ttl.h @@ -357,7 +357,7 @@ private: ForwardIterator it; for (it = first; it != last; ++it) { - bool status = insertNode(dart, **it); + insertNode(dart, **it); } } @@ -1914,13 +1914,4 @@ passes: }; // End of ttl namespace scope (but other files may also contain functions for ttl) - - //------------------------------------------------------------------------------------------------ - // ----------------------------- Constrained Triangulation Group -------------------------------- - //------------------------------------------------------------------------------------------------ - - // Still namespace ttl - -#include - #endif // _TTL_H_ diff --git a/include/ttl/ttl_constr.h b/include/ttl/ttl_constr.h deleted file mode 100644 index 125bddeb23..0000000000 --- a/include/ttl/ttl_constr.h +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT, - * Applied Mathematics, Norway. - * - * Contact information: E-mail: tor.dokken@sintef.no - * SINTEF ICT, Department of Applied Mathematics, - * P.O. Box 124 Blindern, - * 0314 Oslo, Norway. - * - * This file is part of TTL. - * - * TTL is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * TTL 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with TTL. If not, see - * . - * - * In accordance with Section 7(b) of the GNU Affero General Public - * License, a covered work must retain the producer line in every data - * file that is created or manipulated using TTL. - * - * Other Usage - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial activities involving the TTL library without - * disclosing the source code of your own applications. - * - * This file may be used in accordance with the terms contained in a - * written agreement between you and SINTEF ICT. - */ - -#ifndef _TTL_CONSTR_H_ -#define _TTL_CONSTR_H_ - - -#include -#include - - -// Debugging -#ifdef DEBUG_TTL_CONSTR_PLOT - #include - static ofstream ofile_constr("qweCons.dat"); -#endif - -/** \brief Constrained Delaunay triangulation -* -* Basic generic algorithms in TTL for inserting a constrained edge between two existing nodes.\n -* -* See documentation for the namespace ttl for general requirements and assumptions. -* -* \author -* �yvind Hjelle, oyvindhj@ifi.uio.no -*/ - -namespace ttl_constr { - - // ??? A constant used to evluate a numerical expression against a user spesified - // roundoff-zero number -#ifdef DEBUG_TTL_CONSTR - static const double ROUNDOFFZERO = 0.0; // 0.1e-15; -#endif - - -class ConstrainedTriangulation -{ - public: - //------------------------------------------------------------------------------------------------ - /* Checks if \e dart has start and end points in \e dstart and \e dend. - * - * \param dart - * The dart that should be controlled to see if it's the constraint - * - * \param dstart - * A CCW dart with the startnode of the constraint as the startnode - * - * \param dend - * A CCW dart with the endnode of the constraint as the startnode - * - * \retval bool - * A bool confirming that it's the constraint or not - * - * \using - * same_0_orbit - */ - template - static bool isTheConstraint(const DartType& dart, const DartType& dstart, const DartType& dend) { - DartType d0 = dart; - d0.alpha0(); // CW - if ((ttl::TriangulationHelper::same_0_orbit(dstart, dart) && ttl::TriangulationHelper::same_0_orbit(dend, d0)) || - (ttl::TriangulationHelper::same_0_orbit(dstart, d0) && ttl::TriangulationHelper::same_0_orbit(dend, dart))) { - return true; - } - return false; - } - - - //------------------------------------------------------------------------------------------------ - /* Checks if \e d1 and \e d2 are on the same side of the line between \e dstart and \e dend. - * (The start nodes of \e d1 and \e d2 represent an edge). - * - * \param dstart - * A CCW dart with the start node of the constraint as the source node of the dart. - * - * \param dend - * A CCW dart with the end node of the constraint as the source node of the dart. - * - * \param d1 - * A CCW dart with the first node as the start node of the dart. - * - * \param d2 - * A CCW dart with the other node as the start node of the dart. - * - * \using - * TraitsType::orient2d - */ - template - static bool crossesConstraint(DartType& dstart, DartType& dend, DartType& d1, DartType& d2) { - - typename TraitsType::real_type orient_1 = TraitsType::orient2d(dstart,d1,dend); - typename TraitsType::real_type orient_2 = TraitsType::orient2d(dstart,d2,dend); - // ??? Should we refine this? e.g. find if (dstart,dend) (d1,d2) represent the same edge - if ((orient_1 <= 0 && orient_2 <= 0) || (orient_1 >= 0 && orient_2 >= 0)) - return false; - - return true; - } - - - //------------------------------------------------------------------------------------------------ - /* Return the dart \e d making the smallest non-negative angle, - * as calculated with: orient2d(dstart, d.alpha0(), dend), - * at the 0-orbit of dstart. - * If (dstart,dend) is a CCW boundary edge \e d will be CW, otherwise CCW (since CCW in) - * at the 0-orbit of dstart. - * - * \par Assumes: - * - CCW dstart and dend, but returned dart can be CW at the boundary. - * - Boundary is convex? - * - * \param dstart - * A CCW dart dstart - * - * \param dend - * A CCW dart dend - * - * \retval DartType - * The dart \e d making the smallest positive (or == 0) angle - * - * \using - * isBoundaryNode - * positionAtNextBoundaryEdge - * TraitsType::orient2d - */ - template - static DartType getAtSmallestAngle(const DartType& dstart, const DartType& dend) { - - // - Must boundary be convex??? - // - Handle the case where the constraint is already present??? - // - Handle dstart and/or dend at the boundary - // (dstart and dend may define a boundary edge) - - DartType d_iter = dstart; - if (ttl::TriangulationHelper::isBoundaryNode(d_iter)) { - d_iter.alpha1(); // CW - ttl::TriangulationHelper::positionAtNextBoundaryEdge(d_iter); // CCW (was rotated CW to the boundary) - } - - // assume convex boundary; see comments - - DartType d0 = d_iter; - d0.alpha0(); - bool ccw = true; // the rotation later - typename TraitsType::real_type o_iter = TraitsType::orient2d(d_iter, d0, dend); - if (o_iter == 0) { // collinear BUT can be on "back side" - d0.alpha1().alpha0(); // CW - if (TraitsType::orient2d(dstart, dend, d0) > 0) - return d_iter; //(=dstart) collinear - else { - // collinear on "back side" - d_iter.alpha1().alpha2(); // assume convex boundary - ccw = true; - } - } - else if (o_iter < 0) { - // Prepare for rotating CW and with d_iter CW - d_iter.alpha1(); - ccw = false; - } - - // Set first angle - d0 = d_iter; d0.alpha0(); - o_iter = TraitsType::orient2d(dstart, d0, dend); - - typename TraitsType::real_type o_next; - - // Rotate towards the constraint CCW or CW. - // Here we assume that the boundary is convex. - DartType d_next = d_iter; - for (;;) { - d_next.alpha1(); // CW !!! (if ccw == true) - d0 = d_next; d0.alpha0(); - o_next = TraitsType::orient2d(dstart, d0, dend); - - if (ccw && o_next < 0) // and o_iter > 0 - return d_iter; - else if (!ccw && o_next > 0) - return d_next; // CCW - else if (o_next == 0) { - if (ccw) - return d_next.alpha2(); // also ok if boundary - else - return d_next; - } - - // prepare next - d_next.alpha2(); // CCW if ccw - d_iter = d_next; // also ok if boundary CCW if ccw == true - } - } - - - //------------------------------------------------------------------------------------------------ - /* This function finds all the edges in the triangulation crossing - * the spesified constraint and puts them in a list. - * In the case of collinearity, an attempt is made to detect this. - * The first collinear node between dstart and dend is then returned. - * - * Strategy: - * - Iterate such that \e d_iter is always strictly "below" the constraint - * as seen with \e dstart to the left and \e dend to the right. - * - Add CCW darts, whose edges intersect the constrait, to a list. - * These edges are found by the orient2d predicate: - * If two nodes of an edge are on opposite sides of the constraint, - * the edge between them intersect. - * - Must handle collinnear cases, i.e., if a node falls on the constraint, - * and possibly restarting collection of edges. Detecting collinearity - * heavily relies on the orient2d predicate which is provided by the - * traits class. - * - * Action: - * 1) Find cone/opening angle containing \e dstart and \e dend - * 2) Find first edge from the first 0-orbit that intersects - * 3) Check which of the two opposite that intersects - * - * 1) - * Rotate CCW and find the (only) case where \e d_iter and \e d_next satisfy: - * - orient2d(d_iter, d_iter.alpha0(), dend) > 0 - * - orient2d(d_next, d_next.alpha0(), dend) < 0 - * - * - check if we are done, i.e., if (d_next.alpha0() == my_dend) - * - Note also the situation if, e.g., the constraint is a boundary edge in which case - * \e my_dend wil be CW - * - * \param dstart - * A CCW dart with the startnode of the constraint as the startnode - * - * \param dend - * A CCW dart with the endnode of the constraint as the startnode - * - * \param elist - * A list where all the edges crossing the spesified constraint will be put - * - * \retval dartType - * Returns the next "collinear" starting node such that dend is returned when done. - */ - template - static DartType findCrossingEdges(const DartType& dstart, const DartType& dend, ListType& elist) { - - const DartType my_start = getAtSmallestAngle(dstart, dend); - DartType my_end = getAtSmallestAngle(dend, dstart); - - DartType d_iter = my_start; - if (d_iter.alpha0().alpha2() == my_end) - return d_iter; // The constraint is an existing edge and we are done - - // Facts/status so far: - // - my_start and my_end are now both CCW and the constraint is not a boundary edge. - // - Further, the constraint is not one single existing edge, but it might be a collection - // of collinear edges in which case we return the current collinear edge - // and calling this function until all are collected. - - my_end.alpha1(); // CW! // ??? this is probably ok for testing now? - - d_iter = my_start; - d_iter.alpha0().alpha1(); // alpha0 is downwards or along the constraint - - // Facts: - // - d_iter is guaranteed to intersect, but can be in start point. - // - d_iter.alpha0() is not at dend yet - typename TraitsType::real_type orient = TraitsType::orient2d(dstart, d_iter, dend); - - // Use round-off error/tolerance or rely on the orient2d predicate ??? - // Make a warning message if orient != exact 0 - if (orient == 0) - return d_iter; - -#ifdef DEBUG_TTL_CONSTR - else if (fabs(orient) <= ROUNDOFFZERO) { - cout << "The darts are not exactly colinear, but |d1 x d2| <= " << ROUNDOFFZERO << endl; - return d_iter; // collinear, not done (and not collect in the list) - } -#endif - - // Collect intersecting edges - // -------------------------- - elist.push_back(d_iter); // The first with interior intersection point - - // Facts, status so far: - // - The first intersecting edge is now collected - // (- d_iter.alpha0() is still not at dend) - - // d_iter should always be the edge that intersects and be below or on the constraint - // One of the two edges opposite to d_iter must intersect, or we have collinearity - - // Note: Almost collinear cases can be handled on the - // application side with orient2d. We should probably - // return an int and the application will set it to zero - for(;;) { - // assume orient have been calc. and collinearity has been tested, - // above the first time and below later - d_iter.alpha2().alpha1(); // 2a same node - - DartType d0 = d_iter; - d0.alpha0(); // CW - if (d0 == my_end) - return dend; // WE ARE DONE (but can we enter an endless loop???) - - // d_iter or d_iter.alpha0().alpha1() must intersect - orient = TraitsType::orient2d(dstart, d0, dend); - - if (orient == 0) - return d0.alpha1(); - -#ifdef DEBUG_TTL_CONSTR - else if (fabs(orient) <= ROUNDOFFZERO) { - return d0.alpha1(); // CCW, collinear - } -#endif - - else if (orient > 0) { // orient > 0 and still below - // This one must intersect! - d_iter = d0.alpha1(); - } - elist.push_back(d_iter); - } - } - - - //------------------------------------------------------------------------------------------------ - /* This function recives a constrained edge and a list of all the edges crossing a constraint. - * It then swaps the crossing edges away from the constraint. This is done according to a - * scheme suggested by Dyn, Goren & Rippa (slightly modified). - * The resulting triangulation is a constrained one, but not necessarily constrained Delaunay. - * In other to run optimization later to obtain a constrained Delaunay triangulation, - * the swapped edges are maintained in a list. - * - * Strategy : - * - Situation A: Run through the list and swap crossing edges away from the constraint. - * All the swapped edges are moved to the end of the list, and are "invisible" to this procedure. - * - Situation B: We may come in a situation where none of the crossing edges can be swapped away - * from the constraint. - * Then we follow the strategy of Dyn, Goren & Rippa and allow edges to be swapped, - * even if they are not swapped away from the constraint. - * These edges are NOT moved to the end of the list. They are later swapped to none-crossing - * edges when the locked situation is solved. - * - We keep on swapping edges in Situation B until we have iterated trough the list. - * We then resume Situation A. - * - This is done until the list is virtualy empty. The resulting \c elist has the constraint - * as the last element. - * - * \param dstart - * A CCW dart dstart - * - * \param dend - * A CCW dart dend - * - * \param elist - * A list containing all the edges crossing the spesified constraint - * - * \using - * swappableEdge - * swapEdgeInList - * crossesConstraint - * isTheConstraint - */ - template - void transformToConstraint(ttl::TriangulationHelper helper, DartType& dstart, DartType& dend, - std::list& elist) const { - - typename std::list::iterator it, used; - - // We may enter in a situation where dstart and dend are altered because of a swap. - // (The general rule is that darts inside the actual quadrilateral can be changed, - // but not those outside.) - // So, we need some look-ahead strategies for dstart and dend and change these - // after a swap if necessary. - - int dartsInList = (int)elist.size(); - if (dartsInList == 0) - return; - - bool erase; // indicates if an edge is swapped away from the constraint such that it can be - // moved to the back of the list - bool locked = false; - do { - int noswap = 0; - it = elist.begin(); - - // counts how many edges that have been swapped per list-cycle - int counter = 1; - while(it != elist.end()) { // ??? change this test with counter > dartsInList - erase = false; - // Check if our virtual end of the list has been crossed. It breaks the - // while and starts all over again in the do-while loop - if (counter > dartsInList) - break; - - if (ttl::TriangulationHelper::swappableEdge(*it, true)) { - // Dyn & Goren & Rippa 's notation: - // The node assosiated with dart *it is denoted u_m. u_m has edges crossing the constraint - // named w_1, ... , w_r . The other node to the edge assosiated with dart *it is w_s. - // We want to swap from edge u_m<->w_s to edge w_{s-1}<->w_{s+1}. - DartType op1 = *it; - DartType op2 = op1; - op1.alpha1().alpha0(); //finds dart with node w_{s-1} - op2.alpha2().alpha1().alpha0(); // (CW) finds dart with node w_{s+1} - DartType tmp = *it; tmp.alpha0(); // Dart with assosiated node opposite to node of *it allong edge - // If there is a locked situation we swap, even if the result is crossing the constraint - // If there is a looked situation, but we do an ordinary swap, it should be treated as - // if we were not in a locked situation!! - - // The flag swap_away indicates if the edge is swapped away from the constraint such that - // it does not cross the constraint. - bool swap_away = (crossesConstraint(dstart, dend, *it, tmp) && - !crossesConstraint(dstart, dend, op1, op2)); - if (swap_away || locked) { - // Do a look-ahead to see if dstart and/or dend are in the quadrilateral - // If so, we mark it with a flag to make sure we update them after the swap - // (they may have been changed during the swap according to the general rule!) - bool start = false; - bool end = false; - - DartType d = *it; - if (d.alpha1().alpha0() == dstart) - start = true; - d = *it; - if (d.alpha2().alpha1().alpha0().alpha1() == dend) - end = true; - - // This is the only place swapping is called when inserting a constraint - helper.swapEdgeInList(it,elist); - - // If we, during look-ahead, found that dstart and/or dend were in the quadrilateral, - // we update them. - if (end) - dend = *it; - if (start) { - dstart = *it; - dstart.alpha0().alpha2(); - } - - if (swap_away) { // !locked || //it should be sufficient with swap_away ??? - noswap++; - erase = true; - } - - if (isTheConstraint(*it, dstart, dend)) { - // Move the constraint to the end of the list - DartType the_constraint = *it; - elist.erase(it); - elist.push_back(the_constraint); - return; - } //endif - } //endif - } //endif "swappable edge" - - - // Move the edge to the end of the list if it was swapped away from the constraint - if (erase) { - used = it; - elist.push_back(*it); - ++it; - elist.erase(used); - --dartsInList; - } - else { - ++it; - ++counter; - } - - } //end while - - if (noswap == 0) - locked = true; - - } while (dartsInList != 0); - - -#ifdef DEBUG_TTL_CONSTR - // We will never enter here. (If elist is empty, we return above). - cout << "??????? ERROR 2, should never enter here ????????????????????????? SKIP ???? " << endl; - exit(-1); -#endif - - } - -}; // End of ConstrainedTriangulation class - -}; // End of ttl_constr namespace scope - - -namespace ttl { // (extension) - - /** @name Constrained (Delaunay) Triangulation */ - //@{ - - //------------------------------------------------------------------------------------------------ - /** Inserts a constrained edge between two existing nodes in a triangulation. - * If the constraint falls on one or more existing nodes and this is detected by the - * predicate \c TraitsType::orient2d, which should return zero in this case, the - * constraint is split. Otherwise a degenerate triangle will be made along - * the constraint. - * - * \param dstart - * A CCW dart with the start node of the constraint as the source node - * - * \param dend - * A CCW dart with the end node of the constraint as the source node - * - * \param optimize_delaunay - * If set to \c true, the resulting triangulation will be - * a \e constrained \e Delaunay \e triangulation. If set to \c false, the resulting - * triangulation will not necessarily be of constrained Delaunay type. - * - * \retval DartType - * A dart representing the constrained edge. - * - * \require - * - \ref hed::TTLtraits::orient2d "TraitsType::orient2d" (DartType&, DartType&, PointType&) - * - \ref hed::TTLtraits::swapEdge "TraitsType::swapEdge" (DartType&) - * - * \using - * - optimizeDelaunay if \e optimize_delaunay is set to \c true - * - * \par Assumes: - * - The constrained edge must be inside the existing triangulation (and it cannot - * cross the boundary of the triangulation). - */ - template - DartType TriangulationHelper::insertConstraint(DartType& dstart, DartType& dend, bool optimize_delaunay) { - - // Assumes: - // - It is the users responsibility to avoid crossing constraints - // - The constraint cannot cross the boundary, i.e., the boundary must be - // convex in the area of crossing edges. - // - dtart and dend are preserved (same node associated.) - - - // Find edges crossing the constraint and put them in elist. - // If findCrossingEdges reaches a Node lying on the constraint, this function - // calls itself recursively. - - // RECURSION - std::list elist; - DartType next_start = ttl_constr::ConstrainedTriangulation::findCrossingEdges(dstart, dend, elist); - - // If there are no crossing edges (elist is empty), we assume that the constraint - // is an existing edge. - // In this case, findCrossingEdges returns the constraint. - // Put the constraint in the list to fit with the procedures below - // (elist can also be empty in the case of invalid input data (the constraint is in - // a non-convex area) but this is the users responsibility.) - - //by Thomas Sevaldrud if (elist.size() == 0) - //by Thomas Sevaldrud elist.push_back(next_start); - - // findCrossingEdges stops if it finds a node lying on the constraint. - // A dart with this node as start node is returned - // We call insertConstraint recursivly until the received dart is dend - if (!same_0_orbit(next_start, dend)) { - -#ifdef DEBUG_TTL_CONSTR_PLOT - cout << "RECURSION due to collinearity along constraint" << endl; -#endif - - insertConstraint(next_start, dend, optimize_delaunay); - } - - // Swap edges such that the constraint edge is present in the transformed triangulation. - if (elist.size() > 0) // by Thomas Sevaldrud - ttl_constr::ConstrainedTriangulation::transformToConstraint(dstart, next_start, elist); - -#ifdef DEBUG_TTL_CONSTR_PLOT - cout << "size of elist = " << elist.size() << endl; - if (elist.size() > 0) { - DartType the_constraint = elist.back(); - ofile_constr << the_constraint.x() << " " << the_constraint.y() << " " << 0 << endl; - the_constraint.alpha0(); - ofile_constr << the_constraint.x() << " " << the_constraint.y() << " " << 0 << endl << endl; - } -#endif - - // Optimize to constrained Delaunay triangulation if required. - typename std::list::iterator end_opt = elist.end(); - if (optimize_delaunay) { - - // Indicate that the constrained edge, which is the last element in the list, - // should not be swapped - --end_opt; - optimizeDelaunay(elist, end_opt); - } - - if(elist.size() == 0) // by Thomas Sevaldrud - return next_start; // by Thomas Sevaldrud - - // Return the constraint, which is still the last element in the list - end_opt = elist.end(); - --end_opt; - return *end_opt; - } - - //@} // End of Constrained Triangulation Group - -}; // End of ttl namespace scope (extension) - -#endif // _TTL_CONSTR_H_ From ec5a767542627a99125b13a88a7bbad6cb3c3716 Mon Sep 17 00:00:00 2001 From: Marco Serantoni Date: Fri, 14 Mar 2014 00:44:46 +0100 Subject: [PATCH 13/46] [MacOSX] New OSX enviroment seems to be more picky about options, this fixes the linker part --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a923759cf..f75978e6ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,9 +199,10 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) if( NOT APPLE ) set( CMAKE_SHARED_LINKER_FLAGS "${TO_LINKER},--no-undefined" ) set( CMAKE_MODULE_LINKER_FLAGS "${TO_LINKER},--no-undefined" ) + + set( CMAKE_EXE_LINKER_FLAGS_RELEASE "-s" ) endif() - set( CMAKE_EXE_LINKER_FLAGS_RELEASE "-s" ) endif() # quiet GCC while in boost @@ -215,7 +216,7 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__ASSERTMACROS__ -mmacosx-version-min=10.5" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__ASSERTMACROS__ -mmacosx-version-min=10.5" ) - # Allows .dylib relocation in the future + # Allows .dylib relocation in the future - needed by fixbundle set( CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -headerpad_max_install_names") if( NOT CMAKE_CXX_COMPILER ) From dcea11e5cb34560abac57d4c814ef0a91ca89755 Mon Sep 17 00:00:00 2001 From: Marco Serantoni Date: Fri, 14 Mar 2014 02:07:44 +0100 Subject: [PATCH 14/46] [MacOSX] New OSX build enviroment now supported --- CMakeModules/download_wxpython.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeModules/download_wxpython.cmake b/CMakeModules/download_wxpython.cmake index 4e1a71f688..112a8de5ff 100644 --- a/CMakeModules/download_wxpython.cmake +++ b/CMakeModules/download_wxpython.cmake @@ -46,6 +46,10 @@ if (APPLE) STRING(REGEX REPLACE " -arch " "," LIBWXPYTHON_ARCHITECTURES ${CMAKE_OSX_ARCHITECTURES}) SET( LIBWXPYTHON_OPTS ${LIBWXPYTHON_OPTS} --mac_arch=${LIBWXPYTHON_ARCHITECTURES}) endif( CMAKE_OSX_ARCHITECTURES ) + + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) + SET( LIBWXPYTHON_PRECMD export CFLAGS=-Qunused-arguments && ) + endif() endif(APPLE) if ( KICAD_BUILD_STATIC ) @@ -74,7 +78,7 @@ ExternalProject_Add( libwxpython UPDATE_COMMAND ${CMAKE_COMMAND} -E remove_directory "${LIBWXPYTHON_ROOT}" COMMAND ${LIBWXPYTHON_EXEC} wxPython/build-wxpython.py --clean - CONFIGURE_COMMAND ${LIBWXPYTHON_EXEC} wxPython/build-wxpython.py --prefix=${LIBWXPYTHON_ROOT} --unicode --install ${LIBWXPYTHON_OPTS} + CONFIGURE_COMMAND ${LIBWXPYTHON_PRECMD} ${LIBWXPYTHON_EXEC} wxPython/build-wxpython.py --prefix=${LIBWXPYTHON_ROOT} --unicode --install ${LIBWXPYTHON_OPTS} #BINARY_DIR "${PREFIX}" From bc707ced5812a9bb69966429bab98308bd0f526b Mon Sep 17 00:00:00 2001 From: Marco Serantoni Date: Fri, 14 Mar 2014 02:10:27 +0100 Subject: [PATCH 15/46] [MacOSX] Pcbnew crash on editing dimension's line width --- pcbnew/dimension.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pcbnew/dimension.cpp b/pcbnew/dimension.cpp index 819c1a3110..fee6c85304 100644 --- a/pcbnew/dimension.cpp +++ b/pcbnew/dimension.cpp @@ -160,10 +160,12 @@ void DIALOG_DIMENSION_EDITOR::OnCancelClick( wxCommandEvent& event ) void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) { +#ifndef USE_WX_OVERLAY if( m_DC ) // Delete old text. { CurrentDimension->Draw( m_Parent->GetCanvas(), m_DC, GR_XOR ); } +#endif m_Parent->SaveCopyInUndoList(CurrentDimension, UR_CHANGED); @@ -207,12 +209,14 @@ void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) CurrentDimension->Text().SetMirrored( ( m_rbMirror->GetSelection() == 1 ) ? true : false ); CurrentDimension->SetLayer( m_SelLayerBox->GetLayerSelection() ); - +#ifndef USE_WX_OVERLAY if( m_DC ) // Display new text { CurrentDimension->Draw( m_Parent->GetCanvas(), m_DC, GR_OR ); } - +#else + m_Parent->Refresh(); +#endif m_Parent->OnModify(); EndModal( 1 ); } From ab27f56cc72695dfbd30999c7f57c2b10d158942 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Fri, 14 Mar 2014 08:37:04 +0100 Subject: [PATCH 16/46] Doc update --- Documentation/GUI_Translation_HOWTO.odt | Bin 226795 -> 235937 bytes Documentation/GUI_Translation_HOWTO.pdf | Bin 332687 -> 339069 bytes Documentation/wxWidgets_patch_notes.txt | 21 +++++++++------------ pcbnew/dialogs/dialog_pad_properties.cpp | 4 ++-- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Documentation/GUI_Translation_HOWTO.odt b/Documentation/GUI_Translation_HOWTO.odt index 031e2d682a92965f4db13d3102cc8bee3a575244..163846098d3f8ec3caa6d83fe93b3bfe44272591 100644 GIT binary patch delta 233280 zcmV()K;OUX>kXl^4h~RD0|XQR00;m8Tsv+=kq$)>2nYxOTsv+=00000000000GBTy z0vDHkZvzp3G&eaiI6*l=E^uyVl)H6YRBzYskD?+{0@5WzcXuh>DBT^>-2sp`Bd#$~LKgmm=yup712M32DB`K;1 z2lt#D4(?gc>sPQPqKQ$)u&)=6!cxkwVISaY;~?07Z(=7gbte%;v5(3Mig0E&w$>&L zb_O;kRt%0t4kjixj$dq@2ot$n;o#oGNr`?`c1zn|a7|NEx#>Mth$))biO2Iuq!g?C zg+*fs|MFvZwf?hrG>n!wST6~Jnu9=qoNY98B-*~5tf2RbFJI=dG5=(qFpy^LzrX+H z=O<-<%E~N7y>z)3@9f}sz%$y^A49d3;aQG|#(Pd|B3z z`p11jrVcm0rd-|XB?6F{pBl`>>hd{b_c;Op>3MAI%au-wVuT%s}P2N zxtvQEfy4bKok)p(84#5#k8^2DgH~Q`qD$z(I^=dQUynGl=2rZ$cNRi5;waMQRW8r5 z3tLWVQPDd~oxKn%)^avDi2AhL`WSle9NgS>ISt83o6@^>CYp7Ax}YO*K*zU!vm z$|RA>Bw-fjN`mVo5n)6mrY+~i@37!Y+5_b!9U_Uc-wP3F>AqswF#NGCS(x=}WaXDo zWx%Epk81jMUg zB6vNExnty`5tfhjU3hD1WK7!J&=N~%pE+`Fl$X|2Y?Dyv-E)GZA$4I9M5M?(jln?~ zou$afRQL~&5rO%7rW7ATkmYLCmj|^LA(yvst`Qlfd7`2tlEH{li_zKa*dP??~} z9||20&#kcGW%e_Z01^7iGa|-+LH=_LgH@zJ2GCTBq>L?o(2STLW`Ezs683ndwdE_$ z16kpGJG+_wQM%=$Xu=FnAN0fo0L}G|kK;T>SgcfkWTCa%DyhRUZ(4lE%01{O^N*>@ zaEK*j`tkV(Wg!0NV-;X|&5U2y=Pz3`ZG^PA=ZJ$voxg$1YJ$R&LyYu)2?9xUhn>u` z_V0Kr30yENJEHfo2zlQs$ZGH6IeiwD-a87&lxn=-wXr4cZiy5!n`)+i9hxT|&OWF2 zJM0Z9XT!-97|&{A>>5;5f&dMO%2sJcI(FuT9G#ON;eLx?X6%;oGi-4QUtpi-f z3p2%PuX`qb&{_i~1Z9Acw4X1bH(SSD**ZyBzWf_{ip-Zz%1&B;Tk^cIXM_m3qyRLs zeQp=9!&lETJBigLL+UL~vLrrLzf)QASB z>!ozP7M;CT#R&Tk43Va{2nZL@tzMGEDt#mTUN%*3iH~p%=;*ePP|t_;z;-*e_VNj- zVp(c`Evv&VgV<9hJ8 zf3KraZ7u|HJ=lya(|D&UOHueM%PyWd5d#f6zgGMi z!?aHOQ@%xqqkxMs7hS+xbRXC-M^X6h7`JW=aBvWqqAID+()8ubaJ|Tx@&8?Vt%^#> zcDz;p+-2tBJ?P+Fbq;nl+nvPJ;Q}}l4}r&UzuTLC9{=_m`1g(lF>d45?gau?nDC4J$ZHD+jKsk_WSq%xLRLYms|DT=;6S>{oF)+ahJZY z+a7Cw={enN{GF-bQTmJT1$#Np;Lr};!tP9_ULRIGm>HQn#Vq$Nri&J-R)fjOfoIK+ zTw_sk>S7KnaIA{fyV(chNo=vr_^X^5bPTZZ=Jv|-eNs+grp#~(YmR`Xw=!j!%wd^4 z%AdaZ`l#eOj49GSP9mIM(DhZ@`iqbz(evtmkYT*uh}p$Ryrzm2xD-?=F0`M`cQ)7H z^G`Y7weq_O`SuVy49G{6BmB(m=-AWksMbT6Y@GQ`JKgwBw<7Cjgiy#|~H>SWCOK1)u0%5JOPT-m*qS`pPg zN-7tOCE@ms&kMdA7gHUQmA1%F2fdKKUcb>!QBGY8tX97QSKKX?im)Hp5urKD<_Q~O zTJ;LO@7h3h182Gg!uua^fmoA=v}cQd2!!sv`fW9+*?;b@*<#vqv6cL8p~!snB)%w@ zGuLE`zIwAlPDK@yme!Y#GH|@S=VLd!kr<~j1Xv}QMl3CtAEBXv(xk3p#xS$R=g1P) zVlAut!23ryBw=tGNa-RNH0jr)V}KBP9|E{bS-u8;0!wdDBas?p=f8nT!hFboQbKH0 zoUp7D@(xPO4-27zY7*=ZFm;|eWljc5p)%=r7!U{;fwvRhb)@~kW|#aSnSIXPi%P7& zbYT56nC}K({C6srC&arTrc*@SX+nJZ2QwobN#_MWom51bpIYgj>IfmR?__Oq#U`VH zsST=&((6f!iIrf!xwoH-P*L}PFg_p#OTM?(dkl4ac)iT;d^)s*I8ejqy(Zh_2`cxAqCYUhmfE7RpH|p~Rvgn?z4Z7+A7AW5=1Zc?>Uq@bb6qIv;X* zb1poM2AxK=9kI{DH3IsENTcNkrU&f@foM}qkTohCW6`@+ZSt~tb4Y0F&~E5Nz|PS9 znF2Dr%|0aUjsr=f_2GT%jo$8J`=q5?xeq}~zFL8U=xfx}_}nIcxOI}buRH)~>FV3) z8b^nbpavd_HrfYTf|}reyt(6d>-(mV@>cb5(J%p&N;CEj!gego<-TArvuu*AL=dal zr$YC4D_DS0?)T_4=^-nxe27@SxNA5zYZFNstG}j{APqz%GF`b0y=u?LPN|jrY51M@ zw64|T8=|JffQwK+fnPzJ)nYLsR?Xtlj{(66!CF|9Hm619;o*UxjE)|a9 z-8|2E?}E;pJtc};vy6v{k%e@Eqt3PPex9V^9I?~v0cYF*_}G3?-{Rwzn*}{5^U0tL z0X_^R#<;urwYw@8qD=351Qe#$QrU>ypesgNQfOCxTOmW3%gHVQcNMdyd6IlPq@w>? zsBp&Gh1Gj$_<|^Zp4v`S-{Jm-^{)bBZu8b&z&mTo06W4b?SoLvWR4R~$EEG>=SsO;Z=?yWd(Z%9RZV|k{@i4`xN z-Bzq`68CEAciS`=B{BGkDZl5}hHvcVFSSonT^VxL$jzjaOQ zc1a{6yf@p@e3(i3_;Do|JvvrxZhc>K@P?tVKC|tu=I<>5W^KyAMn)+ghf~{j#(+ER zlQMrlQNM40Ji)G++uu1{`FwS?hd0#f-XH!Vb~#+^&ISk4RL)lUiGL#HjV`X+bx;50 zk+YD)rW6M7NdsEAQLmfWgc`V|pBlb%@1V}s8Rhe|X^^z;uJv@l0SCH-#$Alr{7!Fa z*t-c#^mgYTIUs;t{b+@o;79-(w3+Mwn_Wi3x?iw=SxY$va=W+KBK8N%QC8RQul0Q- zK!_yHXTER^OXH@U-F+LYPsz!U(l@Y?_V}8Pl%@!FCo~a*6K~?98e7#*V6i@oS<;Iw ze0*27H292T1xjLFQV3f3zPJH~lz~=0SPDZAg_t2L6@Q+yS zMU6#&FI(W%>L=kGzx6Im3i2&);nmXx?`Nx)lo(o*^3w9}P_<|S@Bjd^*K{PhDHful za6i)Db*$%m?l_C!5X%?8_E%+PyF59TaJ=66WSufaL$d!?jQoRid=y-g2z^{=`7-bT zniv-(DMd>@@zqPq-E0?!u)iN{j7nN9jEuN{bN)rMq53kj2;k5`<17pSC?>$x%la&g z5<;Yi9gUQc!1WFtJvz%VB8uPMaZ87_q|YxQA(vA#NC`%CgC z1u09iEbwG1R@e0{IyyRyOoQN2>FJ@8qvXKuE37BhXtV1VNJ9)BgZ+z+NIpHkrYxL) zgO2g^<9%!|I>yEmkYIc$ZweHbgzc7`nm;1y3wAIJJzgZp&pr`I)J|OZ)6euRsj`oV zVz8AMRh#$KVBg%m?UOSo?b zTX!I#&@Zp{x-WnTA?XH+->f?u=WULEs6K?9enDg866i|=s&PBqTdLGL{bDZ_t{+Ga z3yi6@W26$I6wP>WUE}MNAObpqF_c*91EUE=lfFt2ChiU;XlF=Cq+eODI`j zOIbr#bv^-uK(MsEdQrtGoEO3J=*;RXQAhBz*{*U)3ayaJ1VqVWU! zD~&pTm8uIBClC%U!uNi$lR{WsU1LcdrZ{wpaNs5+>>DsV4_RU+L`|u)a$dZo`6W*b z=AiQ?BWI6GN}72(Q3rAU$f!6E)L`GrPe>P?!W3lQrYxy&z789Jet`_keY+9OCWmPD z#&rx%o2%3BJ4#vcbU0G?GK>a);G1)8Zxx7sAlcJS6f77_RM8CuS$4*l=?D=0-m>BL z_&X|=DsBuAj`lZY-Msq}Pph`M{W<*rBl=VWFRi*NN#V{xO&9|=0g0aU8|Hn}FW5S~ z-T((dx>zMnDhv$fxX2e>{z*|k{b#Ar(T~G>l{oW>ND*0lyI%xs0$z20`MV5k<{?!n z00670tWEpVhMWeRsmwcZav#)(3Xo0)Z-w_`gMzMl)=b*-i2yu2fnC{tW4vi0WvzlS;Ctd@AVKZ}k3saXMY)sh> zY{v};W0A>dj?xNTPvppdQOZz%KHkw@EE5_P6iB-IRij`w;2=6G4keH3`_R4 z%-Dj;%fiGoNF-DPY;?IOTO*EAq*8&naOf6y&clg+49*fSs46M|gbLbB?l>S;#U9=g_k;~<@ z8qyShU+9@Oa&?DR5sx;a0b+*ysx26}EYshvZchbZQa*LGd_FNVKl;Oi+0cCI+FJBumt}TBfnqc?lA6g z5C3S@%`cL#(`_lT)2hzYIHm<8vm#`4u<^5nYJi?pgVUM)(mM^@yVM58>W{WDsa9`#&jBHMc=D1`v^bUXsCWmHHo)xo9L|FGvqC>9k zJ`e{Oe6qWu5?s7OFL9J7f8TrQ)i=^-`9)Xo1(WxyACRGU8eMex{rxTku&w#^p64d@uwe2OqPLQ&5br^xV#VHi27`2ThjAPA5q=+zSql7=39~Z?I-LCn06> zOn`V(J!aH%1xlnSQ&7-ktaow8U>FuD))DzPwet-Q&3L9sFa|Sls_NaW-CR1`AJ_+q zO?24|UT7A=oa)(YnvK`N2293(hf|YbK40DkCq~-Y=m{PQIa%w*_Pu4>JQ{E!Vf_YQ z@~C4K1IK&;PLwD2#KuIAS89S*1russCe#d7lc{>RT8cR}eHtQNQ3kEQ5m!i3p+xK- z;5snco~8lbF0SSIr-sHQ^8$HumwYnnQN~}hr4}Wr2WD5a_UmPabu%M>+u%-Tb}NME z{xZo-9%WkVpwcwLebwM9xfx5s%7W}0c5Q1^{gYtu0=AUT)LULL5R!H)M|?`u(9ZR( zgg}L~i%>XTJU#hr(HeNW|E?h^)9qZaSS(XIZP5$JdH;AzOGHqRF>@Fb(Q>>9{a3`V zi~s0EhjC9KOG2q{pfo*yrp0mP@!8EVTtJ|;K9{~mk6>|tXK`O05OJFJmeq7U`(82r zIA5=@DyhS?CLUK4+I;?uIeADqq@vS=$m4iL2*i6iywo0MmXY+cGd`6&#>_dvxeTJj zM?|YR-;f$xg+uIMLoi;#(%{mVVcA^2H5P#KWolD;mpp-vMOW{CCT{8&pZ3m--qy>N zL4-FS$K9)^ZEd~Qx}zP=S4r=P>K035gSZ^c7M!$naiSipUfSzzkn%fKFGr+u)=C+a zi=rid7glCQ>$tcmT4=^seKMRsQ{ECWDm2@%5nIB$cDJi9cv=$g8Vb@r2lWZfV5LI! zMy#y|K_nF#8ty}XW%xU7dXs!#Y0SKk#Y9KcGN|e@Iu^W#DPvDTlMr7F-AmQY%^AtX zIk!G*$nS8>;4tWheLJ7h!08>DXNdJyeV2o*b|&=v{B0~^?z<|FJuQ0^;7(%i43Lmi zai`r*;1{_xI?Yw;!1$rFO7HM)ZsCZXK`2FbmabjTb<=}rT1_JZUDFpRZoId zyTR4t&TCVaSS)t^wYT2g%S)Zd|=xA?2tTqv3YX$btJDR zuGf&2yUn!#;*A}P2pT;HVe!Y?&ZANt1&x%#zvJReQs#^7b z2urS8ER#L#lGJ@Pv8_5MuLq{xAP5<1_MlUaFpkC!8>Lqyi_khM7!p^EcxD_;cuEC@ zt&s$O^MqwSVyqNhVh|ZRBtWq-JA4`l?MrUA6E1^-c2up}%Ok_rTgxOC>WOAq>%#s- zssA)@ijBuaX-=vvpIQkT&~RG9o}MEzErQqE5@X*I zh{(#;D#U8aX!XE|Gh<>Gf|W%Pzw;JrWM-DGpUKHiAMz%n@zT2CJ|zKdBX;T1@G@I> z8age+9AKOH&=K7ty#KOS<8~a)Pu0eI>bN-}ShgjmD6_p|lk33X>@0o+3g5HP-5Cvk zpM0}G8?g?l+8{EzufFDIYrHIKmR;dL{zSG&$ey&XoBNt8d4A4(x&ogqQ%8RI8I&3M zi%=G2ra)`l?)_YIJZS5;yetWK%;7Y&;Fk@R(Sk5B9=ETh_>ziM`z!v*bhJm75R$1w z``N=>R-OO=V2dGf9&CatWv(!r^srcecy*6T#H($nvpC>{d-Yrh1=w*aAAk}|(OGt1 z>*9Ly5yTg2U9u7$d2}8g=>{xwS;Dz0t4O@y@7iTJh#7bXVPX;nwlwKVnGmPm;i3uM zP%~umNOoU2l|vsfT5hr&+Y3or{X0ZFSvYUGQNhcX93>%Tm+KeD4O2#A5QXD^^+T=7 zK$QZUni98ru$gpNVXfDj(5ATl8Y;H4gj?JMz6`a)*0gQ$%cJWq+#WgaZw-%i@%(@v z?)@h7tjq2VUgNfI#B2Gf?ge_`04Swv8+tF2<<1f*BA8in*Nz~fQ0;e#V~o~pTuG+M z>Nhnv6E`2?0e<0)bxrNdNW`#z{kVPAgR>jV3c}$y1j?iN$~NSML=j~Nx#p!?-a*~w z!_vrqCML7Ep2#S+?~sR znnSC-6iO2dq+>*J!8Ngf?y9ic%+c#ZO)4__tPiJ*7V|8hPZhM6>9mG_lnZ#g;zLG{ zW;^MtvHe}X1t*xs|6nC9372~oYcMFR?8F|ggnu;pIPymNw&ShCiF6v0y#9@`Ky~zI zaJ$()&gIKeIT(CrBo2DZ@Dxq%3n~DjA_y6;Syz$dm~G3q6uxaM#hNlO2a2;DP42MY zdVXVr@wZ?kqLjJDLk4Ppi4O#RZ9Q)aN$&kkt;dG#GiwD=QR%}{`Pn4df~>G8?J!|> z;ioD<6025`%JbeF9vB@vd}E34Hfc9S34akcyACmF-%9-pas;DfK--@mSOgU4Fl$%&# zIhulzG+X)B12)|~u;^4aXMU5JRTjpnw(}jLy1a&+mKZl7>IHOoJu%ZePa_mtIU?l3 zU2l4RtrQkOD^3U=lq%nm`SwGl$XghKQuFhtd7uy+ZISGmdtJv19&R1mw40?w1;IYb z#f06_V2Y(r)A7B3exk9OVxpq!vdOZPgs2iUuDs`4Md%nNt<%%d6>kddfl{B*c@T%zd;Xz*VkHLQm7>ZBprTw!W=>BPwOuSdBC0MD$ zsyE%fqN2}#T5)1x;7hx?xqX;Bb#oLzi3++>v(Y8iYOpeYy*@E9KIlh&swUXbVrfAmfzD39TW`O%(Jwb74*956x#X$F|(kR0>}kw+;QhF+S~Q1)dS_tn>TlJ1&K93OwL0=F_Rq>^sdCB&SHOf z9y98*HdEp~Eh+jj6=uDxbh7z&QkVQ51XveYQM!*do|}Z%Fq<65ElH6BX_9;a`MuMHO0A zqZvngy$>xFfM~E=0%#x)U=DcGc&S!E*64TG99~Z2F)^z4i&iYeQc$>05)k5t&Jz>h zjNS!<%_l1YprMOiF&D#ou}M*~3!6l4CqhEaldd;GJv|kaziSrq^T;WbTD@gn z39yBK0|Rf19SJsD`ca596)AXvHRa}5H+@ZPoSP!H-7sLgtsrS1a)zeFro>4~d+0PT zK2YyDSdFmux>OjuWm^77PLKvVsLU;}`_(a4^!9YuTrE(UPqzs6OR0RBzj!66=@m7} zrkkZS7?4MvKUNC12DUR*Ox!ze$PiMTztr!4KHJ){GZ%=#Q2GIBfsa(sSg&gBY!NC- zaiN*@KgiXK==5cmD;Xhi_ZK_|k8iEaTwKrl$l&ZMmk0|>^D^+xclphhEL_-c44U;O zwuJ^s&K|oBP&UR&%6`4Y*{Kv`8M?A((9pPjHgmk8Z$r=?5UsRXZ8?g%DTmjwYk!Y_ zdpF4#$zjSsAQM?tg2!us4Pj+fZ(a5p<7|_kE==GZ+}Gj{7y-Af*0YRXSxUT;X-|^u zsu+bU^ft&O9Hu$Iam_^BbJxE^<~$rQKHa^Zf7c$T+giY@XX`SKq)KG=MJ8{pg?@W2*vI%gI-Tjxk-WLwF)z1g3?yR-ug z&dqDv*I-WB%hc=7eY}rI2Q{!AE_}Xw7=RK(kb+A`W1UajocaYDpts)MaV@+GWA9nJ zw!G6G+}$b%1(f%%6%tAz(wi6Iz?0p#s6dW+Bf>Us7wKKTZT5^H$z+Fq0oina4>Zmj z6#V{#4ZYJoA&*<_-Ui3Eyrp#4r%Y2c7ZDyRbiQ#wP42j7K`F!%HQPfy1)T5IFx~CZ z(Z(TInYR@MTPWYP$Ma7z_cSqhE{wB-&bj%fBbgL0lVmIv_aI9=km{oqp_&(FHfN2I-~>78aN_-i^U#`z zor_4jo6WYVUE%)d%>74lT;Dze9y=p{$!?Wx`C)oR zCXwEvgq|Q~1|gqE92aHVNaaedWSL_A#BFHMi?JXB5qJALIzj=5t}U;V69-6d+dA)d~nX{>GwJ`g0F>-D(`-S-q9njOsvA&l>LM7sG*#Cz|Ys?w7Gkt6f0K0SUPZ^bJ zAE6k0w&qV@fSMI@r%ccS6az-$VeTq-_dGV~K~kiDXVD9VCRn9$^8m-39mpG7ehM5Q zE$?Pd0CLCWD~bOuHN{u4;4(UrsrkaZJP}VTWu0lb*l3x=Tg)_BoaZomE&^kXxYP4# zy~b3ZOG_C;V5f!`dUz^FM!GEuxd4wpCs)M#i*gz>?P;mDGuTz+xe)i7HFTk3k1 zmAMcf%%9-GjLRu)YI?~g%X&G1SNXbZMfEWOSX^5X1$F-vh*v4eyhBTX&Xf6Kmo}Aa zF;&i^h7ri^e&_G#*h&TwB4cfqs02SXdPv-Vn+7PUtKxziuU^m=PMA%A9&z?R!K_V} zM0t}$P;c2*GQ3a4A`Q$GZAG6RSL;Qergs~5tZ-i*STF!q2W%RQs;=64CTEY_W)H6g z14Y-hVTMmiTAI>vG`Xw^cB<5T^|n+rJQVMRvRdY$YKXx>?S26P4&Cu;EVc*JR&$Mi z&p@s83G3K04>`?!%F41O}J^65aj(!2}`9tgGO=6s`Jk{vakD|se&hgo^KF1a$4KLb$ zrv_lqqXxpKPU1%yzpxt=UILc4>PxdJKz2mTec0z=jIAB#R;M=4{w`tAG_4-8sAm4;D6%i4If}fv%|2@?G z?~#25h6j!I5{BvZ+QNnek~>f(M7zSf4M|B^zNwaJDwU`b0RUvo$l!{nYi@4Jkc68l zRdqQW(f{2^vhC!IGd4En+^dJqQwTHGF3`FD@7Je65y9CW=lJj5U0s@H5i876lc67z zluQo9bcgOZSi5T0*$_Ro+4!Y@WfZ7rXp)%(AHxs=k0qYj)f-AgKXz^wteem%n3ZF)n*?KOfJ~^8A*w8S*Df~;EReE{Z+bKC zYo`>(`}02=Q$=v6?(uI%xkoHB8BC`~!oylS2C`DAK+v^88j7dRndLz?ItI_--R*;` zyUT?rFISnoTaf<%4T{^@g1J@FMPtp-rb(uQ$eu?WTFqMwbg*21Zb3}l9Y=!)rPtBB z@bR1~Kb7U(+oh~ZeFR%s$0Zlz!FKos0rcq5fZo(S^B~a?oI|rsyIOk`;^)X|q7BMZt%4Q>p7r%nye){))P50@+yEUYN##RaPn&23Ehy;jd3pQA_r{4HJPpbKKl z=O1O5SF%dp!Q*MUUUtswRp~VRp0+Ul{9QVX5~bdl{~ug@1h(I>bQrmG8qP5xiz`KnJd zpSNs+7UKnfY$OMQ(f64}MMGetyGp&K;#4`|slgotLzW>^HYuro;{zJ+`*-Nk`j9Fw zKB<11Z`aTAVd>>L9Xop*U3p80yJNfQcn=B;m7ZF?t35UiHRfxt1T$FD8FfI04Ae)S zsl-gTlVit#2TW{Yc}-2;h2~5Bk;Kdz+a*B?3V?%ue3d#qIVI&-otCS`#1E;1<27&F zahMp#M^TfYAD0C6z24>c@*$T}?oZG8Jpe=hzjEEYBU+-LC|+=o5MIE?kKWH-UO$k$ z!b0aEam#=yA}l$Pr~LW;nEf}QZMTsB7vNGx?nP}^>;38TPtS||jgH-yztQ1bfd1*< z%e&rx{+-t*?N7UNBDO6rbmRnho8qdMsakPr>D%lv02HN7Ym%dWed+{*;m5OjJ^$pM zlKB??dYjpyla0Z?`B=QC+%vCEkBxzW`DL=0qt0TI6u|l%%nak%g9|zgea@2j1rVEh z?GXa6&Vqk!t<%D>8cYRH1ATQsF4g)E{5eK{hCg&$U%hIa`9jIcWdFm=9 zDn_=O8DGOzE%H^P-&aDQymDlKE&kB%?+Z3)vPPP)0Sdc(xqn^$f_J{M;o7Re12pn~ zX0#wIC@4*@Mf<{Yg`B(%=x##N_vQn+ST~G`%dBCmJNCb9SKQmtyOMrB5)tt+1L#+^i?^h}Y{5t?AyMYl^PoQpa;THI8KApV=U$y||;2nX;yEycHL8cYck~ zhVQM)k|`zIb~cVfFM5>r{KV?LgWI|IwtAv}6xha(`KB(I-nqzMcP zg;qVZ4l_s%@xd@)F_p7C@o0|(xVQ=7n+6AJYwg?^KNMxtH2I zcbb+i7X`44up&$gNkCmN)0}SRd^)&|3_%5cWuGQ zo>)(%$j-Eh-Ox)mNA9`CS7^@y47f=s$BX<+PA(q$j`m8AM4|_obe>;=Bpo}X<{#nO@ZZqn|!%0D8 ztG9?YT!;>{c)AG@?Ts@iSI%2D7l#m;sRu8@zBz@9Z}h0fP{#!KW(b@^IpNSH-J`LO zD)#KHs{!soL-?iBJWwEEq1Ojoojf`YV2Dv!8qHEjy_x5+Io9ZZ22!$Ik16QIDMvD0 zhMk?a#bg&c_az!BjU6*W|BTSy^Gt`t5-Y~?xb=~^6aEG}v_luEQ%zG3aa020mWYr9 z%w9?=BhBRA=&3w`OLlX#4;?FdQYAhJVJAS^?!=@~QH}GOJdc~M#I<3$K=SUC(Ngjn#g?ClQ_U0KzD;|b`fdGon{8M5$G9sx%3u$a5YuFGG-em?PSbX= z$^E_K^nT8-&wUY-j!mFxzI?{DV5Z)Jyfx_HZ8l8b045TDbal_|83L--!P)fbtRbcx z<3AKZc)ofmV!qD`%LVbcEcyAC@FhJQ-dNiZe%#klf*twa@`V#@N(EQ%nn|7idrVPG zJns6xBFk}Ur)#1l0Avc^n?7oaIfX$-wEnmXC%{1vaYBXD@^OBk{yX{8&|4KSd3r*u zW8*k3ob``?sixMspnF=fnc~@)R{dETu&VH+v$2D-gb z17x<=9-d@0Nj|Y$rwaSsRjb^SqU#&1tmNhAkC%CWqHO}Nd2TPDN{TSTc^BF(Y-kA3 z0XY|nho`I)3mrU)>o`QdMT3ZTp~1ZNkLj#u;VJChR*d()#r44C5-;GVt^oO|#Wbl!UmOP~b8To^? z;(Cs0jpl4CpRX8_PuBRPj--rCuN7xvOKwnqpSkJqogXQhkmBa~9Mq-WdZAN6h>;w& zE9rQ;&!3i;K(U}rV#Y$NxR{`;&`ArE{?%@$rh2|I%?8w`!nYVq?JXwDeY*_}W|`XU zP8k}mgh*kQ67X%~zmW#5`3@m}5>eD=?byF1`8ybW?y-jl#o_r3AHGIJ?67IL%|94_ zch?RSt@#t9N_Js@U{H7{)$Iq>C)|x5#|>C{q|<-?;eQ93$MWBlad|km_F#&4cXK?b zJzdUIBo&;OH=Vx+jjSHYNB+rlC?E$ib(WHqEwDL7Z9;$W|i)0l&NZ?TLoA7XS*De*B(9d659gaM2{YiKKpa6zSoE0n~~Et zOsBBpQT<0|DNAd3Atg%wOFpCi_zaiD@CBV(IeoR)#z1@+E=$gg7rZ-d-|3To-&cH- zn&>rvQnvS5a7b8E6qzeLMSALFdVWAQ?UYkTYm$_8LbfT%=>VTE-q%vsrR|}oZx%V_ z990Lu5FHys++)qs?Q;B^32`VB^gn`)ThSV9OxFjX5R8>+al!a?W4_*ElD64-PaGV8 z;)^?L?lfDGR@Txg#0uPY1U5K-2?RQn!6nHaB-UO8h1+=&W9SlrpjoHak0u)@T2Sf+ z*3We$aFlW8^li1L|0*TU`#7g9QpufQMW1$jeFhJ=Jyk|v)En_q|7`nr7!lvp^<2}> zwN@+kKvC(n9UJ&Qyd&PF_Q{Ni8EN$}pdseiNZTsg6>i37`ocORuI1@}bWjnt4UHEZ zjP*@xW~u3Gv9t|8s~Nryz-o!4t6&wN7CIz=i%x8D_vx}J5E#)3s|{%_D&5vmz^1)_RY;%vQE-|O>!R8T_{lK(RQZ4Ch_p`ca-yxFL&a@UJEO0# z1S!b-k;K=deNENWcwGGzKWDs7;EDaa%^LS^e&TJOQst_vv5{rh0OrHRRQJ6>6T%Uu zt^`-Vy3lsRE^F(BfhQhHLqZ1swBrVPoE=U_KHT42YcJYyKc7N>8->w8T)5j?0vx^d zXUsNJZZ2&cQD^J#=H|J-&wvWznh$C%^)_N9c3BF1s9?&m&A-fJf#Qu2yD>2z`;5(O z%;V9_$x1P{i?(iCzzX9$0JyHIAO$-idF@aG`fEFCnZmFfjbZlU37ekfMAP5;Ki3s6 zWkkD{V5hUvE0N`Y#&41f6qQ$-e=)Kh&~UO5qqR^U?sKH2c7FoOTWQ-LE^Ow?Dil@<}^Z5p2MeHpyq_f zpTPmCsUq+3^}$D%1Jf@z@c zrghqZ=z+ZO?`!6E_Tk)Fl(N9G-IQN#sr}n92?SYy9V6ta=2rTz3LA{)|Mp^|V9DZXNopbwx%8i8ZwFJ_MD&<{^>WMp5^dohqFqnJ zP;`KQ*-y-WN^UE5+~0}9gCx=a5^4K_Tq8GZFVD%jm?F!xIBS5{tgM&DulNYjc@**s z)y`#Fu|xfT{Gi^QDp9bo!1`NtW3qP7@e?J7vr?r4xtdjeSwVAZZbpK|H))vHh!&8~ zWw}X(?0yx^S}_fSed|4J?;Cs4&!0al7i$N9fB*iS)wY*_f*kNn|9|vkCDCC=)2!Rm zuTodP7-X6U4l+EGlRU$eBZnhIMew{djY*5acq-C{s8BGZ`y$l93x<@SV?@JM{pC}W z9=%gOVPRp|&GjwgRjDKkKP})v!_KQa*$Hc1W#Bv?>Mcs-d%!(d@&S% zth9lj=CIIdECUR#&e4&1O~|}gsQJ4@(jk?(*YGWOE82`j8A11MoO^0_eG;(-a#?#}SOtBt-$Ab?5FJxIoq0@IWQQ-dZ0o5*H!GIAj{TI^6z>UQ&7N>=iZ zW?pBKEa+ZxRzvyp#9lIH)*(XrklJnw?tjKTmDU%n$VRbn}r=Wsd&Codh@v z7IhGtC+o3=M(oih5xn67gY4%vA>s5@ z^8~qD%ttks+ur6Xox+_zT+Ce;Q=QTD9vlseAZgrN*3I?BBE~!R+GVvY^A&R}Qv_g+Uz?rAjU{k7DH_&7~S*+r; zHx&*O)K@I5hcHR|zWYDAY%(fpku$Fwwn$edt01TejeOOM9{+k4V5yF!@S;T964#5Y zLW3o)sKjNBx+se$Eiv;;M`-J9jC1d)Xp#bdO7@rkpsI0K6?uBp zr0DI;fn7(NmonRUt>F?kPLu*X!T90j%fEw{?D}IEBg@Sh?*^T!XrlVri{Vfl? zqs766Y&*^DX376fSmPep2lklehud%KC|CruySj3EtZj{qtqeQ8oMjdOYCx60B7%b2 z@dCbqBO~>H(GVOHIDR2?e|_BJICxMy-k5tdLJoak>Dk-M#=>Vl@U_KtoxAw#B`?Q( z&N(~b>{%vgq`qhtHa)FFqdpY6`ou~i>NEUN%cMq(LtdT=2_mRx@2(>p7x(I1cG%dSE(e=yK-9{4GYs?_bY z^+ien7=!^}pF*pB7X)k>scEtV0T@Xk!u?+$*aWw}v2g>HZ%3#>dy9!la76OdXhHn? z>({69#uM7j;ro;y+te0Q#YAy>?*R@5M-tV`cDRInbE7AEiND*7s7hbHG+7k4hmE}# zAO4*@QXEnP98%8Ce~N*ux%+BS_3HGZ5@L?m@oLdADbfeWYyaB#|B^*sEn0wC!GBXl z1@WgBNq^%0Q-b|Q^a?8)N#Wx|leTtu$HKn~ zDgU>ZlK!_f#Y;i{pEn#IJ{Nu7&0MKj2Agq&s1lXAFcIwhfAd7rZUYDrM*?<2U)MJ` zs+j-%G^zqY&*VNxbf^q;^ z?XelHdk^Wkfh`1AgRxy8r4zNG$72rTlWmFzL7MZEj}v#SywYtvzHTP zY9!y^FZX4O;NI-laH5a{L&c5ZW5`!}!j0W-uc&q2f1rPkzPp2uN=UFc&28it7B(i! zp*~?pL60Y})LF{@{pEc~j>-+=n@8RlL+yq6c*bu*LA0-5VN}2APYM`a3hx{*6Iof? zc)9fR)i&>yJFs~#Y%E{H&mcI6mQ^F6?B>&Rh1pL{v0*z&b7c(Weyu^5ZS&s>Ej)!= zQbWdje=pZc;xWGwx6|kV(9uY8$9s(!t3_kg%U;u9~nbT;HG3r3rK&uJtj&Gc~?)s9SrAD*i&A6Y2R zf3MP}_C#RMtc#nxVedNbA-L`&AuBKn9-u+}aA9FAeq!*bD{U9e7`gr^G zCPO!1=_?*GK*b?H@nIOeVa!jL9i9zUe`OyZ9}kU+@;39ZwPnqQKwfV!Q=$>FxC#7m zAzRzCRG!Zj@d;fj+3Qp;k|s_7M5ffDS-o81E@^e#5WumXAW%O_O_qB9a2fAR6?3EE9R+KAlo)SN)#SPI zAkY$48tF-U;lfG0b<9a~R13O|e~Bjms;jN8t^)joyFKRdsMpgn=k_z8Q$*mMISE)L4njCCN*hE(T5CtG3up( z%%phqUrrjk?I-NriTI91{3EH5CA~>Ze3$S9@_*-DstQN9jckXQbjLIF_3?JZ{s;>~ z)&&ZkiP^Cg*;KqZqR0t>ZAq0#ssZ~dakS%DJtJv&u^=*0m37Ume?sttQ9d$R=t2Q6 zyVk>?7>;90&?D~gH-H1jB&JnJLcD#i>bgcev<#J!bZsv@4CCZVY`%Tmk-D~U)=onS zqkRh%Xi2z%{|IB_vXEezJ__e5akJr~MsJPmT2<#BXYHf)xlA@5XrvtHhl|;LSR#*! zk#-5nZ$y{C0IKs>f3iwcu1R1DnoDS8O*a_B2P3#1Haq5tT>UK{Hb>e=jR)Jeho(7F zQ&o)S1)~~5Ozo~u==aZ$`6+A!qS>9j7gxVJ+1}_y*u0>x%xz*|R3bzpq^HmBjk0a# zm{G+-#smV#O{Kqm$=4_j_7CclMiKM72%-jUgyPh--Wh2ZzdWBCpu@VZU#LX*ey z>{l%MBtW5Wf6ty-ucllY{sOlKfZG1{lRsK7BMG;()VW>T*T*OmAr?dF5RSa05{dj{#0e3LG!nXAPl{m0Qqn;R>~5u}a>vp_~e zC5;9udQSyZl*vl@r-kKS#3SrOpcHVZNmDh7|=p%iHOOe-;VIxG0fS(S<(IgG-KheM7y-^!;<- z_&P)dmGEz(ztRK8GwRNO)x%xP$4r6?TIw)|E5lC>JcUMN@u5)qALf4x@tM>LMJt8j zR$kwA@VQcax~KO0`M(~#loXl30h2_lG$2BhEnlL78mD=!*V%KOpDD+NZ;8rVSbvi> zf6?ZoRdX4t-RNCpD6?HIeR6Rk9azrpe*feC^FB8CI@PznC`G`PBTBqz1yt7vPK?jE zcY25BVudM!_y*%1hSnP<#(3M?;Gj8M z@Hk*_DADp@><4IS9)feCc&!Csm*Aace`cH(gY*+jOTQ&kgN_2*Kr8R*8ZAlOV}FpZ zVI6ozJf99I+gIC?=`qsKM9CpI|NIj9er5H!ABq0AmB8UslH(6c$KzAOix(hz`u##R z|D1FPnuvZsd*$#iHdW3qtC&MtHOOHzWk%bDmR%fV!OXhPKL{>ec(ZG@iXbsFf7b#4 zZ}EquYIk+Hz8vYmU6?RKe6_GbAP&iM`BX_EKIdz|+jeO^d3ka8Xh!Gb0^vpa*SayT z@coIn`}&7-TO2O|5)SVMY|S$Lo{=eTr?Y#m&+A$cJ^20p&4@0%4B6`|45rLp<8YWf*T^fAdi$jB)g z%;Vog?(0w?4?;9n1+^t=I=78Y9(bOTUJ+aOFo@kb0ZIsu)ZH|lV;|{Ye|8|U^8LKl z5T+{^+Xtabv}7SSQcWce6vsy?=En%Nbok&C4sGet!y4ZwPPa~1mRdaDsUdf2`ZTjkO^CCZ{7`QDi|@&}?sg)dTPBtZOSm&Qe8P*N8U$ zAcCoNJ+80eEBatOd;0}6>E!bK_34$Qq(?lv53OpRBFEY5SJTDXflo#K?&{ETx|kdQ zVrR$mhF!Ebd7Kl_&=_oxy^iddWSp*6`)ak@4{;c&u?5e-KfNEdd*pIZHm3+Ha(8DOdSDn+l9wznnNACx=o*GAFfLB6tU>(}X=lOSUQ^Qjy zNdP4AmQ4oi2wrJzaw6>wOvARq^-52T68N}h#4_}wOkVxQzjzH+ZRR_@jHoTRsYCNT zi8w3BMbl_)tdRh}f1VaTNr~iLkCCYR&~Pv8M!XDZn2-=a@Xc1|d6TmOnJ4dlq<jCd%*ZMjXl9LaFd6q0!` z0SKuX2xRyskv~`?6~?4dP)f%vTcXI(7V9!};RP*XFd4~Bsp;n@MV6V#%G)m0LGsi&s;U7&kbh0 zS-xGt@W2uo2h?11GlG|^lW~gtnfxrRsu|Q;i59k79~)U;=jip)fQqwu_B5XryZ2>h zkI{No)fl;Cj=?+sV4ycm@gx5;fehMkV%=yE!wiOm;tN7NTd9k_=-eYjGD)huA@>q= zrgu%1e;u0HGCg-H{*=N5tK&Dif=Tr8hRfDF5_}I_W^+w(?SzzjJYt${kb(B92=2~Z zXW!MZjki=6mv$%D*|^`}uyI&3WrvH#BM8K7-1GvfOeSRgv-@z9zVu^7o;=!vB$= z#Ta>RVJ;|NB5-9_lXO%eMyxZmES!3|Xr1anZw%SybF^q?28RxQq@;b(ySz(#w!HO~ zgzx-K)-RG#Z#&BjxD`Cy7$`!@SX~hLA;zH=b(W_Qb1T>_FeX97Qz0>CW!Eq<$~0<@ zf3?DBU0hF}3y8ENY$?D`QM#@{+&H|4NjKXBdiF5@zG~RYv}G&XJ*UsbG?&119N8-a zdEYUy7)Xc6k5t<6blRs`LGqW(l=QhLs(g}a22XinR0+m$p#gufRAVE&o^OkQ4JcXV zWs9B?^FKHeLry-Brc*)kghN1-tUgL|e;`m>KHjWI--{)j5T*U9Rtl;{T0_VzRie>3 zI7rz)^WkdTiatAFV`HIe?(KbE?$Wo2h@#J1CQ+McWWw@GjbP+cj5s2LekN@S^c7XY07c#Z$yf zw*IQnvrwlgqJzQUq6;=TLLATL;ZBS;#C6;V7)~e(WS{vRA{MsO4;d^;T$WKK@k){Y zAHdqb54+Llll)CTIJSR@kU$!@e|wJf*_A3qQ)8Aj8h2+c|G;Wrb1D_w`}A2fwLrke ze!qNzgru1?0gAi3XQp})A5^zi_`jHKxW@uSSBVs85MwhFSMG3JwlmlK5<$6{8t0MB zKy|7(Mmnxj7N4c&=OgUwQ2j=48VCu0PB2P@mt7m z6SMJ-4*9)9B1%n!yW~wke;ys1&EBwNJHVsh8;%U+x=M61VZ^R9Y5Mr0 zNEOrdq+l7#q4<_!#@8Ft#urRo($~5$HB8-@Af2V|NU*Rd1ORBym;ia3&;#J!t4I3S zY2PG4bn~C=YmRmA-@gyx4ag69OA+MKzMpa6o6{0v^Tp+Bum4mTe?(P_!5w^?CD$u< z!y=4(y1y(o6W@MvdL~uH&Tu+7OrW{Pe1Q_zRhnZ-vkUr@7rBB?VZ;Y|#8Ee>5KeO&lkdDpZC$jItalHfxYG3Q zfGi4y<9TGr%yReIe@FCK_e-iR+&`v&#(w2p{QxV9ULsXFo=h&wws_$!vxc`FmMDK- zKk+0(5T6mKfR&LUjsxyr+Y{sG);lveIrV?~6CK}=IiVjV)M}n*Iytt-CfUS(v90L7 ze~Q{!UzP1uOk&+G_l2DSwkw4I3g2_MYR z{r1Y5t-&`OK4#XB;5Q|Bb`kV;~Ny*$c8`*S64~`?2Ux1gR zI+n{|R@Wx|-}^G2_56uKqxBWE%HJJ~XI3XFa4|?l;-O5j+DaEYw{W1_|?g3+8 zh-QFXo6I=)f{qd{wFGUjl0QCRWsKSy=E;YJLfvr~f6dkkiBH^0fi6@u@Y=qQ_Z72; z(@f^;2OAGi_66ViQAHhHdtO`@7s;V|=O&T^6PL3Kuc2c0#HUr_k;YSKJa0Hf-!Gf{LR){$7!0oQ`?0}?f&|j-`{ zn;l}3e|SE%3)bOY`Lr5%U>bq7vW{2ePE0=NJ@~r8NaqZQNdynS$rztMJn!q{5}mZ5 zyV^c1|7vYB{SA?*f!gTEm`OnnvwnQFe5<=-Aa~eQH}{0;80T7%Nv&?V6J2R(Vkp3Y zwwjs>cgCq`pd?QR*|hw~w>|M~3%Zx!{g^4-e=A6`L_*>5OoXZ0QyhbjBUJPU$oFQ( zA?zKcN`+xwpDiO z5WrR@`o$g=+86mMoZt6|wZ)(nPY8Vd%^<&O_Xa-8@f~;e?|kR72*4Y5)fuDP(mR~; zmRvp*Dh@5MUSF=cVP}hSjN{6V~Y9%Eb*-ksz+|ROqkN z%X4_caT(8>mg*?5sZoIb0-0_+C%&ZM4XUcbe^z5r zFNgp=HFJKj4$3MibsAcXWNSx|0Wv0_&cnTJxD&#v|8%#|DFQhV_6h#KE$d(2&`YwXR+5x7e<{~C z#lukPLTIMFYfU4<7$mBJP#9h!}j)apm5TA)UN!aFJcmmU={-S>`> zCC-(zniPJgt2fS`kUyJ(t_O!a7NsCBy)wiJwu@ zs;~rZxj6UayvS;uLlIKc54lHyPrS&2kt@7F>ZD?jTOVzhNztdI&o*T)KjckxFD~L$7fni zkGe{sdq()m8tt!;;&2w~ExMYNd<%K}yHrSpVHhtB!MN>0;Ozd3-5c`m~Fy8k~WCbh79)cv{ z6d9rV6>`wM%uR1)8hUaZeqk4u1}PbchUF`&LJcX|>!Z*N;l;@p=R@ROib(-99L+&! zB|64R`_p|5j$-YFwD|ux$d7f9&jSwcm5K!K3qaLw6_xwme=w4B%K9z6>I4mNl9_Mp z;eIMo<0~pD#@8Kcm4}G&`uc9<?LFjU)UQc=BEJH0LFJI6;*B2XQx6344<_m%L?73hmIzA)x@Qhvl_@_w(7q~%bR zpS^igMO0k3e`bBQ1eTrsjeBwtR6HZ`D=BQu=bnI+JPcymld19Jg=3K_`WFonvoyT& z+K>jEw>U+wcqsM_Hro+<`y!|@!KQ7JY2FbI$5o(Robt-Wibaw=yC=vd^)GI$kG<5M zxZL0Y0B~!c{tJMC=lr@{MA;2BB3qh)aSU7ips4LNe6( zLRHl`;3!+Hde`cYOlMtF=e>oa79AaXwBRozi=kFuPf%tk)1062&3PRSG+39A7F9>< zBbsu#kA3jr%~DU{TSL*J9)IYTQOw?mf#sq%itwE4Ko2-q@Tp2%pnPcf6&Bh(Kb9HI zfhM>Jf4G{v%eb-R@(I>%+>NLO08qq&kJ$E&rxWv?1i0_MKQMOMMcUJR%fVB=@froY zvy7qcCMcN>->HrZ9`KL!_#)Mc3kQJhj#ZqgV03xD34YA_@Bt4cyQ069=KOqL7#l`X zG0n`yf_xL%6g{(~0I6K5=9l zliOm8EM;U0F;oGh@)@l18R)8InN$tS)u#f#$ssU-6sC2}Kyhgh>b)c54x1j_G0rMU zf98|wkX{A8Vqn0S@2VVC>eR+}Z`k>~=J@{R`VG(3s|HlH*Vo=`_)G=;HFmmcHnRl% zzHp>6KLCgUnUm}Y{riTQWrIuS>Qs@k#hIDA>%NB3GA1_6*f8+g(dX83;*A|He)S$7 zRY?QxTf46>Psu)ijP7!~BaF2gTPwhme>m-Tqs_9qyjz}!Oj%bv{&?qZ-oJgbKBO*t zHDbARN#0eg9rR*~)~j|jBZbs>PT;lE#sx9IJ8#E%S=Y)T=Apv=sI4ch>Jp4VW<)PA z&;|gDO!EKbpyX%T0^ZO%zwUV|CQ6wu0!k~FQ>|-BONR(m{tbJkicap$LsN3te^4o?!k@Wq1llkj=R#ydeoYqCe>WW_k4xQIq54E zx5i=DVX>_qKb+b+Eh#3N8~>+?t9*zIB5$U1a+ECup3fW^xj!oQP0Q7#f5ru}xUxVe zt)UMdwcy7FAbBu>lQvf%?&kFjOw$EodND z$d4J|C-q#zWKGF}tFT@GkSU+W*#zr%$U97k(vL=M)feM9zH8M*ZzX7Y*py~HyTdzoB;1e{LKW=w2@C_WtWj&8Ngv zsod(IC7QxN<-*V40s*RCV`0T`ILxHi;v>~kF1asB?Sz^eR z;H#k2cr-d8>Zk^{-U98ah=Zcq2n4RyYaS$)xl;QdM5{WjOfL5g4TxW*>BgG(+qPn- z;Gbt;FUu&Sf2}#>(Q|VnyB(R)zuw2Itg4Fr^-KGJzX=}`IQ~4>%P{qE@ij`7bWM96 zb?d6MJPQR(JtR{j%LYpNKG;25-&CpEe#gJulLiC#Omtn;ZSvBsvssUUkbS8Q?sBI* ztQ^r!O_6*lU~VG8ngUbzH}w%>L&JU9eA9=mb@~3je`33j0!}l9Ix*d)(I;xs54T`s zTv5Bgf!lPTtZc}I_VGvi|3-77A=b>OC;J%7woC0BSwo0=_7iy=uQG{reP7R ze-3=esL?EdTqV4K3kZeVQi#JYdnpCO#hkz*=hcF*5Z=k>dtn^>(`p}n{bah6!gx-SirGZpyNXu(!%V+b3yR6XO76P zm4KKl+HQ;UZTc@-FH@VpU|Y*r@Zjx-a&eUMO`R{{M{s#Apxj6py>AZ7AZ6=_gc{!**PE$b+J~Mb9j8n;)`WJ9J1lVBExsDcaL2n=i?$qVdj3MP zw9@ilzCijpV|*N-Rxz{E+^>H+eqC{6HX#h~GbjsT9sE?FmKUN^;X8_k zbZ*^ipRT}qHp_HuohA1%XIo01#o~_-mp;_JD-qGASS65hrvYq)#!^N#e~MD&i(_mz z;uIy4B8!s7IaZ@wQq=LPv{enx#gS>2QBb#$pu^5e_*d2&0qjRS3>Dy&HLii>=((Sq{(p5CK!%Ao<9~QzRLmr zQBkFnBb>Cp6hV?iF3~_7*il;#t=Z!k0s;aU9ryFY`MFEKz1#+z3~jSRZ%0LZ(E^c1 zMuj2@1JT=!c<8wqkfkBOI7W#QjjW#P0{+`&Qb&_*MfZplxxf*4M8FtGDOt(VcExzL&RrAEbKPCvBT!=AnOF{Tc9wA8uENgUR zpcAc$^M_7dVRIn*2z(9&fi*;>{7~<>D01Up+iO!b<6t zf18lo_0P7`TBnE;yfq{`JUC!2&i~TvuJitp<=4Q04#6O-RPU>{&VQ9%vu>roYG~PN zuzJ;^so015bLL;sujKMY9H9XqP>$Sls`u^$CAzi#DUIlp)+4RC|My3P zWIhMHlHhz4f9#GYwGQ&t#I1BL#lXhwh-M%??R41w$-Y}*>X0v{B}?EXsJD8oQ<=b9 z18N(bN2jBs3yq2BP8(7P{j~%6ZH^Gssn+l5ZVK{Ow)U{lWqSYB0Vw}wprclCF76kD z?oKYzU!W$+3+8>MCx0E6H)XAyuSk6ZgLPOUqJhK6f0U(BkTq_-vZ9r%aR0O!m=#LU zo-N*NYsm#jN3c+o{4rOv&TWM~HAA4Ooc}+%L3tcXH*^o_aV`W;?U}qi*btFVE#uSR zy+WI-@sg8Llq?lD3iw}8O9u#w`%i5DXaE3CZU6vKO9KQH00;;O09-q6 zL;wH)1^@s60001&FCYRHm+T+{34b;-FfcGMFfu|kGDSf%Hbgc#E^uyV0AfI$zll&z zM-2)Z3IG5A4M|8uQUCw}V*mgGvXZLzZ zyHwKKg%%(*AwWQy2s{;d6n!*N0YRRCK139a_&^_zr+{Jsp70m(DMdjL5PwBMYNUpa zNgxS<^qySb@}J$kyIjqsahH(!h?l+D*_qk9+wcBICp4(lpy|F^Het~ShZyPTYeO<}gh zS)Q@O6S3ZJQ>A_5tv)I157GWa95>!c`&^y~`)Am=%daMYduN_`@x)E5vti4P8MJqO z|ET+Ef17vmmfeXs_>wHo-O0DmloPT2f^B|xrqY-f#fxjE{4M{;kbiYqPMYSR@z$qp z_a!?$5x?hFj-OI^Y}6;&Hn}jTO?P=BcIR%@c;6Yz$NshG)VTlVHta+ke@muab^r6t z)e$5h2;$0>E5`R>ec?amZORM2DKEeTX1o7%-~Q8KHkjG{eEs)VzGgQt7a0*P%5Qsn z9A*AG{@Almj(hTCn}7O7$~P|gY@?0LJSZx*ytQQuv*ET+sB+t?|9$lU%B@ohwT^%7 z;1dlzjG*ub&=>>)(MqXPiq%Kwc(5G^1fn&=D8<>`Gd$f41Om~j;k(Y#_SwDnCr>w_ zB}q+9y?*%*PqzZmzGxRp0hu`NaZfh^foQ|D7o|WT5X}K81%Cp8a7|;BB5%jEH^F<` zrbIrl)*v1%=o>^d6-P<|e@{=WO|N@D{g~S;{u%_t&hd%w;ma;~jSgdGvQ|rCj4bOJADe`j|5- z7Gy2mpEf<>fq%9PfoP31%=_T(QL8N88ZWbMOZRVX^p%sFlb$d*k}Y#o!rIll*$cI< zOw(KLuE?b4%w?|Rdtc4?I(pmEsIO;_S#y=i$VpF=8)H^3XerFtanR)*IPY#Ih#%Ir zWWwgdF(oMmu?z!6K1W0Aq}*0 z>&k?`+NA*8g(-LDq+MIimAO{AA#M90a2E=}$}`uNM=GxzXP$96endGj{XYd^7abuKuwwP}s9WYFMA3y$Z)k{v4-CqPUK;oEshdl-pX1>Uf_ z0-dRz&3|4d$#i9&S&_7O7ciwn+3MY08$oQu#|yZl9DGw|t-q2LyFcw(1m{n!9@Zd} z3em1#lV`JSmytVGxm9)q7emuOM8+376dmqfNw)^5)gG^<1U;G}s9XWVJ(wgHZ zmMJ!?1*WH_r=>ENR{wdNvD4(nm~X-+FUCr_>JcD^S73d|TI`LAPGa($ zIt+};==hL`!B&FUWa?3T1fnrCUMZOCeDT(kQ=0DFo;<#*d-N+hloWh2@dj+7!|%JyxJQ;g~GZTghP)nk8%O)U<}gx5*3adXg8 zlS`k>dLQ*4*nH|&L+4kZ>%AP|(^u8yVR|%etFsYASM9a`Fr9o;+qu#1mXcINyP>_# z=60@zb#LpDHiuWB^JA?JbbJll9)DshhzNv7X|GDrp0QU+1i}?aDG&&RYubfUq^2T6 z9)V~U?LsNg3Q=u{1&dzau?Mk%`X=;!HXJXoMoJoM-IaIj*<3eXOIkZlp8 zO;KEU&$I1t1IV&yE3}7SW1GXM6cj~ywjBtB8T4yxg&38BrfJW%!_DXohJPxxMk190 z<9V|m0Q(`(rau%(81#gIk9o^vJRZ-J&24A2w_jtMpq(m3l}g*ce+oemtUNH{KpVBf zyv_WN0ie_A?qp}xR+oha2jWu^LczeAIITGj$!CyZv~i@qJ7zWLXnUp z3AMHs&}MO))SIFICIpMDhk<3M2w!05_Nd@o-57uG{Ck23_ z4Q$1NauVV@!IouZ+zJa067bu_(6R@)lb!A7=YQ9M4&mXrNF;(^ zy{B7*Fe?S+SScuyf_GKI!2E%iib_MC`?IoXHI3{aO{ zo6M;O#knOIR45#)sjUeK3W3eb%FK)j3&Ak-+kJo(6%`u{q>s0^TrL+1*zW=1X-s1u zPHYN-q~JZ5APJq`P=8gUxwoKmo zg0@f$?gg->1x1yWmy)C}pD&1xiMgAb6BXJ)bp1MBtI_sOqLGQw(v(%y95`F_*4#*n zy>$T8Ptgi+(N96s%mu8`YNhhPGuN}BqX2F<`ffk|v0m(@M}K*?7V8=@)~2A$-Ujy{ zXH&4-rUcf!sI06gD9DFilCPhiKp>?4yN*{z_{JsZPp6eGUeMU4BI@VVwL-aXpz+&b z{voCCJTCevpbyXV=~1{;CWUwXfWR1mSf-_UY##zN%mLds&2C$~!W7nK2Q;a_opGIJ zY!>59+k>@O!hiNt0AMsg>IO$Kv!zQj<hOLdx2T}^p6mVOKusGuP z4+F%dzJ5e)QE4P8E7Fq6iPKD-ZD&?Iab(o~G=Fv(yE7|R<^j-vs~v<--uIU$ z*5#UaZDb7_f-=sMHBE47Uz2@WCoaZ5NQx#YQYe=CdiyX_78}_M&0W2K?Ik3gk4m_w z7Mo+Z2^pYnY6h?}C9K;(9(g~=yVl#=P*Yf5SuXGFawT&%w z?|-W|*QQ?qW0KaoFdXcI5+yCpdN8UzimfV+k%_G;j~!;P(gn>WMEhoqc)AAb$2 zMO%?wbMFjE5SaC(y%G$N2E*>1H)*Zmk3a4_K5|Gy8irv;zk~ZNLQ97E-`HOP*e*`? zcY64p&`_RSQd?bAQ&ECZL5V?sT~&7Lx=m>*%S|D|k`^<1F|(UikR}=lG$UD zCc0Rs+b+(CIWk*))!9UEn`sfp$bUnSB>ebsi;fCUHU`1rqDPZv9Rub;DFWZTD=i{I z$!}B-f<<2=G#i>x3#}@+M62(|#YDx%#dqw~*>WF_0m5Jqiv=33VdLi;8q%Z5J^jTF zxEe=bjsLM2H)xtXv^+dgBo$WH6xEg$0ew(X&{Jb)G7(;*F-@nS8`MROc+j}?KA4$FUfzBRKOf6c!-hkf`~uRs8R@bX z)xFa`5^C(YDL?;o(96pUF!9o}YgH<4FQXI$k)Vv@3&fyd^C^roC0KYE`_PxogCsOb zA9_6^+DpPKsV>r#7t{LCWPiz!c}xc=RyXUy2(<0LjNH!o9n4)idX}^JKv!~H7#EHY zJhNf}_$+fEGA!@k$TV!Xt7Nma47yqF?mhD-X-WG8yz zfSZzK2@^SWVqy~ahUtcc7qElaLJ?EuPV7G~X-~b~koG}|BDW?n;f_V2i_TqPOMUb@}N%XnHFZYKmu?Ig6B{RbU?b zaNL7H(#&AO-MiU5fgmh2w6XmZ#(9&RO+k`Pt3^|Ep?hcLh4W_%?%&sHwKBQf+sEf$ z|NcOu)p8j)o1#-kC0D0?Esh`OV%-fsk53CY1EWqX=nGpy27mvBUwELZKv!C5(8i7e zUB{7XwcN|g=&aac8t=5kQE)S3cZPk=dIJlkrl%RV81KeOQ4V9NMZo-40g%lVSsZSC zU@I6&Ev+?Nx>Gx1AY*GX-zE}@R)DLOY*!2{p1S=h!p`qhwRm0+NrmTe<$bWbd=&u!ets04+h}#C zjXj#|S`bdZ^7?DRaQ>6y|7w2w`KO*lsfOj)F)zl3~p~!&}RM6 z>kUT3f`6r?+MxGMuI(~ZB9-?Mi}~zBN)+cwYMwyE3Z zX;R}>!TtN8K>^%~74_GJXaaqda?-TsF*mK-(=9@{@;=yML#79zb3#n&OHJ&jFfKCZ z{Gq^x)Z%g-UC#Tc=UmM2c|56r|LwQi_ok8(d4)T7x-a2**4$8d_$UATC4dvSK>xHyqSPJhu_ zZe=>=6*IlEYuMGTTgN_r1+PY~ZbsSs~kEnEiZeGIqrJ}~3+8O+!R^ge`q8p9go z){0qNWC_0%Hd(Wbsf^uub~2>1dV$A3|eW~;(=3^B$!;9+tRofuTkE~-vjJN4$d2mqL# zo-oCTW9A&d|D{4^76RAX*o0bYt9YM&yv{1Ou`b*)fm{4iED|+ji6n}ms%vWWI=x&j z7YK#sRkPSxSim?e zF0UZ<;7)xu3*A8*vJ+2WW-J%moz=EI0aqvZ>Q9XoZWm~K{riAu!D1jPjt zAc;S(klWS)9H(Z#PIgM-G=GB2!sWpj<3+4dt99@X>hEZAOiuuy9?jN6dyI9i(`q|} zg|i`0;Z<*7pK&!B6pU~{DX6Z%gF_{qdsg4RNh%Xrl`x73s}_t|!8letT&L3`rD$<1 z+&$D!(OPJavCa)7Ary%TMifj}KKqZ81LoB)057~t#wXHz0Yw-{&VTnHjXBM?I6jYW zAPk;8mxmIQK%jn#Rz!QWDYza>(m-&14-^w)y-qR+_%!&1kq`|qwFcU0oNh)E2u>+jGlFLOAPCAl z4nlP91(iZ8k-$yv5R4i9#rXmOj`Mf|KHRLWsaDt4diF%xCw=?$@^lm09Y&?dy;tnn zc05q}_OVT2eGRtrlI^V^jlGpz-z8zt>+tNGFq`z;iR!V>@PBxGp-?1%H#aBi>>(OR zVp9KW=9T`OQ(jp^(m0I?R2o9SNORrCo|>Ba(3`-mlRBH?*s)`tYsQ0R;<(3cQfO8w zj1B;zKwZBF$xV`AIw;_)PNy*#41QVHr2|HSi>K)EGkH=k7Zq5=1T{tCvWOBoX+v7- zAp6jv7D2kK0uJ8$YQ}#GFlWT!O|3U{Xp?D(SlqsSTO<-mrBe86`6S+kb^m(s4MaG` z%KJEa^r)xW@j$tL`45{E#+opXiL!PCD-{NvMg!mA>RREAOMd_TiCFU*@yBoE(5GD2 zVGh!9a&_X29S2ugq%Z=}e+3kaDCeO=BLC1J-Ng78?s84LCA zyh!yNMEm+TwCI09gC{LGo(rPuQX-~o-w&p}x#RAtdJYR8G77wL{ND7b;UG5$jG7v0 z8JFBLOewHT&zZ|uCC~=>I(nO>Ayb#rvk^v}(Lgr@(Ry&I6nD?QP3TlUu`fB?YaR(u z7yW$o#}Nrbw*D;rs%T8+ z({Y(ZBC&sYv?1@;Zz6_21K3#@s_MTNoqPV)FVoZ&S;`?>1k#AS3-4ML)GEiq+36Do zb0?-wub}}gmCFTuA$I#ZT~#4X8O`PNf9Y-YtYN$}zmUm}SKKmUmH^Jb$lKvKTRkBN zS!3kH@`#*_@x$P?oyR6R2va&`*u*V4aBp_}u$h0+8^1gQqV8rUL`FKu>G=qw4nZ=} z7ICT+6mvN-K{{l1PfXtYVtMDMW^>y@p^$!Ld&%Y3vd_Mws?6#%^b3)9?4Q5Q26U^Q zyhximDxhNM^?GJyaJe_1$9x)spT6~-JO>jR*T}?WUcqmCRQSd$n#ZSo1Mu=9AP@nu zgj9bfT9sIT6jCk(p^HW(GZJv})Zv7|+v_d)ZVdP>_spG)=vhqcvae6%0_CGqV6uG# zV~@uTvJ$eETC!Y0?9<%#koyEGD^XXBicV$ZK)kR9?#$3A9Py86Gs%Mzm|Wt zGr9MZ2YOFDec^{OfF^NXYg|PRo)(UC{S>5B=4CdTga^M7hDH`He?fosEGF{;VNqmA z6xq2qHGBeIStk7czeH)iw9nw$ygO9q-Y)8>>yqfUbblHT_;U&%R1`>;Y=3jr;6lc{+{~>N4bKa%z8ivTbGu zMOkDUwDg);S?qFpJi@5Q>Dr^8r<>4Fh7KKC|AZ0Go{LkZprJuQ(e^e)MdqbJ@9#VF z&Sc8&;V6Ydf#X9k!Or|YW~c2O(PPw>ur7alPz`S$jQ0U(kw`3}Y2MG@2~HfqFr2C^ zC1$=t_8#o)C=BOONy#87*;#)EL@T6C%);2c_os$r^WeES@28+Svw{t~U?~bT@a@=# zxn>+aM(OSCjpIG&pmNda0qZhPEsSscSu`4WP6D1- zs?mrxt>pVE6tAzXKD0wqQ(2EpAQ0^t=lvA4(fhFPr!c6h>UkEJ87qGYjR*a<+&w<= z`ibRHJ?7wiq04r}FFZvrY;5D3g|xC*^!ZA!krNd2me(HHqrG%mw`{#zTYx~c9h~=5 zFmAkq9!-%?z>(Q~ctWv_O~I^%!$ls&Fg6UI0OKpPRoSFLZL1WV{a}8}84`!)Vq-Re zIS1*DqXD;Vx!1mZ4hw%VTPDkID8~R;mXb}d>2k*~S|}0=4}IhH*k2X%->&}Q%koYC z(!a0_$Q!?0C|X1l(LQj|PhoFUqeN?tT`{n%3prgTmwi~^Che(r(#nr~CcST28c=gcusL*~Gu7%`c1 z(B>c>Pr!IpLXqzF&60mDR;L}+EqE71Hrnek81w=`L&K>dS_703Pp*ywuM<9>hnd&2 zZzI$R;8k8+`R0Fn}L@ItXe9O$Yj#y2dvzG z@E3)D5H#VrkQq1|KErau@~t_thUHuC={w65z${6v=3#$iP=KFhU5)FfIQo3IN8a5V zkTk5@!VTt}nxeZGRz8!qY%J@2&^(c}_gmjo3VqlGZJYBsG?f8el=be1-;-9WD+8GC zgcta{raZl7APkii6+)p9Ew|gYP^r|_)vCWdHPM4@IQZjUwYm&iqY_DTpPba{4AZ7f z)9G~F+xmZX$KH%Gr&w-4yuH2m{jj&8Na1=_XxyMr&)OVb zmXkx(?|rZsEePhezn4oHJ#G%zv}x1I^-D$@y^paQT?~g<6p~??ZY*l=p_k`dt&Rs3 z)X&$arlz*A;69I~;nEI2M{eO8i9`Yoine7yA_#wiP}xPjC7GGJriTyMFSPDUwRsEb zdZrrs#hZU2(2`-6OXEScqDURIEZ}dcnZF+%I|Ru*j$neUsw(^ZbKi**g>iAFYOUnJ z=GEbbTrS7#RwS&ipMqlhDXxFKpzP9bTp~pnqQ|`yJaC*#H;;Xoo32kOPA^hoi35|mZma4>Un^WvJfFtw7c|U&zX|yRi&0lX`O62I&nB0Az`*s~D?GRhP z95PDLfF8{{V*v^Tz0tvT{n!*@H`dA}w28Sl2se|NnHe4)&cv+8>YVg?l%htZ`{UYu z%8`j7x^YRgV{`2M`5nfOHzqr(@c~(&_QiVj?p?NNQ_U~GguMN>q*vXVqc&EIL$QD0 zcG<6T?7W|X;vW5=EHxO~B=OUh-~VNsa>hI6^z&~$Dcv5NTgbC(EdsTQ4 zN?|jG!fi*TrV{1lca|-?``mNBfBk=J&?~QCGMVL3&NRYYl>NL)=lvA4aXtk%N0TdJ z$Tr5l&)l{metN1or#z}NMG%^z+@5dmy!PR2Lv58n?jsV2DU#{YbRZOsn`PzHz*y+! zsalAKi(VEtTYIIjfA#Z{@Ob#XwNu3co>l(^+*dNXG8`i_tvg0*u1&+_uqq;E%O>N0yxnKOUHyOun|hZ&ZnreDa;lGMHt{4Qm@4Y=10Hi zj&uIa<>|WEc>B-D$Z+9(c!&m0ut&HV`&E%2G$kb^etv#@J|6>hGGVqTfL-?l!G@ai zk&C>fBHP{yzxcp+-Z7Tzyvu*nZ8il5E|EmO@rM6XPu+R#wfnEUA|E<5 z&I}6BD4T*X&AhVd1iJLj1cSQz^t|5v)}Q9Hi&j&5L)yy&;6|T+9p*{oXXf`I)YU=D z_8YyARz_-Ss_RS$x8wf4q#HMGbnDhlp-=#`Ojrwqy%Z>Obk=_X*x2!r=3!O2 zofyfwc1_&3uW-wjybnIOGj3eq!iBz*CfW3EnzzkIH9{%O>r>b$MbCGCFmH3|F@IYo zko%ca`hRi`Zrr?ilN~x~;K{lV)Vqn`7&2rCw}F}N%uMt+YiWQM2mE`r;J45Jn6EYH zx{f7YIrPD!aZ{)FVi$k^aCSEbj)qr(gUh%@pmn;+efub_7H(@Zj1vV)_w1=Ual)KO z6dvB=$dT+f-Y8nNs`|izkknK`OpHx0rln+%r0rBF7xO8gv}9ytILl)}fz5k@SyHMs zdLM|^4D>3Elbf9At^Us7DfZXb0{PjhO*O^%b%xZLn zInFAoF3<1TEx|Hn!J^llDn(F4@9Z0gGLAl1f9vak&{g^bC5D)hP%7(xhNE#jGO^t+7uWhYyL*PGn}Bdlvtpe$ zb{yfzks~Q7DctM~+F$_uy4vlhqeBRSsHmv$^Ye3BA_9Mba0|^+ipJU$oDjh4A1X!e zGtUUZ!vmKt<@x(t3WRxF7H&Yx!h`DwAX*QF#pM(Y1bi&eAKf-QgIjG1ZY;{!b3u|} zGiKy0Sl~Nliubs2W<7v=xv^Z%D``&i8jg_9(-R(fLLT81%b|XpCyWS>D9pd-a4*6Q zxYecr7JYvZ5TC(=yY=mRcg>pnbLR#vU(Sz+Fy}E({BVO!!3R?9-NzLEnlf#=(5H}u zHDah2*28Et+TyZm4A9}BfyJfe-oAliu~;INRa91s#UcZV8w>_tFENjYz9~21ZkqzW z>a(&8MMbp1K&n*b2M@|RclH@D;NDwrNmEjMXU>1b*iKC@C%2AHb6VICMCzo0k5V^o zRrd&s%efmRmkN|!RHx3D3uIo?MMp7-nwQc)F$S1$WyNPy+NhIhw0iDZL)!^F`rIAS_8j zLgIg(Jq4RL-=8%rV963;Vj{*qKi{0TH4suGhXzbdO;JkB+|jSPN^|iXzi-zb zVWGZ@I%}lf-eMnbF+uVU{(Sgy-XAse9$EAqx-|wydzgp_4=yh+3y+BO_4S1sA!dQM z4NfwkL2>2sm55M(PdBq2;Z~ahaL?q89<6^EGp6?BNn9lIPOgix6Z+zd{$s}6UbYMm z3gXAa2s?M?ckTLM^@65Tx^=mHv6#lZPM^M&+&@OA(`VmRckL2ZQbEnT|2}b}9P8YP z-=haFK*1Z(_wg5I3^{l9`QxWPy-={rJFy6txvm1yBm{guG%KMl2!%q4L{d|uzJ7lr zr(;4mkH>>D0VU)3DZ^vna%}!30Y%as0{L<|sI4s<|2QpfjWO#U0z6<-Sawy`T)04# zm-~$z36059r%sU-71cgILO(zFGvOB(;{*Y3AYNWx+)><|3l4=s5fv3xe_bvK^$EXp zvCvyydp0e*ckghOTAg*LN-XyE@|J&%i7X#5=t)^(S5bT{KQI7R433{P96etC{%YM{ zMlZaychKLa9lwzCS%=Xy>eOgaD2lGGsi~-{P3YKFDwV-^3Mu4_Ux1`mJO6h#|1 zRvkM=R8$zs%JSZSpVI003dNC}oKd4kGgB>|eA4C+`-K1@m6eq)YRXzaa3=WDc}Oxp zZ_)VS(Wg${1z2(RolSs#JS$T;_|c~V0)h>sx57_DR~FOPZ_wGfuu5?9jN!;MyXbVf;ybx_}OQJr%k&#X_CO-Klb1MCRHk;s;c_fG5UY;$IT0$LM=FO z-~jwVnAIUNGO|yfKIRD*JeO-~$1gnPc!44#lW%_CyK`yElU<%&vm3ts;}2%tibDqu zNhHaD7t!(6j=%T@^;Y;qYYpOxDll^@{>g{r7hBcGPv_sdCVFfnMN*}Q4yV<0V#-Q< z^74n^`N#I1Z`5beE^&V;7VsBhV3&{;2n3v?A(5&-{&;Ihhet$WF+tKQ6*T_Ta92%! z0aa0nA3Kfr>_PH*^x_4ySX{Mtf33PU{F!HRzW874zup#!T*t4o;^gYY1lQyKK z4yre2-i~Q+g7>yfiELa2Z54Oh6cC4H;3pD-Ub#Qta)H`o$uwL!d!hb>&h{d_q?rUtfYC z#*FT9IX(E~$*-frpX}XhK6F&ITCJw4`jMz8-%*e8=Dff>F#h{V{lTB|KlqUP$D$6; zJbiY?v%Wo(2*!IAGMDrdYtv2T*DC>MRxHR`x<74tL}P!>r+r9G0B*CVbCYB6~&|oull-LtX)2m<kSj1oVG8YiqSo0@5yCc;~(Mf)sv_2lhe0p`z;D8tB;4#rcq3PS{zW5+_B{Qnge}yx#$h(^f;)gX#CfW_| zwkgcs1TK?Rr==zA*n!FA=Eb=JqyYsl72p_NUQ*7by!`UZa4#48Bt#Z+fA)QwMS$xV zFnND0cL6bRK2~OMN|AM7Cs;SaI^(zw;IF&CtGJkc>9v3K7m0cZ6!`>sR<9!fc2ci1 z@cBZKh;flcBB&RPF>HY5Faz9xzfrYbziP$1pZhD6-9|EN7dYbl>VL{svs)A9sQ%t( z*~b9HjOzILOR~9a%8O6-`9A-RJ)>?feW`!P_eNc4P&sqK_qIp%`F>Bxhsu|}1YF9K z-?arN$YpOu@yh=QpPdOmaQM}0S>V@ERt6PY3lpJ;ckSAhu{UY@x=#0p5U)6Yw&It= zZ>@ND)|}Z-|MX+w#xF>bfXC};TW-XZ?fb#BH+S3}G$pdm*66l$|K{ltXI8Lp=Ousb zfy(mPs3Y^%uuDI1dx3@Fz!?#%xDxMu_2%02D_~60+N34Bw@(dk*$=Aq&;m9^!(XLR zX-P>57t1qb()W?)ckI}a>$kde=@Lxjq};&tYLM&Ku3h`V2h(RvpPACnad&1!r1Hw~ zTySRV6FGC!(^3F;ZA$9?#hG<}#FT4O+59J0Cw_Tm`b=ky4WGVh@nPhB)DLG< zH2ihw(4p6_U*}fbvnfiW(J+5L1x-TlLm^RcGrnz>DWm{Zt*frqR|7}u{MB)2@1_Bh zGnHT`+>ReR87Kj;@;*M5#vBFMYnwM4a6nK@OK=Q>J_x)A@dZL!B=nO=BD{U1US3it z9~33f>tG9JgoR%g2zC?{Y^tbGvF(RHXcF^s@MB~y?;Z!ozhrb49NK>i2_f;I(8cF# zUyj40I3L7CS*-<^G68=Z`qcMidg{WYaruW27au%Cb?($@=1fU&u%Wy>edETw;^N|@ zo-zF%3C_%VTH#L_45!qZLs~7tT72A3>#J>F?cKBI#L=Jld?&wf#?jcbE6Kc))%aWh ztS)uS-i_|jcbj$64+DR0?WcgEFBXdn3JRb}X(JY#e-Z8-p8xlJ9>%LKW8}a_DMIC; zxi920%cBAZtBlvh6Jt6w7sh9;XSd@Qe!1?t$|@tqmwP1z_ZyviX_qeV2F-)@;TR9Y zBtoG~0+EU&66k5%ZiSc-&LXHg%BCFqqps!Oj+ynwgnbiSnkTIQmofoZ zrMN%!ulb*B(Y(B<6r*cMQhnu$_pMvqV`Fn~+>jI$4)*g4sj3P-cOgXK=Pwou^}6Xa zT`3T(yPfri!Ek@r6r?jj8BbA;3{R*L-J@p#i_QxNd7w-j8MQxcdxX)~K)AJ^LMRl* z#>R$)h1G?DG*MYu$xQOsRP^53JK86D`_S#c^r)EG`>51a_Sn`V+B^Elgd+~T5Bqpx zr;HoGdOanP5dV129WNRTm;sFne$Hi}tHH%yd~LRvS1x}M0f~?l2`M2T2zV6DBPm+1 zGiY@>y$-s_8iK4MsT7gu5s7#WExm0X`G^_yd*>+*c%rVq0};ofHbcG)HbqKWep zmiAKZ`Q&BpUG`ycZQt|%ed~ADk1!r}ZJ%8^c1OXK@u8RZe4<)yOld>*g+rL`s*sR? zzxUPdymo))kQTm|@_3pH7qfAmJ}Wa)E)Veb4)XE}@{;?CC47p+4J4t{Ll1Gb%xgSJ z&EgB+s;SB}79QOEH}h$_;6e5oeTF7H>T{#pyUm_Yp(buFbp0kE8>(r|U`% zXLr=4m@(~oi1EO)q!JdJbRio+5&9Q}wS_W)%sPMeLY;xnjD1l0Wg4Z!ckbi@&EChz?TV-F}R`~e%2m5;~6mlOQiBtj|MtCQo4SGVS z)iXM-*N}t^1ON2)`Q4x&^_S6gznm*;$0V&~x4M}IL6cMWFP`>9|3of>jeQX@Wo|-$ z?vSL3leH4aR)ca3T;KFt({_gVoppt(VTy$(I0uX!-QnRTN6rxB+!VVnYFc~BA!&jlSna< z7#E2#fe;h$01t{0L6dr#(9t>_t=B7_qIwU+ORr!jKcSBcLY+;fXdqwO+Y1lus5S(= z2l&hOV+H`F92a3wEHEB4L?@$|6&W^c)d7m2De|#C@~4w^kH@KKg6Vfv6Yz%C zEY}0!45$=-e!jlGKJb=65ZyFdO-*&}!Ti#a%ca#dHPBZSiA7S0)Z1GU9i{X2<|#vq z`C1*NW|V@~Gm*DLl%O^!04YVw(pqeafddB~I&{d=STL`<%e{X!Z*XBj0s>lgSv05` zJZ51&o*3F1%wy*8ennFlbT*)^0qCF42@j_!0=<29y-*ORF#PXQnA4dQh?ao+mLVdM z(8t?5G&Dq~)2r3$+S*#RTBA2WL8tTXiEgQQM^rw3qPvNTYYC!kR>!gXqTV8r*wbh5 zu+ds<3V0Lg)~$aVHz}+BoP0iCDwT$YhPG7Ic5rjMaORf8gD$a*wKW*YDAQ_&u9uJP zron`M4=5Tf!X8dFq*94QB33B;p!uoS8{mIxmAbs5lBB4D^58%7BvIm^p&>T{g(|%y zR*X6+S{ir9`+!0K?+gw{F8o+r76Oe6ZYiWjG_>iMZ4G}B#`j_k4Z}~jDGV0@94Upn zF-L(A2n14E0&R`Jz`*eE(29!6l9JN$^5C6Corn3KA!CM0kdC)BZnY^0g1B+xMtFE6 zvS46+&hO{E{9oe-MZDaYgg_`Gk0M&G*I_M ztAJAtp%8znh7XjCi109jfnZj+AqFV?6sVJ;#c_8(1r!UMhp}!ZeLp{+n}*3PZPcev zANbZl5P#mf)vbGXxLsLQm44|Gyl|6Z=%-*7 z^4II22LbH@^9s7TIXM?EUgX3=Z!kbBqq?T%%H@B{DJd!NfU>eO?pT~%bhinWa*^E; zt&oZ19`|$;5U%mS*ay7SRkgK@9|25v1PqIbjm?K9hI#339EaM`yH6jO;qXsCsZ_?N zL8GFg1`HU`*culsdcCoSAlwF0iZ+13321qB6}nVIkvYLFYklpzpp9Z$@sz_7xC zg7An4XdS@I{>1U)rKP1qh72hwE-ouC*J?CHg@sTi^6%gGlFONX4GU?|tMylYzli%c za=~S5xN%m0esNlC%M!O$1LS#{{qqX)e07Znu&(^Ka^?%)6X;HiIw z>f+w_zbT&+}s4UqbV%wjeM2W=j-O-lj>n4LL3JYnaqC}95w5slv!ZwiI<(lOmkg=8xBOYSv)iLA(cuo zCjjf^Gr8?Q|NQgTty{^-$r%|LBuRdlwt4rDuGWoozP61`Eo~JZ(}BY?2UF{~`1I-K zmEeX05p5RF^ivcT7FtRJ6aIr;GLwr@47C8>^WiJ^Q&g!`-+lMpuwlbK`|N+SzJ2@V z=H|Zr_S?4CdA%{j=3-+u0aN;D(2xTsCoWpFiOmi(C>Nc!Ji0E0UA*&4Fw-KxvTi54 zuqUW1f6l?oE-RUxrdk}OkG3q|T!KY=>_1TE{I0D#ICaQmH=%Hh7%^hco;?Ex4%F-Q zmoHx)H*VbF!-t^*0!3u)+O>&^iRaFp3k(cAbm-9j{req{YdVi11`g7+gDcGWfu|SU zSWeR$0h6R$lz5OnHJZJ?<{pBH<`mAsVM{RQ2VmhTdLg?3OIvej;SzsS`I)frnd`WX zmFt&$=_Gx0!Wt!0m{F2ut{?lQb@?_J&+imew4DymceHhT9Jb%(XTk`MMX~U}MaB%w z#{wJaX|33F?f>Ko-@#se!@a^h+K`79&pb<7Qc_}`b_JzDtJQKFdUoK0i~Yd`k9zOD z_d-KMOG`_Ae0-qm@#24rFLvwJ4N8fFLY>DD`?4OHaCqQ=bxVwwM8>rN#>3;sP9Csm z@1Z4K%qbQnnDPUgJ9d|>y7IdW7|_MIVO6hnI;;`i%&|?T;^t(6E>`7Ra(aDlO zpRY}OvVep3yZlTJ*%fQbz2DRyP-%>nsSVpHbse`SB?(5*7Q)N^flXmM){ zG2>wv=I7^ESy_p3q0fVZxhKup=K{mwc0oY_d>a%Lv~%Z9u~-cAz|2rwVq;?`PoC`I z{)NmNr$HB|dzs5}=j2TKRD8X6?E0}W=d;$Ybe*NBLSJ9qBz`Fw&PrcIj$oe|fMhuOstV~lQ>cTt-IIpPx%Pmkda zhj;7KbC!=D4d#qlc_3?{Q)}CFvt{yw$qlI08jBho!(4y-&=)c8S1vqta4t4*edejL z+~IcTYttU4d}I3?)I#nv89f%Pbo?pX_oK&7#C$6bPs59AoVG1GiF+{+xi@!(#}bbxJ- zVEn@6iN>7+=FDmI11h#P8hcD#9l$hb;Eg$eF?MXv*RDOI&F!zRg*KlF09M7WTUVEX zv49?|Q2cuP_oJ03#X@o4vZPUQ!_DbMwZ;Fr`q6)=ZX-3MN?oNgs10A8`}(b(|8P)5 zJ>kOY$6{Uoc8+KIDIy~yGua+Z4jYF8zWw#kYm>)E9XNb8FtEebt5;um;RTFU7A}UZ zd8IrnoW~F|_31gm*@5P_HiwViXzX1)G#A^O5FbChOmh&)5|A?%e|xqn&?zbyQtR_a%W4ECdMd?iSn~g1dWgcXtWy zF2RBa5AJTk-5(J2;qE%`b@w;Z)BUYkzcu+UkE(m?9@%H_Q}CeLf6 z926XCrn!igBFKgO+wbDu;N9wTj8uOods#OUzw_>uOS+EeF)S!zzs#rbk` z^Y_&u0C_@hl!{0-AK@*Ym{nIN>C=;N&dWNcc|L0E9lJ6n;mPB8K_X&SQFJ-@krAu* z`j-i$%#%7a+*49J7@72bY)Hi^nLR;@^7GBx%=C9C@lros^*-Lw`B)5J6rO*bMYD%C zLh;tJySb<)d#ntU`{OGB3q zV&kMLsi=B$AEqwKb&p>8G0off3#-e9eYKC8#D&GzrT;Zis>$=xZmOD?k@$fgx|j_7 ziF6fY((9x*9wA0VWT?l9{UX55jz@g_*AGk8u$avAl)+G)!~W$~J$8EL z{xTXj%Ko;}98o_<;xk*opA9`n=kB&LHY{VK{Q3Q~HS?RXd^vpE@u50d@Qu}lDH4Zv z9PRAvsx?LtlUxsGOTK@9|1J{x;rzUVOj2E4{nDLx&&t@;RJa%_0>P7{gzvH{{Iu=o z{ppl1Rsk2eFk(4H(V{7k;0(emz?}=gDcSed+Y*#4^-avCp5$ob~~< zhdyc5Sll)oy+2MGsO|A6B|qxDo^^aO=y_{F_|+tPSg8N6&n0cUm!SgTO|=id9A&#FED53C*H%O6vlY5{Gyz^euGG1 z!o_nCZXc*^17ClymE{6V>6yrZK549*=cU} z$l`VjYR=2wf(o>Z$>E=`H){O#>&GrDR)8QYB1f#xCoREhPX$fQc)w1;B}I#)QsZ`{ z6F-Qb(J(Jw=WD^Y#$_b=B#utCs2{mq4ws)@)joTOSt!M>jajfj2AD&h;6HxxB>t`< zhya=SbgzG2g_sl98`?kNtA~u&cNBc{Zj3ka<#BA?uhY+3?-esw=F{QMxuA!broZ2J zewqW{mv*a#Dl*sOwM__sYaP0cwytTPc#B8v<%5*0byYenTuxWpw z{gRr>R*J$%#{Nb~&h-X&odMG;d_Ai^F!nOQLJ{{QRv{NQgJsZcdb{`a{?p`OXqHE} z`TN!%dabdQ&|`rSsFTh5CBa|6@eW^BSs?qdx~|1}{!Ei3 zcd=#-*MlQQm;Z+0u6WC|z8HVY5Rv<)E_5q|ga8u2cf*wX8iXA??vE?)cjhbwOiCSS zd)qi+mi4;1!1%&6&i;_N_N6Js&1M5N(t7$*>hinNBF3toQP`XtT^-|>#N97OKV@y! zmj&HF-i{YTT(z!u@YFp1`VjG#Hdj zaqJn$C4W{`)1Hs&zfga8&m>xFk!ldlSId4IKO&xBn4sr#k^B|&gH{p3T_EWxK>#kL zZMH^ZY_q>pq*KoQZ)_-oPrxMy!@;Z`o(A$fEJIkc#Q|=@i6F>J9j9d~5SES_>63~1 zHl6my>fQbLtZkJZKoqXt&~Xu4{E|Ce+Vj*aRVF>lJy*zsNq>JSILGO97^OpHB{za{ z97!?AEuLn7`%Qhff^g#4&*Dm2q~$|301-d&+3Z&TSBrw4vaj>b)WiqBhqwbT>gaBxbQ)r55*0J)+aKSp*8}7~SfjV#%r6X+R?Q9|<;my>nU;nrj0hqVT z3NRoy>GvjpH;FQbBOyutV*{qJqa!3NAiql#(}TbjG%pH^U#V(gX6zF0J0A%$tU{WS zC<2HH`JLBMK2SQIe)p*!=9j;_Qg!iYA{e^~(YAky7#f)Z3wx%fCI;da&&=A zHnD$)ovyn5%YhiXP|Re=u(w+`F04#48^FP>jSq+s_@Pzw-?;r}AWI-F5w{#@jWsd- z>mUQ{IcyuLH3;9<2DHD7umu+^6f!s%1$o0!zSGcwnK6*SM~0Q(bj^Sq92p)iV8*`U zXVC9ZQB#9g{j!+f3k}(wt4$c{%I{KdFSvgmR^4UIqmhBUAXji{(i68hxyy<>_02SH`H|G}Havi2?83`jH6dNHStP~i5D(oJ;N0X0!>rOSmbt8Q@L`eSd#% zU|=xXFF*6v;!9HCvzaSX6S0c45u~lUs;bY!zS-%7$Ky%x%GcKSfXj{BiDxq*C!E)~ zuaJ<$T4+e+@+coa_8@xq4Gb*Zsx9K8AxGrxj;6EN0-8>1{nXsOlJyu5lcvYS*!Gl! zh_pT+Euz)e*TV<*G$^C?_IWQw2iAWYwYC{=ISUraWzitR*3{Pa_VyxWzmhXGjEu<3 z*()MO5QhlX;ekwTuaiFofpFP9nv^|)^n|>$Z}%KfFI4S$ZMo-p=HB-Fcze4y^_3{B zIOj3Lruz6(NSaUArx6z2!E!9uFAS#W2JZvRX~2wk&&PSsUt4~9o15aU>1TfdnxDFIypzrT#cL@-XY zb8)&}lw_XjXaAz}8eBr#8jQsZ7X=CF%k%SQC*b&DRp(l*nS3CT4o6v5AM%Knz-`xJ zG(xVPu`4zw3lyD2UwVU~JweW()%?Wt`#IqqB0-kqJd59)ax<*9Q#P6<)HDld9hY~p zoC9CO$s`$cTU5&ChK+w~mY21D(DjBQdw1lUHa21zp2Ky`+7G~o$HJtT zwNyF?$smV4ock-edwFf~>a8`dWAsrZql}WcL4J2{0XjP6^jBuRCcsU=+#%H3rV1%4 zP@%ovPxv*F+jABo!{TWcAJc=vL6sebp-#e%2WkK-W@#O+RP}!$4<5ad9u+|tY8#O{ z;?wt?7_Ik6RAMKqt#DH0xk@EgY;0ssW6G>1T%jby7`T^ z5r&&lZ>TUPQ3GsY=ljeC6y8_Q$M`dTndh$A?IPT-U3(5#A(#_5DUQVp&Zx_;3#$CQ zibfx_k__3)O+kOwb;xUbbL2krV{rep%(toKC4R3n$a4_t8~leW3Ph7!;(%DB)Q+o* zU9Z~{I5CoN4eL)>7nhe_S9=>fJ0{w6;MCxi092qU;GV2^5@KMOrteY0G5i?!Hj#gg zef6Xk*vgcVnN!hMwQ3iC*_mncDtvypE-Nh!^o-BSS_OZJ+3(+p>cS`>H%xhd`?z~} zt>_#mdv;(0*OjsFehqqc%D&$CF_)MhKQIQ0;(wnZ#)zb$rOlNwHa5OGT^Hcw#2R`F zx#7#pbQ55pvrhI2(a-tt(_35KQg74CSD)5{=W95)=PS>4xnfdSVY+zZ+V@zWAT&|K z)ZRq6oDhG&!^0aNNwKr<>*vTHPaawqUWuL1tDq*3&C#e@SnU5a==JvY{hmH7myRkmym(NqUxb7v5(u($B+R2c52WVpCWMmrrw+3rG zm+`kb$AiY7u-@|$$Wx(xd<)m8tfW++M4b@sDm;I%8nJ=!sx2R~mFj4et)(yjjwK@{ z1`l~+;9G5^OZIeE;qA&8$uomPnUVxqLV0=l^PsVBbAz0E?W<;&yHn z$D4oM4Lx|)G*DkPA9m3o#KPKgK^c7X_d3S*^^RDii|9GRx31&?N{SNSRBE7p*W8*JQ)nSFnl zT(Ql@K)n%YxE7`YbyL`<6z4P4X!&ra&iaYpO+P})TO!P{{ye(vUzbD<%Fg?hLQ^U> zECf-27B(MJ+9H-cD_HmGzm69q()pSM3DQ>Y{x}p85v2PdH*mo7pjFj!HE(h-sHIqe z7QQ*Q^h#)u)X;g!xs<;S)9IBy>S}+klI##cfG12L|L?2TF}Q2kY+oX3O%IdT*F3>= zB+0hIIYcEvPPP1gqq?}AvakPZjIMO2fvzWuW#mjA(N4+RZ7vft1+OcW3Zz%Xiu8xsi0g1ouTRH}4zmtDurQxZ3 zM4et_-pnU$ir${x$#jVWpZ}<9kkIsH$8BtCRH(7=kwYGa>ZBQb=v_rt$?M5;tbbHG z`NgnDm1wA1NB!~S4LK&RvLN_~CLsCo8}J!Tw(#bjkFK?FT}ZQ_42<<|Y$=*D;^n+)^Xl|$C$j9IjS&SbkWC_AYVmL;z(#n!l{kcAj%XSHLCs)so|IEww`ArYET9sLQ2)HfD&Y zNGSqQ&!~a~tx$GYl?rVyx?$)wGn4gpTXI7pXZxvxkl)^MJh50@V0!_Wne;U2bpk2* zMn?J9(5T1EiuOcEBI-g$NM3#s*{FI5b&SrqjztSbZx6Fbdt;lhGr22>Tk)LbL zSF(BSKneIS-()`TuK%M9*uc0e_D)}>2AN!SDS-fz^5>>ittRo zoEiu@rcUSC8min-4XHM03^0C3m;Ls~Rib2=?A12fw#MHIe;lXNv=2cxpzcP5HK(ZM z%6t`R{xX#dFkT6M+RXLBKvJ-O>=jc0(V)XD z@A2wYE0#{vLbrs2?f{)}4LuGcGv7$Bb*{h`l&82*J<- z2ncR6Xo$&w4$)?Kf5Yy7O7PKyMs;-C!-%nL8H$&P+MizhaXiJlLpG_TgGZT%5k->t z0~z#NLTqAG^siYWcPn1kzhBwjrWgFmUN8HwioDu>pwaW1oo#`Ad>Ic58W|0nzEiUQ zdG)2hMg`H7>2Lgmi1I;*jEVI_#e0oo8>uEP;RIj(sR z28u@GbM-8vpl3pYwC9a)OB1{|HwRt<<5}(z+B$7cQ{phW&n%C)v?Yu9N-#i!F~E4OMN)|wA|Fa@A`u>idp+U} zD|r0oJ0Q-P2bMD{oez{S4M&V1w&Kvbexz@t>P1=ke7dQBJDaqQ_j`G{>J1gZWub69 zI6B8(Z@>9=hh5eF@Iqs6lSc=Q5S9Le+X)zvm)fh$^@!&ZJs=kvGW znzD}z`&QHCjK436Fo32`!qW?Ar!}3wS9zrHC$3k&3`bkgvhLlF;Q7kfyi28EK-`zj z0KEIuIVz-o1d%UgMo>NY7HH^p_d?MT&{k#kYti)~@s=A6{=PAFqVqYXd9c%cf{i|^tcBKS3)@!zdYp~Uw4Fj~p2r0}{wvbKKc$yKhNIJs4S&z`Gtly-Cu!{UIIoM%4eXnfi{JRgd$ z-dR_~v7td2D_v<6QBS+3$0y3j*T83EIj%B_^aM&nU!RDY2)1p7Pw(-bULeEPbNA7! zb{gp*BN@mbs-J34!%~0U{!)!Z(6pn_c}m!Eu`E1%%({J#y`|#QkxRaQ-3&s^uQBU? z=H(K;+Wnn9mwW?FW2YcTnSg^68L#QOr%LXJYi8Di*Ie%4$9wHGU`S6ytX}Q@=-f-d zN&C)n9)3@e3m*xh1UxK7=wtq=ZTtCSqC6d**9ma&qud8koo6R|En5lL1jxXNobl1$ zzR@?D5(o*9i+OQFgEV=f=`>OV48y#Cf*{9z>tkZMLKy!1NZ0j0fU5!dOa}F^8&qYW zoLd-Mavw1WtC-U>S(eS-ocv>^KfT}KV&{Poqb{&^K<35z{9Tp&y|?C6Ayh^7qfv*G zKr_%aenP$!w1yPv-P}tkzU)WJ_c8H9ZGJLEg~bbi)nk*_LTQqm%%H!P@#%eke}4xt zHPNg`8PPQ+%r68xkhKnyJlL*{-!l4E`&G6CO8GQGl2hYAlfGw&k0VNuf7R2_>hIc8gRAaZdElYqfC4#@ukj^Z*hxWyRWJ?Ny*BZ41r!F=|&+S!c@DtS+Nv) z50nZnAQmCD%Urm!R#bD;ApDg-3${ML9@{FjbX2zfFawEl_E39&nKnT^Wj_cp7ohXU zq_~(Edg;5lHg*a*YTXCo8A z+Z)Z!auoO62D$`)<2xz%NzGhjhcV1(9$_3yFF20KXoEH#4SiBo#5Sc4BQeda5`%T; z4^g<`FhQdQKjOKO9P@HdwyUIjSxYoP;Q!r?@660PUT-h+WYDunhgrM8KN$iAM4R-x zu>M;L|I5ukO`iJp9mSe7YO{D&iRV>5f_`uKW$ZX^o&()~^tTCJDGdz>vAhoC7<-OcM7Y^-xecH}~V$_8aI>$an&_ft^UAR(`NCO<4BI9No*#j`oj zlYa8KTED%2eJqkidf7m_b;8ADxSGhk&*&=Fsy~=tnj!7yqPJ=tTpr6^Lc#!XpP!%E zeIBrYgVoiFJ)c!n7Q<0Vo4#S;v92^ux%dWyAESeRu*YDo^eUOwPP^gg)UM4T&5P4k zC&;H6B@Bt*9Ed^kRu^a}2(lv`Mx@Wi7oW?(Or8aQ%A@_mNJnkkJ4_6Ur}E;)N~c8S z+Ge5DlXJ=-WQIZCvy#OD(RU} zc0c4^2eN*eYrpk&%C4fgx|&n9vvkBn9SVkj21U4G^_iV(81vj@+}5}L{6j!}Dj@$B z;D+jHSt7(Zybp~Dazg(-e?NN7YB2;8D6QE}ZmAho&V1mJ-+-o1udHC=w}VX|(?OcdAPbI*dPIWL_r`*=ze35~x(s$*j2ykPWN&{}GpD%t}oEs5U=; z3(HUmEe1*c1z80ahQ3`UK0*LWM-Dvvrfc_U88NRrvQEkez%rGyb z^fv?)^d!^Q@x=xOPD3_<W1IR4;8&m6Z$Gj8}PO}Z~ zwq~d2yirPQ8jUIp?0D^H>)2x1lPz#guF8cdZxWn+7kUq`3eOwZpqE-m$}UiUH_ZyH zNHy(2xIIH+Jnx$GctWaN6c+}Y5GSbT!=}WZ_icKX$0;(B)rG8axLzqq+e(GJa%Q0b zh4hvLh#-Cm?^JKcelXpf>TJ||0|+k6X4|vMl$r+ddi_#e_9vmumRmG=R_HXsU;2WO{JV{Cu#BCanW?$Y`Y!dJpG)*{_nyofL;PY)jX#kc5y2)nb=sB zws-V;oC^1~-Xk=BTSc@>&vguL zAL=c)q{eX|nJ{cIXvnNtPPX&M$A)jT66+n#eg*M@MaQzIS^YUeo>S~JHXtBrEx-K< z$u>K){C%r0;MKP+=k0@0=Kj;+jfrZs{c3j=>Fh`lsa){xK*(wcU}t^>)d4&5gB=ZJ zMdXEQpV@x18+AJNd@J#PlQkJj*Chf5*teS=Mn~Fg46SPa9z$YtBs{*qDuhv9{+M!c%#Gw9iBWhP0Mn$OCmSjcK!^J;48fn? z{Miuo|F@=KNZUqACB)*={zXV%URS&}Fgr0!N|^-QgXlWclS&}|QNV<=v@!1& z)MW{#3&FjCk*3jq;97z<`J|EuPp_EUY!s7H|F^H=*N*{U{FKSTVR1;HQch>oBh$Z= zfCrww_T1oHl$)_NOV3g1^X#=w{=qExouwz@(TLuRsS3BI%1TvN8C1?~m&*2V64C~L|K%*VeN1qc!3&a_6=`bP z31obnvOd9aL)_LA{{mMYE)K>HSIxX%R&y^GH) z;sRC=wN%Q_W*3bSNgQ4RMWfohLE_Z?Z_vMmnu8|^XRTzU z-h|#f#`Ly-sU#MIVx8MJznbLUCYk1^@MRnwpSTjlU0tJ&cAd!LXbF2k%*jv`0~xfx z{60Y$)R6F>CS7z~DBpf4FBVO=G?k&-?;!dUaAjg}SZu7zHELZ*s6_++K@6?;4|w^P ziy`#>#VsjhQ7^Z?bIXTcA}zl8`yaL)n`J0aO=u#2`$_(Cx5L&ze_tP{o^*9}?W5ZK zQ4RiYrs6viD$&k7Dv#DXnU=jF&K;-ud09V1zLz`=gTvnEbxok@ zSwByvP(qTd5&c3N6gST~$IN{yR*X#Q^rN#X>_@t#uDr4(Qe>)PI6YNtYKKj~H3*+% zcho_)`uL?&9wly8>1#)lwwrmK7@%IV{lSWVxB53IX7@ML5Xbs6a4w~0%3ZdbM`pqu z+Mj=vG?W_%S@5S~@_bB5s;@5-Kjzg0c?3?1zJgINvqE;au_8F1qByo%p;W@e){(rk zgnCI4wbO24FOy6gtd!b1ZihfR)FTGPw^7e$aVJ<%`9Ardl&~R4;Jp2e&|ABpxu=DH z-ux2=3@A28BJstW^bNU!3y@*{nd;CL`qsk#yvX;%Oxb_9u`6W@W`$&2KPrbzc=f(8 z;0-hN!!YoVT93ywe}6|CQiHy(<@;K}oPH!#)bhhG6**FalEMMZ4dmAg6JGBJ52ImT z9*dD^iU(tE_92iY-$X56PNgFF-aTG_^oU8<*kT_$y&;4CbYy7vDzE2#Tt6_;)ZbrD zy(NCBLZ)vU1-euF{maIR`jf5A6kqI`&&Ep=&l3qw-{brgoA= zP3oaHn5`?SUR5g&wazZZ-9R@~Vcu}Ofjhc&d<^8+JK#X0YK|^qmOXbh5R_z!cijT# zydgI8BbVom@F|kt^})Kn-NWkbZYb^cOEC_oL!h@2H`DRT9B;A0zU!yTFSQ;1u-7{W zCKftWb?ESsA6`;KZ3cFsy;9JB5?vlJh*6rdk`rus#lgCOQSVCN%WfgU?Ys?V!w%Ph z%0^^|m{i1F1)59S0t(>JZ^yv4xw|nZvE}&N1}-*P@v5jRiZ)?ObR8}T2a#n6c%SbR z#c#zkU_PJWbyT@;5h&{gJl5nHjg*%5xp?|^4&@`QsTA;LB2jqH2Z$>FPkn zYo?|03d*ACr}>cE(w3Hg`N@>;Ni*fTMduX`=n=XqM{D(YO+3w>6kg49U_sPOvihqJ zd6CaLubXk5{99{KP-aFs*~n+y$l@L0AEUm30VDQq>+ZVeDxGkO{=G_#!`8zui8XoX zb#MTOIT#HA$fk;V&730N{-Y!<2F^3G|Epgz=`v37UmGbTq@<*OBqSiPH8=mEoD>c! zaOL3<5fS0xpxPDi<|)x>>Tj3|Qnp?jR1ODt`1fRGzm~_QEwP+KKw0*5s4oJ8q-RnMPW<->zv6jb|$r7X*7sW4amT^C;6- zMVBI8xz(4tv1s-25`|D83Hy=g?b}xpJ1gKk^cqZ|)+0=R#xUzLNp8vPy+Qjo!k&r$ zG*?XHKY-n`w&-(d_pz9pPKzr&j&sn+L~pDm!dOu9cLWNA+5|cNGdV2l-p%3W|L!sZSob^(C1wzmQ?c2n1hg{(`_laXhjng zd$q#qod!04;T6w1i5b26Y*eZR%pA=LgoPj=O*Ey^-oN_fyUyS%qi2wy))ZIGC(R6o zRh{+U&VYo1x}3pg{yNz_Et__a{XQlSiO$4`ztg0zPQaUWhfq#sa*7CMBxKMd6?xq| zo}`-3Y@oV{{j;?GAz%=+Iv0cfS#yOJxHA5ZzvSG1+}ympI^|2CYRi^53%*r+e7ugv zf0T{w^TTx{2E9_*obSMUL`0jFhU116+YBDJlR0ii3$PmKxZ8~Ee7UZ2adDC7J@4bY z1>`GG@ebBCHabCdJRFp%>v`-DzTOSa2}n|dWbuse(-xssy_W6JPuta&$CK8HL#z`j zOk~G@X7Bz8bRFaE?QNZ%#3WE1{u$Z&T|!0%&}gSGD%uyx*zxPQ`u+Rt<)=pFjKdIy zE77s=ocp_53P6dhgv4*=yw1)XT)&5_{kpok5-b0)b>!=RyYndN>FFG6?nZigdMYYOBXr~F1<~k3 zw1>h?d{>8G3m{w_s-7_Q+yh!qsOadn2^wryEMnnW8FQXYj&w^q+ipv>`BTJ)8F^$46HHtNH|uI|%4xVO}PK1vv@)2iry z47U~wz_n)D_<^|-2|XiwGkmcT+K@jl>_pBaRlf-Uc~8iw*Q|H}IXzQ@E~t%J@;S6b z5{mi0U02-CZIku5q%~)ZA|{PU)?`UF{P2p+VjdPmLL4gTfUzLTf8|X|oI_NP4M>hu zp&dU4cTJW_2Kn*bE}ybl9+;HZ@L9xv7VjtEYFA9+*Uw%@O>2G_%LSi(0}_0Ts-W(- zswjh)>yeQ)0q@g^n{c@$&Dt!?A_{PYRxu`9_BVrj25!H*0uC!%V^;1?d@gAlui9AV zpM9dakk-1NeRoIGb8~YoW{N!0Nyu491sK2DkHDyo9H=~`qP0vNBa!Pk*oOXpX<_ge zNOv2dNPJh5?YC=>TjCf`9t(r`#VwhG+pFn#slKR<=d;T4x?aciZtFg`vK*`1F6^ql zCAN|$n-x5k7pmd^VL!<`f3hE+%xQ;Np;C09D<~}%E++)+*fSmM>;W&Jiz?Tpb=FfVpg$CK+-lExReIYbyz%Ul7ak}j=!Wg9Tti@@*6A%99kO-)Tv zF}~p2#XO;!w@2Njw_B&|*QQhb;C`rG53LWZ6Y8jb& zWEa#2q`#fEqq^}U0>!lPNy>E_;Xno5D5mi<3_d3QF2cn~RQSdM7Gq;X6{fQjdd=2F zN6?n0tcfrb%X)-=mQ`EJa|mdmvt20t)te5A3m=v-Q7+6!3I;tpJ&8l2&P2}2pL?B3 zgG&{KZ&K8c$SrS$)HizX7*C}abNUyE#+wrvsc?eVAV5^K^i(kI*^Q*_)jLxmTj$9!!cK>oUac~W|hscYP%z{T+})m)m) zWhJBe-i@p+Nqfp#;LXa*hH{OZfwuAwcFj)Fc!jis!^4)VVvN|Q*JODRS@;kEXR2A3 zc@^_pR|$8fLwC#xKAGTgb$EE;ZZT(|T~xPhqB)hjQ+O%PRyVsYk>d8v%^`wv#i7LY zSt@6yLY19=1&|?Z*tsXf9T_Q5Xvp_h!xR&EnoNV(2ZZH0+*v^*d5nixOv`&D`OtdpSN%vB&BJw1n^WNYZ{ zw}fn4+w?C?4#gBeNdE50BVYFrFE!I_zC0ZV8>M0aO^)~7VrRsmL@MJp^Q)=vn@wM~ z+$)~7!v)!ydMxL)@olNUGOjD6>?~hj9pXQKtxSa;or^9vvGiePgS@{sUq+p(fZ&Zi zaFzcb^!fh}g9ul_BfxBsPbwML9VV!g`Dj7|Zg%HwhZc)INhXyryl23|6IKcXWu-L} zA@AzT)mw*M&kZugF%&bJA#j7}U1$jRPTnXPE}p>x)*YCM{sPL%yPuX*DdX>_ONNMl zro(}58~__(dsT%B7C0|Qv+LW8CRb1;YVuw<9DaxAM4zd!z#VE)NL+VJdJTH5j{K&<)zH5iFC5bMaF|#O1qBE zcg-ggBu~tJ?YMkkkf6sHFO0|h=9M#l^3WPv=_Ia>>}GJ`sN8)p8_3q*ilpr{;gxmjclMvi-H&y{sllmaP{b$o| zar$O_5Hng_ES<*t>8|8bx1AfKErknR2tNq(3}z(Bq0yRKY` zcrWZE5Qj#@@z%&20!);ic$AZ$17qH3*3x& z1&Zb;FdzvuU~Da`$cTGf3(Nh-wrSNkN838Zu!=6G7b-=|u@%iorIb#wdc2lbMRRJU z6Ic$rDH~@7d1!nq^@uLKmKi^&Be48Mv_|#6`@1v3GC{EoDn;2i7M5 zs|Am-Z=3x~%f^Sc8!<(F;B9g0OUw5j*{ysl6XDVe&4;x|q#`Yo0Hl98=@vuRZNV?> zlI0syJV5`{Rz46anQhV*&0OSWM}j% zuYe}C#fibQrtJLArpi)WgAXQfJOX0yzBGUWd4-)3JLvp6Y^;5~FP>66AOXo944JqACE) zqRJe+7ILkQ1|%gk({Yvz=4yvcRW)li{`K$JBtW5m!Wq@M^MI;-&`yBEVi#j5T`y-n?1cFSJW?s_h@jJ3J*V%{R8FZB&9%oCJ#t3DLs{s1!!7WfmpD!{DYRT41Q zef7e>$lQ(vnXQwlEzsVA3zL=IT7C$CE$@1dO{!4(F(XpVLj5B4uEE&^&w&uR?+^j}4%}j0MqSQ4 zwqNbiOQJeUs_tRGK)f66Z%u5X+9lrQVu*jg0;8KXDE^4n zh49ZDl%96sf7#zP;d1U0Bz*e@TNdQS|5a8Z*GwG8*jei%!qp0Nbl!+#-kCDAKQc!1k(WP z{eQNby8BC;Q0FlAneB6}Q#P$}$DT4hF)*n!<-?3Ps@EYkzlf=Y^Ra+92X z;_eU9YqcnT9nWz$w3&g$h^enH@X+9Yp`O?A)dPc{605=Qq^;cgG4}8E76JpJP(VWn z6CewMs_<>iF+HRBmS|&+A*nwj8OxlBDETLysqP+_06sfu^SI6ZRx`d`4B6Ms>Ldz73o&*a*viuU_J# z`?h|wRvS%Q1lylh9<%=bqLoPmjsNte;J{mOS7c`;$A@~;nv|Y&MZ1!Inb_K~ELH_& zf@~3Fdc0{qH5ekn|0joHdNl!>=RmsuZ=ihk!@#~sL0JPJK!E;9iphyq3V#XwUrC@fkeBbFaA<{rm1Xx^H004j>E+!-k0DK|`0Kod7A>Uhs5~KCszdqXuh|5F2zuckq zgWv0f_QJ~cg0jLt z+VP5$JK7Er)cF|2!KxdUv5)MKX6O(Vag8@I)pvBTAKB)}F|=~hIDFE{pL`3wsmeZm z5?Dx;HC)IKpKMd=dwHdjv^$_^$};8p#);hI%9pPWgbY7~ zYcHV3WOyEKDjD7}WY*uz8^=|;$-IPM#QoM&7(cAm{&T0cpEgs?PW_x!Rq!q@Y7|e& zpf0fU`DJ83xa9Juk$MDwN8PpEg8<82O`ziio#E$WrR9<4h6>e|T1%~r7imzK?aAcg zSh)8~XsX)Xt-<~4SFQFyM1%9qseF9Q(!d8rMG#s7Ta4>N=_QfmR1<~Ga0M-ql8PLd z%`og7VS~HSUz-P}tNxu63IrR8nz)n1`ml2J^rc9O-n`a;Y z6D5Nm0Tx;rs%FPVilWPt?`5 zap}ns_Cg_l8aF{1AOJrALU>?gsMnX4(fCh)*7kk2@hBkIUfTAT1qT8*w2OnmA8rvt zThh+zLY&!@n$wM&DFDDI3c&7m4@W0=i;3$xz>pzOR};V6WVMl(ko%XAq9q+VGH7%VuI`Y{H>^%s1!y^GvD}pD-P*0I zJkQyG)gt1--E0F3I9CiJ1OS9(I8WD_{I0`)iRIe{)0A!OZ$e0Qq*&WkmuVxR3S7r0 zrv+CKWy&K(w$cnMEeN}n!&B@hh5E%vojDFPo1@Kiww8l=YtA_4)S zRc=P;hs+iQzf#|}Q3)}*bhSHxg=c55Y9XJB#$s)b=T-0{k@#1)!iH3k0ckiWlEZav z8Er4jyoA#T4sGe$U^s+)uKwvQQY2)@2<&QMF*bMPwiP= z<1bg8Ygo#)+=87*HAQ1p39YN^_-!=lPFJLQ2CrH{-#?VB=h9j(Y~ENBwHEpcCq6A(g_B zNyB|1Xf(rLIvz{$fGfa0kf@aPmM5%#KBDJ9e3f-HL$u)ZaE0;uh4=jRMd|qfeH6z%4v}HeF?3yH_4FiTXaSjbinB>)hyKZio`>j0HBisA zViB9E8asyCD$6D5bCfWN@veye=TmCKaiCg_Bd#ewbP+rYNL7zDD~;kSL2%q^l!IdgW}!+4icCp$Y-$Ca<9Jft^6b9Ce$6F1i4cKLHhbds^_7 zOiJu3?8cIqM9Aw#&~zh}$42abt88Z%8$e@`t-lb-O{e!bilIskP)(oyqddGf_Q+{s z$L~+2zPH8F=$4Hl%J!r?ei$z_z!+x&x2VA?jym(q8iDvYG-ZvIK-5zkuGX`JpgfZc z3{dG<4CS&x#@+M^t??A(tK;2KpYA98a%(IDAb zFUBBoxd%Rt8!C?QtyqT~8gSKU-QEZwgtR6U`pg?m0!H=+#NwaiTjm74oVn5y4xzTL zMGdH6f%`Gc*=}7Io8|a_!tl#+u)jz0t`lnDPZl@8Mp3R5`}R9KT~FKtxGgp@y$VbEIhSe=+PgZ|nx~9{Jw_oMaWny& zfCKq*la#!`VDr^a2%qy2(9{b%uQn-J08?~Wizr5pNg7PMEgg)1UD-RUy+iM59~=|^ zyc!{lxV>pkzE{g`dn9mR9$I`W`@wJ+_4Wqz+DV1r~#j+E5@(9`r-z7}nbdLJgkMh><)2(^bJA zS+_9^YZNrKgjG&g4qbW{fqQA5#$$`U&wvc;0)`!f;a(blYRxVes%e?9e`*n7yoXtM zb^uVZA+(*8yLcW12T*kE4_EJal`2o!3c9F?BgfJTvl&UW8d7$Fe080vPeDT@{;@#) zolxCfx}4k0?$KxU0UQ`p$eG?!BsI`t6&-qS0btzQA6d@T`K9*q83iyT$abX(FWvsL z(R+dBn$tdi*CAtSaTU_Dt3G-_w#)D{zpEuf9u}lP%n6jph&Kw8wEm-@&5=b`Ck&|y ziTcUZy5iK|=vx#4cb9GwyV6 zM~6Cpwy$t15@;jU7N#JQu=8&!o3;gISHIxX#_q#^n>Ly5xll0xz-%2yW%b*zq+We# zuvFka07CbzJXKpIYYghIjPnkaZbd=v+PdNLZLemRZ&%p_^EeD}7L_WmcVILT3;@ey z`9q&TI@=Xl;MveqZJoSjNDo_m$S%uJ;QTR1 zhzSONoeV10m^>mYyQ7uW4UCNf{>U%v%2kcAy*WE(e1l z;V|Mhockw%9X6|X?eXDvyAj~&ZWn;B8&e2)TGE~JIs3}J34z*f%_;|*f^Obc`}~0p z3=WUh01BlU<}$p2mSyP#y6kf)u8^jdZS2{9B3{hD=Kjmq%soB$pP$`)4KTE^A#co_ z*IT^KvLs3Z_h(AL)h%eHlQM(wZ00JD&hVhkZc}6)V~|PHYK-^?^V?0?M5x;yA*q@e zQ+Tm&w4My&-l)kEhc509(YSwE3&nKf{)(Ndbl0PtH)li7JozkBjikPfS-3QS1N5|i zT>qLwLu>>A^5}~ViS^x38`bDE4lXxINtU5bY;cbsGKo^-ZP;yGx2O#~{YsS1Rz75k z;Pdd5Jb|LL6F=IBYiD|}cNt)MYJ_mIsWAdQU(uNCV5L>(XtL7I{gfSuwX>LCmziuU zyw>iD`0(IDMfWXGoeqi`6*Rd>NSDEXB3+`$KlngKFJ_mq(d8F3FfigP-zT7Jf&ir? z<@_+?8x%$WAik5qw_NrLCsi2?7dwb&Z3?kz^sF#%dW;w!>WBoC*xCjk(jG`)X|X$f zq8bs^se(r}li=TuK&WZXVt*qMp$+N9vrx?<-ujxsEiNQt_$4&YHkh_l=WH{70JrYQ zggd*A-131*Zr)bvr&cw02y@y}cQx*qi_UPFwnNX(*a%UBx{2y$f}svX4{f5V;PPcM zbH9Q|&VNDXhq?1RCTe0jw!+GjVL7vimyyF@wG<)27G{0qdaZa`lzI;Z(=xj!(;=9; z+e`FoQp;RzBy+8nU-RC1`Y3*Xac*NV@pQtjj;#8YN?p6nAQ@Gx@(j{Oh{n#oLB$7> zU*M=3HeE}`xY5Q`nULgZ@y&PCmX<3^i5pJ^?hm+}aXx>LtQC)-7Izx)l4dABFTHYv zsYx+u@2vY;dbE(`L=pf`pE0~JnT0ioxC~q^Eurr>v%p{w#C~dydvEW55Jf}3)@cFG zp>KWF5IEfJ(zBx&4nbW2T#UC7HTR}MS1@*nqb1dIah#H^2TL|Y8pwa#U z?}gtM;GYL?rZWyPt9x`gC zVJZwVby5^?C{fYra{O* zpSFUEsduL!Yw)fK_zV(pDJjrjv$^p`7q~_@XMS?jgHfS>>l|sS=#<~S^I=$>-_VU0 zs}(Q9S${%*L7uO2ms6kOx*#4@3`UEVl=t{su2x@cM^sDCSK<1 zNv&^W)HN}G2ty-*b`t;hz2MT+G*etbk@Gv2Nd+ZBlGI81{=;jE zhwpkS^{O{@%JP?3ya;07MBcZJfEb2hoFFRzLF88%=Z({#_h)SrZdnrM_Z25^&>Cb8 z-*nu->G4AmVy38rf|P#*K;x0E2>mg?@&+O;|9!20mlX0{yMc%c^1(@uQOL3Z7n-+b z1L)!okG`d_#d2PW8G<=k^wY4}f~@}0-y+`SBtLrmHHgrzd2=?E;%Vu8PyToP85MU7 zMWC2rrYdNt;suvgP)$4HP{he*pVf(&(`W58xgO$T*uW^c~#mikbk@yEi0 zJw;1@mC+NvaoXB1h87$}OmD-lfNu$zhGNhp3du63)3DG_VLVigKo#w(&!eYc#w+=J zyCc|$NMva-lzE5(5D;@+FK$lZxORslf0HVY*j?uw%d9mVcGyI;%nrfzZkePng}=En zO5}u@rsTz%U5xhQF_=z$b$?EH2Y&i=7#ya5!XLU+=;IUAoevhe1MhrkX|Q=awODSm zf$*}@fIkc3%RMu43)q>vZ1lQw3>cQKD5=uZ9E#6zstgl9G>mKC4I{HxJGzK&O(M~; z=LS$^uC2BJRw$pt3`F%9O3R2SSJJ%{bG?GTKwsVo7=tjeTePV|0q6!IxsE510|s4x z;$uUy=K()eAvhsiw%jx1n~r;=YR2;wc&4v!1Y#9W7`?6- zfeWvzmh9DrsEe%S0sKTxJD2kWaN~6b(5867NPIj7r-ekha^8G3T`2(2@J7_GO^ zPffnDySF|F*wZCw-G>1=Dyh&kFE_r`Gyv#g4W);5v#7(%tVIVKn>$nZ;C=6ZN0J-q z3LWa}Cwn@}?Vs^SJM^y#e+x=90tu^8Cg(V$Dzy88ohE8^uubR8!U>6hAcy$J%NsC2 z*@?aiCI^ft!@-uP@oFQt}y$L3Nb@oOKpN0+)mz@-7w2snn*26dCiO}Yfy#JSv!9A?M zOKX7TtWyKmh+ZRpa^dj5}%#70PpV~8_xOjc~^n#_)JskmcLClEaRgoEgh_{9yUoQo( zE!z;aF>VGK+0WCH`{Z;n%(fLx$RqAXH1T1^0xl56;Iq%X^Nzs)%gkCC_I=HT*vpX} zFbM`RjaIlKyuEu*L{|yvwl)x}TAm1GSQdRdW;VeOTVCfa zPh^ku92LK=p0C;VuXezHuAg*SMm0h}9enh@Gx_=2Dws}IYo7qiZ5|R2;}7{r+V_iU z*sM;pqgri&VT>)v8;&S~L9g9vf5shg^!Rg%DwaGN@ykT%`YzzA8eI;cc}?PirFg?; z7onOL2dioR+!7(RlyBLr_qZ$v^F%~ki4xy*($IpVLc)WmBLNzJ@Bcz!KNRo*k2OP8 zS%2G_u)5bH+Px`9L`wQ;TaX0SXkq^;Ukg;@8v}pQ&-KZ?7qS{lZ zD8U)+zvcEIjta7W>RZxn7m#8-yUsQ6ChANge!Kr|*4sLjp}wg#-84zZRAq^ zp=;o`_?J_A^$(fqQxM$~g}*%3mvj=Ho$ur;QN7g{WE(eq=)e?}HIL8~I@Tcrv%R-4 z627vYC4?6e6!G=7N;JhcX5^=K)iJf(-N7XWk70pY1UT=1e6i0^70uWU?g*#P^~%YH zAS|x)E~&NLIWq@sT9hsdV)&RaCv09gFzt)m3W;{;Uii}VX9nxOZ~E#_ntI6siw1FE zA%X3@UfN{MEJ%S7LZ4&e(OkndLZ;`5>iSS7M{87i_t)Am)Xiy$e=BDj`mr&3>{v!P z#0UR$EF#CudaIiug@2OIb$d$22(qIAS4&yDnkoXN09B1OlJJ#RP<*0f@ zn58coR4PWvc>dluUB+z1Fh%v6d_yee8 zS1N%?QeKbNka2i}2?iKeG0axPP}FMxF+k40ul90tcLNjz;dgcPk8NFgb!hiunFNMjB5UseP#Cb;!0dxqszYg?FA@y ztcXfd&jEE|hB;m1Gs+Jt607dNvG$^&A9yjqtPxK`UMMZjflI(7MdSbj!IW=vUfX6t z0iqeYf^&cfgZnxapTHuP%F~U{_$#O0f92YSfBL{NEwT4fqaNJ;baPsNceiL`>|(>S zy9EYGu9G*a#m!u5u;IBAW%{V-ln)ssUzBKX%|t+0*k_fJ8`mr5)+nHf>2d#B(L(DT{wNA}SqmDu`x?yvTR-HpYSH zc6EM9Ix&g0v9VDdNdC340ah<_7hU~ij9v?Gm1pZw?A4aV3GH+b6DAr+h1?ByNB;Xv z9UHU0(BTgkwYDzXffwuy&jinvcktD)e+JPQ`Xs0KT1l5(sRjlirROKd3Cfcle6oD1 z@OUVokSPaw0`qite3GqZU$AitbDrn#8&rqkheP6Qp5juaCr^yGT0n1g5>W2&6GQ8n z>a`}PPs3<_R2B6qsF@dJLwt)unQ6Mnww4*pr>7gEKpc=m1(k^Of*`TSR(l(je+2x{ zkIpk?o#LuO2V_1DZy8yAL|W)uIgigTy8bOQQAU$(MEi_aMyvL03BJCGBC@K7wc&wp zae}JRen&<~x|;fL)y!8j64g~*Lp@jb!bTXs%vYo)Jdx0 zzV9tVzGA-a^s-9lF$(k{bTJQWf0P=L=gz_YIVgd}1-EPWV=g;z6^QQxVVB5G&(Jh! zDQ2ZX%6U)zvy(6KH+2zvsrOsQT4E|wM1qM#kRU(?E#=loZ>yfE^x(%rR@{TY_bmEZFFsOj2=&KLUiN&;`+y)P8c%l0~T;mk_=a8 zY?9Gfc^K-|Aw_5O%;f&z{Eic7I`ifs0Zl@Wuqwz3nK5lzYJX_rzV-@RBHPj15DTUE zTtmbDFfB4BrKoEvO0)`sf1^VP+8R?RS8jGh@w~s}h1HH&hpgCW%Z7_L;Z~LGyv0ea zG~U1-Y0QLItI)oF(r>nXSvEN%u~p}z0S^258ra+n8KgVR+(k!>JHi~02~LhEbAhA% zkrW(uIj}y57MknQ0$+=mSa^5BO~)^;$}b@Nk#<)kTM0^kW(z-zf2BQ>5lR$B`df~Z zCk+u1!zKeoI@+qEMYPdsZ%3kyJx3xFTI!QaPWA>hAISQIo!JFv#2+Gk$UA0c4NlH_ z;QaRk!tA`ZF`5pL-im^I8~5WbX$D~;@%acR-0*x(gn#M~4$1A~5lHf2tZQ23Q|C+4yD}D@ZbWDu7uOCe-%tWHvF=0JQ-gn#LN7n zi+_O(I^vxM`sP!Z&0wG^7Vqr`-$oRn>6QwzHdv~&{qzWCm?`U!bdak(wA8xRv{UjyzJx^!5wfP9e}oPAG!~n&aebj@yqE)#mZtG} zPl3Qq{v24w@2Xn-;{lokL-dSKU|_g&XbASE`*3SF;>h_WqT%!2)=Qn1AQbt(1JOv} z=)lnQ+30*LI4at6-oJ=M@z+3|ENQCi5&7F%^FV)*f0B$OAM}s}uVy;n2K&St{ z^ct&re-MrEaqq9-yJ&<6(T{#~W$gz7KV*0RZ19pB7Qy|Ci^#kiu1UuK2w6l24ttvL z|BG%+Wpma2i&Q-C|3^n75vS9|-G5g=%L?QB2IXqP3bhtCYmS2RTzphoeD_<_wa`T{ zPDo>+ie=r!SB^}9EN!?sM@~wAH6p%kDJ*7we`_fd81hnid@?8!HDEeQSFLln9Ij;g zotT-!jssF$?hKU##SQlXRl-bUuwqhvn@={6^X7MK@X>tF zT3pAi7tW|Tg$0V!3i|&LS9A%qo|xvVJJN}UzB;UoC{wzD(fprWfRgVfMPGNzyCwcE zf0j}22I=b!g^+*5S+ZUZX0D6Po!)h&^_>F=X|v|8Im=Sg%lQ#9N7z}bbQx_}9F3?B zw{4Nduc86TG@!nx&_zwAP}^mgnjpTp$&HFAfAr-M!L{BDk^du`BBlbt2FpW!{;5x~eUh)rd+DY+21@g>}>oogw(iEqSe(tH@Z{RR;e}11ei$D2) z-e(Q6v^8>K*m2!*lW94EC%B!^XuM+0uuT`IrTvibSSzyOv9vq*gtF>-YnF4k)-kLz ztyzlkF;fW0A*II~WDv9iedCO_Qg)_eWIC8ADYJ`W-c$vHWhVhi>>{3e-uVYg)2Z?^ zfc!Y3r_(@*!QsV|oL92bf9FOHxy2rtG`Dd_D%_?wQqM-r#b$r|VB=uF?Hu)w#UoZ! z26vASLgv?77nGqIz&#E`wzn}eT?wfLE zYCm2gef_xSlme3A;cD#}X>D>Ptj!(a#)984_R=#6q(@_rT;D*)fA;-aX2JRW1TBq+ zl5YqPr`~xaH_hADXH=qIy$h~h?3+_n16RFPEI?=eE3*FDTGtYt}mB&;90Mswj!1pOy6I->6d5 z!}Bh8Fr4g(@SHonW9tV?&@HFDKN^R=XX0*%c{;**f7`6W0Xn~3ZXC!FeH|k*HP3YI zfIX0Cx1GKdC$Si>TM3vpPz9-0zP*qd1{5DZv0-Kbm*QPd{8DarYUd-MiCl1>fTaPM z`O4Ny_m9C=M2cr@4(|Wvc9E^tgYUd|>IMp0E5nBIVtFhV4{qF^p9FOiGmd&L`jt5^ z!u_S}f6OR8`bBbWOw|JeeS2$vLvSB+Lc%&DpYJs^dd^Mf9c@I%(YY_sJ!!DyaWu19 zM6G%>=P1PXIhSdOPT$qZm9JgWU@b)WG7tiWtB0UK`(EhZ1WqI=tBN6-m^CVt;}zE4 zFp+u+J$%?*bxSSt=u=KV5)3Q61S2qoVQVkP`M*Pk0kTY2;ZrDjx0M*m?{llS?VS>R2 zcB0LZzgXWPJAZb0C?(rlJe`QUG-B`OWJoe(zx*j7bhqF6D#jT&xP`gC#xxfbqxJnN zf4{vW9+4ZsZ+-v{Fs`WoMJFlO&f4eJB`xqIoBqiAH4mY=z9qW(IpcQ}oI~SNyIuN( z^vWF=sNQ2W7JUDvi_V<;1#8c)D=9PV@a2oX*W?VQ$1MWM1^ggd(W{HR6Z~bY+9ze{ za&E!Lsqq)BwvL&DLp748R1Q8f7RGl+e_JLDZ@aS-)lqec&#+mIcvf{xl(y1@O#8{) z`k{jWdz=%Uh?XZ?o!-dDE-Hig!39S6LbWHC`dI>y(qbuoWltQa@wh2G&T$STq%q7wza^3Zs}y06$V>Nm8D0ADpqe zOrvAHS2rvr;6#>GJ)0ka8cc3*X@6(kJp(Qj`rHKXn*;+>mOQ9z*Ft-|5-mwNC?HG* zL$p;+<7wS#r)E_@%u*Kn6AjIAs#2CiaqV6HyVjoDj0YU&sx%@hsWJ9?HvC4J7%tA% z#$^r8p|S7mWZKsJkENR5jSm}ne}<03bgK;ffs_Z|*w3Q72ARTm6XTU{u_|8b6)j;b zth}RN8@MTL&`LF$Z4w}uEu%JKH5YsxU;hqu_J(4}&`8R~u}FVf)?g!)7eng7I!3se_4*b7aQf` z1@v=R7jj;5)$_GNG!*uLN%e-YuAzFOUVkU&rIBOnap^c6xU80ErV)IdAWSn$BijUn zo{F!DK()0ZJmp~&H7i47btHf#rtUI*oJ|78A7QhFN+ktR~&op!J}3MEyD9h;z=wp_Fx$ zMjv;uiqC-K7OC;W&Dr+rCQ@M1g(CTaAYq`RJ`9dw$*u+A*^|fV2qT1V*XS+}vr$RpTix`^6A`e?_B=(WBo4eP~;($qjbv z(OqNXd&Gq%!29KDG-t;C?^05QR>Vx=yMr}rfh&^OX7i}3Un^jDK4H{{#X+qg>@Iv= z_R!LTTl2!hu0xYsa>H9@br9ggim2i{c=xLqQ5CBKhlP(W*ZV_Y@JB6}XC7=R4Tyo) z1?8-`k34x{fB#{1W2Fh)K76SqXI$r~@-t6rLJH}9mBp1vf`LlgWgPG8qb2DQCrxx+ zLa=g7Pf8ieEhm@DLuMK?r6Y}=TPxwvqDrU=wHsT#O99yN=r9t8iSC>7=&i9vrbF%T zN>no_)=~!~#|8R+=02X5M>*DksTd4KcsOrK2}zmPf09>et#WEbgK4EUL@CQtgC*Cc zDi6c6>5`G{0-Msdd@{VNeUm2aD64XPu*!G;D52Y9r3+U1*78uOzPJ*`XMp#)xk^`L zq!}u(DmU?XR&{N%zx}MQ8sU?=N|ji5^BlAupGIw1tfJUj5wC2$?N`Ak z$tl}xm(#vd!?n_*-cTHrqfNOW0@gFO^b@S=(wwt^f(9=g3k$#bd!w-%*NS&9n*Bn) z?UDNdk0hoiC(M()7TWntyI2!Y)Q;*1W-_mMf37W3%iDKL65qklqpikMAny~s);k!w zh!W17hh$lPAHzs9q<_^``%{6yQ_G{E5?;V<14*Vr^FJJPo!V1UTI;u;~eQr3?RugNE0`PK+FRwI2kLP zA%ibiSqBAje>G@jB^7#KBpr^kZ5QZ^e=L`md5G)nLEB|P6N?kFPLKk@GJm}UBgJ2q z)>Q>K@mu}I9Xi#Y8MA$wN`#AxiW@tMB6-LSBuvC)SMu6OI|BFzhKpx9>8+jDv6|6P zbw4ZEdNJ)8bo`^s-tUZ6tNuTzYM$!{t^9W&4`5m=QkWX+?kFaFzQ9oRpZ0GFf6Po{ zrLeQWBeA(TNIa~JI#`0dc^SZWAofT0NWKA<`I{Zb)g@s%pcLVH+NK!aeMidqRaAYK zn^@N7A8p#5miRImPo%zQn-^TJc8j*Rdz@KZZDBuCQ(Oy5n!Y0wfG&cS?70V4qRRSV!?cjujEu_ov1C-)Lu28IlVp1*YXcwk3cnhs@{&`8e#xgLWXziFmiW;%?MH`a zD$5_DDFb$VR}UY#xznu$e~|O@?TT`qh@@h<)I45@&v3c+;p2;#dx|&sQ30{z0kMz> z#i2$+2xIxY4GrQ~`afNnnMqMVv|I-3SH)#<=Wr&kGT)mfm!a$b51vQ=BEd_`BD|+{ zBQP{O!}d7ow8VVU0&Vf7RA9MH)cJP(dmpP;@DHL>nQ|{zXHHl8e^!5!)YslzN+cU? z&|c%?2{I5zU@}hjjIW&+y_s)+N>S1VVd2idR%xz&Zz;;&0?q^az{q2RVD4s)!k0D9tIu7l zn)7yNjJOLb=jEBGe~M^`9a`OK3`#rIwPtn`*Du`M&F!V??@PeK&Yje?c-lfSmRNh( zWyETPkA=5Gg~9Z!B^0UEJbpOuVGbFalW+_b@#q+-oimOXOSZneeIh?+NhDn$1#&G5 znw%m75-?&c50}72XIn4%cmq*5WtsoIJeoP>F}Q+2;10@Te`yFyNsPupV3AsX$!xJe zqR0v^`wYzDrSyG{EkZrgk#*ezpA-HrTF9JRj-xEi(J{THt19p%0r+(l;A~Br`>sm@ znMLRRoJ_PxDb<=zVpr511wXbs4&Ag&!di3m1jP2|uR5dW)d4!+^0UO1lq^^3DR(w> zlfnY0I}?nWe+Dek{VxE@2@1T}B6*Ba(*HGU=;Q>TZ5z1rv*e?J0eVOP@WqjQZ_7QH zi84xJ02@Gk^D`GI`^m4}qD+iNL158rz%$=WO&(J3rjFy*K_EC;eut~>R{0ib^i(|< z6O6U-c?}WXm>@JNAp3@Kx0k&mDXRPhee&Pi2{MtY^-bpv!m3Z`V$+v+3LTJgBj z;uQR1stdsj9GwsE2^XN!4`_6|0EpbB6f!w(zXj^*b&$+^JYt6C+2&EGcU4!d49`~l zFR%{7vLU+K;RZpv=`MEv)HLFN3z#eYMRaII4ts9T%n~o*uD{tyRQD}jDBhw5c*b0; zf6A$>eYHb5e%;U!{nCZ(Zi5g)Q78pJU-7XW*T9<}7shX|ieTR@QV%=xGUqCd!^BeH z211q5fig2JB0v91LQ)MAg4&x#nYvc)ovC>$dSEYz6ErtWlpaL;12ni)*=*$f{qJ}> z*M;jP(f&9)w&rWygx99&G~QF#==`e1f8KiM^jDt1M!RyU)v+WKPBjBX*P?{7qUcrc zl0P*>&DqU9IjDy6{bB3g%uZiFBJdssB@&x&j=2`d)agzzJhK`~D9pO<`REtMMb)Da}z|i%KmzW1X&{*Pq z3ac|>ppd@`Y5GV-BY|%kGTgFyS|^;0bc>h7NG2x1V0cNY9CrBdnsN;P$9;My9=|)p zcmL|bVuBr=lu!4sEPSyV^xs)-fB%{JRywp+6#wCg6|~~p<*5IKtAoCI6exZ~k>!y- zg3H1GJoO);|4e;bzLzr1w-fspkru!mCCLW+*VC_{)9IfdjWu!~A$m+D*Y*95TX|Rb zkB+cKh0b{6@w3g3v+<*oOat>S@jgP@(V^da$v>UJ!=!(t=gnja(D|vCe*=cAMQ9Us zu!DO^gL_a%FHH%e3}n>R;fv&90|a!Yok?S$QQ_c}RaBDcGhhlMd5k{--WAYA@}ZPb zL|c7zW@2MvY^qJ~V!%jXAr@|^H!h2|iOIvyo?&__enmsb-x)l@KwzZI*22Ocg&GZne?6#hX}mU{G&3}# zm6hd>oM97srzk^=rwhL>b8}})50JzThGR~FhVe*au$@kOwrDeNsp#lfO}Jwb#O@8n zj6*-Bkv_p7CMG7bvoj?g6U0Z1oUDQqJ*1B;K|aGt2x1uc`!}Gb1aI3`B_Ds&+ScZW zB@j`F6a^hNKzu71fBsCojQM?~M4L)xOY_rUDlI;Mp@wYt!sLgV5=H6s&~Jti$Nr?I z$hhz2&xQAB%vuc` zP8Jm^oY{0M008x84=}*k>8hU)jfkQq3BGw*Ou7~T3Xi&ye+Di@IlREcq;QQ2oo&++ zHc}~>S=~S{q50oh#e(BE5ZUe8dNM|y1i(aPkWiCB*eGod?TNdFvRbtVUSU~fS29SH zaTC;VnO+d`xP?MW;;j!ozzrFopr8atMv7?upaT$h5J$=NL{PK&_m}8D^OcK|{rQBx#;8= z-$;Tr-~4zqs}w!Tv79UhI0CM^iKIZQ!cM%iOP0~2!hPe2op@eXAtC5cr3GiN;lAbj z_DUwJ(;rJ&#J^UYhu~RA{iBrZJX4so0<*D5D7Wys3dh{60&gMJPf(7(%-_IQT<8w4f z{9i{Ydq`6M|Bh0Sq;@XDmM}?MRd}4;9!T?Cf7lJnqc*mOU7V3K+vXq~%pO5gY{<0T zPr5r9${@}#WP$4*Cn^Eb~??c2(q-v zf5UKx4xnHCRaYXr`~6pwpmebxO7gES+!>4Tf(4Nl+6D)CYXja_4}&YRmxO|%iG1~cIiu*a$3YCz z)LNgedvd;IAnfp9!z_}CjhGAZN6w)vvj1}l2EfFGV?UD6GLs;i9!X}32akq;!)(Ql z1HfUPCmQMK=t$!Oe-*_sF(eN&3?(N*U}7dc>8|ITWf%QEyQl^m?h@>mR*nmae@tKf zWH#W{JgOoSR`9456-+1+rL^!)x9Df!2OskN7~G`*z_+T;b)~~n6EF7*knVLx7@RCc z5Y!>q!1fzP3y|XSqUzty`Eexs&nk&vQ}pz7{0p$U7ywsmHk(od>Mrl6c=8SW-8SK#aeg1 z6M*i%(hV-GB3hO40`1gh0R|w^TihBA-s;TKey)4|(p<40S+kb*iL)bWMeU62`L20L z`9IM++S-4j_sU;Qr6naSf0TbCx82i_Y<73yaKN?mFK>!T{!Y}HxLu!4VU(pX_nDn= z=Csp0u?D}7)bE#~CuZkp`8E?Rz16op2OArdJ*^q$eEB(;h`Wb9xr_Htyvx;<9hfm) z|L7>8i%XO0mT_3Y=~b&bOOQx$YwL&sBRin=Frv`1ubNQZL_?*?Bo=CZLZ%@^BW{3Z0m`^?R zOLYdEOY{u@2-bSSXfCBny|IQ(fxX?Z-QHdUT^4lC@n8u$9+|z@dKdLk{y@UuWZM?h z(qLPdJ>2|n?Be6Ue?`l29Yf4KYi2WE3RCk7w0`L;-(Qdzsjim%3{-xla|&-g;O0jy zFXMOZ*&BxzJW3OU11Oj%>gydjuV6UxvQ7R7PH79RF}uqfiTm5$U5YpdAwu>teL>iZ zPV(aa1c>~BGVkQh1N54}kn`Hj*nfzrAi%`;C}!yxQ(Mc?e_7;wPKpi@?qFYEn$;X~ zAca#3zZ&ds*1HUD?yn6-4ckaM1M=d%E53joj@3DZT77L`3(IGSd^g(<9U z(Sb5g^aTAq03N35iLrFe^;-2i&}@Y)@xR%M`w_dz{}|)On^br=i&&U6=;jZiinBeo zNWEe7e^int_d_VSV_g#=P8?n<-&xAhaHYDc@B6CEZ*}R0Nx8V--l1Dw>2E&Lz3=eH z1o(Bc0rVM2N+#Np_e3>Ypqs4FBf%~?U#;!>W~f6j6_FXEjiFzn{m?fVqBun_h-5B$;6 zH+)Gy@O7<%ucRHT5s!j%wwI6y&tS(}OUe%>VokQ-t_Xpx%8^nn58#03mMGu%GLjpF z_2kTc8}8DV0G*4<(es;2(LEiBaqCOg(o-Di@?Q#`=?R-r2N9Ld#+3K2P+3>!6ws;n ze@v8r|7VisM1&#`-0qK`ApPb$$<`L_oScl~J8W-jTW;NYmNqnclKP|@o!jiGYZy5C z{raVw_XEI$R)5ZCyzWuNGNNRF_e;|2pJ*3^5)u+3-g#hJ1+l|~M8%KE$^Ew8A4h51 z!ohnJFEdO?NRhQnj+d}IZoQ1Ip~*VYe>S(^QZ`dLNM!45I%zQ0R(m}*!He<{lOQN` zw>X)NWn%@@zUlMo@+Ob90OiubvSxy6P_8!2N2>$Kh9?8tdC=9?2#d>L{E=n9Dr5S# zD{H8$g8^`G4y+v=-(i^|Hx`zXzJ4CutJ1zUzwy)kuMAiPBiqy~oLMS3V)DT)Agd6a9=DR<>nfu+p_s+bt=iPhOUTf|8uIG98-u~ejx;K2M z1ZiDV=6C9AYGKwo(0NBig$*)ke`>n;Wu%`1p*9j@#lWCHSZ;QkUR;m&hDT<qn1glxhpo8Qx%pGpi~(dnXj!w_lQBTe~=^RMJ~f- zIC(@$%A4El18HWxnk$o4AU%49P}RVo!ENgn4Zo*9mo`btvgsb$i-nAZ#Vr+658t)bPk1j~kDVIQU9Job&ciX(}rf9Uk~!7Ophp4l9gQx*XQzbE;qjW$tFq)b0Us;#5!JemjY zQ1zA{sA{XcCruH2lT_4qoPOS+zQd8K5F9)dxja1cGsC3f`g3_lyNDdU!zjIdh082i zP9L7Lext@ig6|TM{iN zEO$K(1&VQzadQ{nc$@)cQhIQ!b!LV!ue-antg0x+oeYO7b#w5SOn>Ad8l6Xej)NaF zmT85&52c;k%~NxS$6Tn>OFv-ylE~;(M~aA!a#$J#jutSHUsdRZG9lX9NPT_Z)OxWq z*42Su%o-5Wvkc1~e>$@^_uB&IWxy%@t>^%DBI<;)mff8ZZ?^ni%3{J}DCw$sXW_+> zf)?kUuM^$(j45cpO!rfa2?zj`H|D{@;B*5^pQ#ovnmUiV7fISTK0Yt4sgOCjNHMpx z8HR5Z)zZ;U;DhH8F>*dqLx2bg`6^0FpDHWgz~k}E(cP`(f1OE*G>=(jIUkf(14WXR zr{}d%T3?4IZZ;E0UPv5B5}}`tUf(_XPr`7ZI;z)~h*&MzV8wq87qJ`**4mccw~KTmB;rur#vrA?DrWqN!U7z zs`fd}U?S}Di=_BOcgjLX8~)44-TL+T^CNPdUX)kFqWrZxpgi}^>r%BE1WOlvQ@v0o zZCf&_dUc3{c{DU%|3bVqb&)(Z)y+XbIS*@jiMG;rr-8mH2~w6wX5xUp@s>b1Ge#$O z_lfWz=DnTG2j~I0q8+Gr5Lp1g|7LcxWShbR03b~jQ*8(U7}2^x$pC;(#~e*!MsL*( zf0|7cd&f@p94@~yKv z|1bRi!v6<_@ec(OV?DmKo09;ZQfsU}f7{ta*=y`SJj+4yp7H)Tq60ZQ0{}lnTlxPJ zJFz0NHmJC@dTKCnT{^&bM3t)b3FF|NlcX|7N8wUG!#crh001|=M;$mQG#GTS6@NU2 zv7M|QX~U)Fnk9|ptK}4P_HrCB6K&$Uv7%-c7FHwmd-aD=3O!A5r%Q4+dJI)te}gJX z0=9$bl9r`i3IG5ZVT;OVpexvC5atjlR;(L$)?_Me+I70NsI#??7VFyVMS^#xoORl0@so;TY-`+8&hRc z){qiSP1iB--MN6?YTJ&nFpV_<+tDm5HR%o|(gS>Y>Cnl!A# z7h|jYIS@9pEvlrT>6bIX#0`1=r9>z43iOuYzEskh&}55WY8+RuG6F7!f2`Eb_ZFW8 z(_;cU9O-Q*8s)Cu;fz3RsW~~RO)Mr$5WD1BkJwL+*GO}UhT?|FDjQ2rp=E~N@=>v( z1XgeHeu8B{6dI`!{p8T6%W-#ahr0f=n?1jEoaaENNBR!V8|tWHjl+}plsTlM*~cI* zFJIP;bx0Qhj3Soh0?#jfGjKx-zmlatX};KXKC(bCcriJopx$!ofi}2q zf;^ztuP2h3#Gk`|gwLXDi|2H%52mj;lAQgN*ZerN;Dq&R$YlIKQiyUR^++D zQniMHFm#3tbwxkSn}dz#Y4*lR_u8aBkqNeM(dSR%A3-wtWYLDw-lNCh-l!2n)_$AG zNZ>e^H~){r0@AX_e=0}bNLQbFrv`EDGJPg)RQjh}z=1T5QIJZtGgk%eb9w@uEX&L= zF^L(=3D*p{r&jrLvmT}+VDcB?_|2u!d}~Pm+SsdB`{u_&XzU-v8LQ#H>=CU>xshqOkmgYpv1F801vX~#B$~kOpERJ(Se{eN;U!=|ObD8prY$Ig@ z132x$N_t}~2xf#a33&UAi(W`Me#R-7=)h>LvjuD&sSs>e-+hQzU&O@|S4r+2Q6{y0ozOZo3Fe*rmWVIb(>E9&lZUn6L|4I<#v*0=uKDoHq6He0@B~$jY6Zk&a&g zTufk9g+NM;e-TQCn8C)nMkD2!p-ffNto4doV=axjgH%+3DA7di7Y5;5!?`(29IxjY zL+=e2EJVjG$T>B&T?RU2{b;?vL;e;TAEk^wO3u`c6?gqGtQw_$zx;ia>M)3 zOr8@mNy6#XZ(T3cT>RqYX=R3M$uNI2!4v$(pR!Pwe;p*OV`l)rH8O0<0A{rq=dNm8 zqOJ4Vmxbp@;cz;HeH5Ay?iW+fE$ICeak9w>vrWoKREf;jV3(Udn##ZD41w$zBy@!p;v7du69JaSP8i#$X&7r*fezi>p7-|*4Y zAPL3lf0VRHF?~VHKvLm85EgqfP1~QyE1%L}YIza_iE#+3`LUUNT3KAbsvYX#ll@}X zMz7UNr;giq>7EbRz0@<5iHGc+liT_rwc8X6?qo;6J}y3!lK;24bMnKN@Xc zzx2L>uTfXTc6A^0%4^LTW;6734u7Ikwfnl?f77$nWkdcCFLTPX>GNDVIgrP0b&}y| zug?SRCCy%C1?Wi|V ztzn`EO1+!LmKSb?t#G40;e1>b-Kk`lR!gVKzpYeIX(<^Py>GR#{toZ(_TQfR%JQnJ^)s#Qm;Fh;$ zfNKYES@LVsi3(a^}S|QcSSrxhJuLs{!K{xoSmi zh>a^3NRM^{WOkEs2>B&rw$XIjGAUjsf6vt{vJ0e&Zl`Wk>=(I&5>8%nX;)~d$l1Cq z+kZx5jKzZBh6hVjq3-M2T-r5iDwyu0p+Uz)+~Ff>ng*GHI=tIFar4phH#qrWEr!Rl zAIY6ELbW8G&93*vuX*Y;a6#x?7ohWDdbX1Znf9)W#8(^JDR^Gh?8XqhFKypqf7$x$ zSkq2pn{EZo!RRiGR&1kMwFc~twk%3H8kLhc-AxdIO*?xewxAjI6pK9+_iM@nuvqG; za%n;$|JAK&Rb^(k13U2AIB2jUXRHw$#;U4@TzYd!u`Ud#23dOp6ok9#avh6j!RHMJ zYmTulkDMzuw~mVJ8gW&(di4(4e>p!Tf(>oKJF3`!bf@5T{k#4aXEG z>q_>PZi>yC2rq-7;D=OVEp9{i(Ky-noni-XC@*05`hSiiU8W!C^ZOcu&2zlZqIK>^ zEpV_Bo!ioC+#3k!G`C=DpGhkQOZ9a}<%m6C?3POey#hg=%!Q ztp*R9^gts2@Z47?x6PQ8Pq|ZtoEuZMDn5|YZ5Z>GIpa{JC%Vdrna{P&IL+v!; zpraEDyVTF@;;4LI3i4CiOxm2)xt6B%-OiSXhdg2%cR{3Qi|45jz3L&S_@%7c`(!NL z(Ry+$U21RUd$zvskkcI?{IZ`=;kBdnZwJKF3UFZY*>B7K^0wobAA~XZ0gmKZ`()D$lDq2x3 zyBF`(m6^#%qilPx25Q_F(3~?;zI3pz=`yco2vXyVZ)PHV_m^r|wjP}hUpe8?1RWdA zP3gqxo4`v#xo}PEf1OT}mx6rvhl{<7tn@1ucsuZB5M_`4pZt1kv!o{{8_DPcP+P!o z0l>ik+Zfb9)6Mk$Ks}W^bZ=7RDwVQUH-(4t}YC>P)8vm;v5?wbk~m-qES`?!c&bMX1mD5Fetkl4;DMbpPi3t)DIxRFzd^k0xZ%;UWvN4gGHx_E$ZJ~=sK9+;z zAR*z^d&nYKMt$W=^{&z9Rj=}L?!3C?vLdSm65JZff=FoeulUPiTL166?kN?ys{LgpB@lt%?<9kCH`% zZIm46fAp(q+68fMjY<}?hbs6rjV^L2%(_ge8FQ65N9_9O^@ocp zjzaoIQeRwGK`jU^+8E|QQfW(e`{SV<1sn3~U6>MUK6KGRb8-=r;f&$e>&@v22YLqS z$DY;1cG8_5sKC&(hLJMi9F00vur&!DuM2v2v%%J33?gt!3F{bUw~myKs{E0FQj*9}?R<@!-)qYVNIcrM=Pxvb*iO)>7qy$CJx*@; zG;bRq_jGeam0uv&(re-f3N`z+22zyGe}$0FePOGUrDR{iZO?<@&ICUdlN?3z-Hiex z#jrR;N&zEQLd9jib5hv(^S=F5ZvDn2u+b@-cFN(M0JmPQ*j7`?(aCX2rFbs{@cUW;|wSMvNprN=SAH3UMB9F!Gn%dXn{XExqcaAV(Jo4A4f4yHk zi*ni9+D+Yc38nL@*qkZVeN3UV=GUnN^c0_qD$_aA5feM?Dof<^en+W21V!SY6m&Sf zgle^$XAvMN2ik0Fc=W@r^-fb0-~4IZYJeb(Y!o>;`GN>Fy&^=O*Pf6Tk&dJ{F{a7xWsMe2nGbj9ija;^td<+7<)mAV%d z6OkqrcpbEd>8dno_d$!~hTCP^Th-f1G@OXUCpS zn0|mH3pgy(L8wr-*zWU1M-s7PMdgHq1nFMwI4)H60v31n92_rVaa5Ntn4;LZ`3u!@ z>=J5HQc^V1kDZEB>56iXfs}1TKJQmvKJ;cQJp=RDPx74K3G}1F0MTMf58h$jC9SUU*!K- zQSm6&rD8Kn>BZVHBF?{S{*c!32r3C`?8yi(P_Al0SaAqQhgt>+>tj#MY*EFkIhq5p zOo^vkh)`P;5%x)AA$aQs?I%_EZ7E!MM+(fwF1+PPonfiG@odVFa~#s%>Mf_bc{BYf zGxInsn334fu=#I}fAk*k1#F6t)=?OPXt)GJ#29m~U5QE=FOqU6#L_>Nmn zVi!~}e(^bRNm4s-7qfti51&0|Wz7hg&oj7$C?9As(`G9s1ET5+#`WT8&KuxGIcuiI zAY_MI9;mjh>)P}V+HusYS<%VdVI@Lx=H94``=mN$z70Bpf1!e6$=I<@+k~L7%emLK zbhul~IXgN!td6UT@*zB!scXfw-+DyTgkk8O>K?y8+|Mv_P-r=ljZ4FxORIzgqL(Gm zjoC?A`a0(DcHUj5hD&XWdn&hAxJK1xG=brUj{sFbs=s*Zu&~P@P4JyO-I`7L-1t9H z=7ioJm>9$N79~S&{eKL_6cLber`p?W7NTcq4>7)E;hhBvI{Abq(~22_&AU~W6gSrU zcyv@;{`-#@=q*3UP6=-DIy`Ab*9gZsl*T6$clV2=omjXv2b0I%S;zCTEnNTVhAuNtdcFSZM}CI+LY!;gvSNwa0CLib&x<9E-u@R*O9u!FbTs5T zSpWcfUjP75OBDkI6aWYa2mo9=ZbSe8000000001&FCYRJm)LIu9e+%F1yCK$(l!Kw z21tNl2MO-(?iO4E!QI{6f;$}C-QDHj?(T4KcX#>o-uvBq|E;Z>+S#6-+3wk%eyW}h zm6sJqLcl?QfPg@fln_ybfPex(KtRsI!Tjx!d;ZM%w}EyLl2nHKdwIechWvfTcNG2Y zD6A+ds4S-lVPb7#Wq(9#t7mOwN$X%>Z)9ZcU~1!to5bz{0r3MuQbbVMHT^Wh#8tC@ z-gg81>!ST(9lVEJsq0S&Db32N47G(Q3Fij^KOZm!jDZ$n)%}#bE?pCuwpO;bo4f9z zQBi;A&99<#e2?zbjPvFPbzl}$^ z`a4knl9m000Lni?v}wbo)DZQ*uT5Z4hhXs%y9fRm2LprcA(b|cX*ECwm2|cy&+*22 zSP1@l%2@{hfpug*)n75vsKJ8lPFFhGuDgPOi*CU0!V;Of(bgqg$NFt94zUo>KZD64MdgH4*Eh@B6$RCqa(mRihV zm(xf0EI0p9lfsfq);shU*zd39SU8`w#i+~tmVkmnX6Im=qM);KE+PE?tZs3i$VRM( z?I=-}*ngQX|K7(0|DRWX>d@Iw)R6v9?r+2KEletnwhmw|%-J|#$TCxOG$6AT^>ZsK zAVBa~_-H>WI4N4{bqDzMxw;IH7jH{yL&Y(#eKATl%vsGOL( z^@jDk?7~Xcbf5+F&y{a3y!JOF-IU~7XbSpIAb%zBSl{9Yy-GQ&-^3y82PR)bNjYzp z6mEGTb_z2e(4>eszL#q}eTO(0Q?nh}rcr-Gf>1Ki-kcgAAQ-nUyUQD7k1LC#M^zV+Z>HV9FcmJW%H zi+>yEDDI~OoD?CY2Ra{gp1e3Ar8E{%M7<=4!`_q|NgNash3!>q#CKB6S3SMe9*|Cn zeDUj?UjGQV3fa8nrwU=%8FyW%Xa|HPNWHFLF@I&i)-bZml1xZ=9x^^=@ivSYaTtE{ zJL4aj;Q~TMd1uKp{hs|&wqD# ziX_g711ieT-SBpolU#HlR{w*|fj5o2+naaQ%Mh)B*V{01f?(QpUVPjta(Iep)^7jz zYIk3bmW7eE?7eTEj*?+)Olh5<8Z0ZQjywRYN|}9HVszn z0(anKmQ`}Aeh(ScSgk!jhUM_42Nk2(5WQXpzH&B3t|nO$&-OzO4(o0#%-6n-@P|T0 zRr;U6w^|aS+#i5-0rApgT&t@~9afkG=L<0zah@wK&+TO_ZXX=5Aq)AsBOU~AAuW4E8>C90RUKa4pr^#Rf6cBqwd_w1} zQ&){oT3aR_&*mXteQb3gqFa8a3|0wb@bgejN{pTW-y%)BYT{=pa>+0Tf)5@H@ zl9f|_@$*jo4>AEF2BOUDOMi}}UPrDa2J8q&_R_1k+AI0N>3P_ZF4;AqQiYOZc^DO9 z%82AIWD&sFA(lf+u%L$&2caHguk2=ukX0yWTyO5qp}Cb%(PEzCO*cJHpsxUbiiUry zUsNJYy_c6SDm%T;YmegP%|k7`i>`AI&PfWAmiTuonY+U;V#@g5Y=72h4n^uc)tU2H z+4>tWMNm=K?Enag2^T$iBFXxDoJXfzl#2c`OY21fu%M0&J?c*$Pa!y&p}xVlrG1m< zbFNgt$>HoR5oLU{2kck$6fs@jrvC9*@Cigncz97u31r54NLmqpcg+#S+{ZqDzu8n@^ZmKSdG#} zB{t>BQ^*&$T_Q!1kTGJr6j&uWUHsi5kim_4LC-5V?(QrS2!Evbe1ZY}#$R!Ep#;V& zS?iA?0(PZ|>AG%`=~_{0eSB!CqJLix82ghb6tUTcXS4yT3Fte2U})C(hVPG)YTv~}m; zxC?bS&lBpUWq+kdiY^8$lvkJVBs_HfhnE5=o?M95&tMX~v5#XA1>Zw0}a-h$smM95K5O%suZMSdmu1*3VH+9}Y}Cj8@Bq7b;Z@1R!kq zN&xK<;O@CpnS6NXe10ON`|?f#l_(@=-?iNFYvXL74nbwhAP0VRNg@`b zPfEtxy0N3~D!s*Kg|%%FQBksvZ};C5l4UG+8GpG?t(JN+fsNj8?%%%RNGZDGWU3f7 z7j41qCHyk2hgoa0vYN#v)8d{l@V8`TNUu&75&Gm=yi^M`&WNr4gH58A;NZ3BeUHAF zeH~&Tt%uCbmYhUwY+|ISsv+efhk{Dg_SPFBGfCQ|G+)IZiqqgH{(N`vov}MN&Ci}! z{(roViMhC}?2LYcs_nHmL~^uyL)a)T3Y?}g0)zWp$z^U)s_;-eZnVbj8W%g`9DU(mVfs4R5CJmxA&v*yxwH6F3A^0(P@N;4%v9a zIL&;;6*a*MN^*NS#8?oW$(~Gu=@!GVe=`In9l-eAyy=|z7cpY0Nr+FxO7QS}3*=J` z-<8znr?b4}+MtNwqNV!A%~L#dG(L|<-W}e;#Ai0X!HdV=(I-WP%4Ii{e9Mpxo_`rn z@-1fh^JjPK5OiW@Ra#Wlgo*xht?d&WoLu+D#;W$zAHC~C8w}3&j|0pkJk@4AnRyubpfv$N+mIiktPM*K8e~O4O zK(sFSQwZs|ICP5|4nS{5#SXN>sJu1DBGFzsb5}(r%G|MH?4%`+XJL#J@lE-kH)1T5 z$I^G=w3UxMmz>HoQjYp|;I2zC2R!$Te(QGYD3#wf4! ztN%K>aR!GOfxv~-Yy4#jR>WcO4l(Mepu_K18GCIBWoU8;MAWIaN$f$%q_e{dYh4JE zZBbr9s7;Y|@7D>+TGIU-e zn&g=+MXr#CX;gux#7s1fmF#Sm#_7FXpqM|csXhGFT8br=-bo&G?ted5Jo~%V5YkHv zw&kY9-|*lm*EYsQSNoIRVa3+X!=l4}c**eAWV^d338)ab~vw z=qKH|Uw&xq(p)Zl?lK9|^xzY=>XJ5@!lc#8q!Utp)^xH5IBRuBzesIoWuv$_-Aa0{ z5w>YG;E0!tj;Lo$Q9%U%mTt+e0fFV#!U4jEcfhKYp^2uCR-^hKmFbRG2eKnP&vC~BhbVX14Wy6R?nvg->Cn@$ZD5X zHJ#XkxU(|q2ib^bmRZ_^!Iv<-E2PFVPX&ihv0J@>07P#b{IZn^VwH_(%p!lJz zw<)keZu_W+&J^KV?&5X}bJnIW+^0WI&7zI|8h=&&(V(m_d@qz|ZCZT3M!Abgvh$R~ zZr}%9QU7j#!Q$JWa7^t#gD0bprGrTjqQvT1EZWW9xV)?$Pop~g1>XrUv_B9l+u!X! zy@MhWQgPE5%3#_%V`G><8_0cb?effQDfg{B)_=dPI;*FCZN6;{Pak1#W`Y*8q)g~& zh<_~(HDJVce{9q8zIf-%X?t8p__^vnoXHUPLMOXZx$3m`^s0c0#w+iUf7yoCUao*S z)B|EINE+193=)6k$ZR)a3Ab+jv%f9F^M0z{hDv@pRwZV4Lu;V+dP?Z2=xNH_f4zo> zc2q&LUvkiytDU!2^aN9pjMTz2s3&MuB0-rFj^;raTus%U3fW0Km&XXHH9`V$dR^Wh&g zkws4{RiD3jG*5r@C*9k))7Y2mO@HuWQe9&?TC}ggjM8?pQ+Hrn!!4SSm|Rg+WnyvY z0rz}3NDlXTJz?-xKL+s8J`4495WFG3P%dTzOlBaM>7~`rfC6QW*429K7X1DZ?F6K z6SweB$~7amCJr8=Lpr)!CSK4PwD$afG+6DL8AP2~1yz67(+0#q} zqbrvTR42t(S!$mjD=|?R%{`GFe}ZBck{DLXk9vIONXyFCPZFW-=U*(RMCdwSzeAlc8bRP0?Vc! z53c4IUeNsQ=EN%HU%nQb<_}WOn|+u#$>9rjocD$)>4xVmhvyjcrpLx}r-*kkff!w5 zt|WRmP=i}|Mvrp5TYvfRXu$}`i54Yu1lg=Nzf%1d4R_B||&!4og65^A!mh%;|_Q6 zHfI;4bbV=!`vymB?gcC3ItDs;=j;2Fig}ISlm%;FF51;ZRQpV?$;S1@;#*koN`S)@ z1+s+9yvk$-vs*vYTyap6P*QZxj7V7$ag8T(Lm$h~JwKjN;@wRc-A61@w^1M8%c??0 z(+$z?yMItiF)I8@{O~1E9q*1Av%9jHzp1zn7o7`mI>DADyST9-eD-`lS6QnyiAlm6 zxpr|`Nig_9C-drxV4~es|4yp>4Zhp+Z5nxGwSS(Ctj{V>t?cl>X@t}D! zz8;PTBaY&X0yPT1W>4Kb)$Vz!6HG3xiKHSRB7M5L{i3{nz7;`T9dl>uPo) z`w#8x;fG)7e}HT;KBJke4ozXG2;3)!+J9p^?%%UeaK(HlxX2#scVBqUh;&vy9md+@=;n z8-&;-!0vL%I?b-1XM2NjB0c+s!~{4C2Z$S%e^kGq{qx7#%wgr~e=@Q%bdkZ!n16Sw zeV4PD`<sz8Aj#J4xI6&vf>3Qi+~oQ8;K>M#jMCKhkj8|7tUDH_&a|`m|t!R zFlP`2yZ^~uQ$Y1sX$K?+sS03_^?$0kGcXc&fw$>6+`GV)-Y(0@UsesbINeS1_BY8U zt}aldD#&Rj@JMS+=ehl2u?0vDK! z@JhGutTK35NRus?y&hepNP#-YW|>s(sZENN5+t)rvNA^0i<-FuZKS@0yOdK4t{IAEAvxvp5h(V0{bYBfD< zGBBd)H{BoZi%I22im>1UUoFD`;lAC%?l&dNnlC1bJ=qjxi@+SY{r3Frhhf= z^szp6ld)8^AFd8PNbB+MYSp~&jTnwriYqxf+*O#IW{nCEtCD%ADF)&yMxj| zs0pBNaf*KVH$qH5-}Xjy@rOVz2Fgy;jvTQ;v_}$n-hUMJ(N2W6z^NP~^E@bA+qa0Kc<~D3O*Vx`7CiOt#WKSGd0W_KJ#N%F!Gc z*xBxPIB*fo9TmX1^LV>=!7xEEemE!5^Trbz6@Nv-#RaV4UzAYADQ^j>)S9G@v?6ym=+UO>I(7vdRL@LsZ4Cw5}3ffxuwi4A_ z>nWAI8+k{SVA8=gCX8vsbe3C!{$_!9r!X7BH&Foi&h27<)Gi#qg(fZ6b66w1WDcKq zy?=$&HcY&~8h;r$17FP**N+x2%9c8ZYa>Q*Zn$x0s!iC_ zQP_Cmp`j^FXDt}dK1gBWP{Klbi*q0Rf??v_*Mv?OSoid20wECANb&pxsn&QV-Wyz% z-qx1OXLrP*GQE!=Zk>{{l|?u6O!cjjGM@zTrSBX}!eyfgA_v!;@I;O<0wwuxm49=q z(tvkhmb!z;$TLzbWM1Q6375&2gojI!c`<|CZ3W{o2|x#50lUG&Q&KvrfDBq=FN0zM zBn87SKYNw=U7YWZ;1%YEZWefP;(ug2;(z8K5Q?k}!rpml;_;@^G~r1D2ttOJ20;bt zxndsnA|{6FA90yRARLK_$^6{8A1H%@-k(9EPAY3<6Uyf`#ce=&=W?THW0t&E zW)A+!gc5J-LzV>3=`A_$RDhLu>rh7xKUk6F$$y5I0c6By(wo#3VpwY*#D6D8G$%~A z)1i&G6(-2!-lsRGGW06yT59-o7kFW+*!#+G%v#K?Ze~^d>Br1$*OREohVUO%O$YId1Gl@i#VAA3k-;2;&ah2qqr)=T_#VBbJod*J$T$D11NNe0`p2upJk!%)#~uED*rs8M5q z%n&IDF|daRLV;5Gk$-~pmJIDyWo5UaaKcT)U{dU)XKAInI_=ki)c|&6 zOZ*082(xbId8=7AoBK5aYK8QFMgu+HLhG((QP3u4fnu3VyBHff=}{#z+9Dmpd$PpT z+MBebI*^-E-f=g$e|66m^e7dX-kVryEN$ z&E%-ss>Nf)x#+OuY_}4w{~YJUA1toFL%sJX z?HFvP1U;!2uerL6I3!@INLwT1VSiREr+REasdtV6~alunaGV5{{Ztm zvT-t(F@KV6eJ$>0IwoFivb=4HZ^6h7BZd(})mqd9u_+@D7kHyp%~AT!R_ZcO)56d& z?)Ep4h?KP2aw5)LW$WOd(URM3X$QbuzOM7gvf^^8gSDrd68^UDRf5le->^DuP08ey zX+2AQKR&guF&sHLnvLPbbljuHXV%Q!;mwAt#(%%@WICREl4UYS*Ps=}rZe0MK>c7N zmn_8G@oP9;UZk0oa~pn}y;7v=*G#^Ssn!XD1|LM@6I zCSohx`#&LUqrILcI$XHET;Oo#u8*Aa5=V8ef4;<3euqJRM4Xg}O}GlE^g3N_3_1=Y zhKBWU7?nXRS<>01F-@u|F+o`=F@bFee}8GJ5CcZkA4VPZ^afVE_^J2b0 z4QHQPE8T0=8BTISo?n2t#b2hYn~pdKH(nKxj9Rh?`@~;w6RoJ9Bs*+*u9V(yUeL+; zj8D6#-NN>Z4_nUVIm6yLWeDGs!#G^!Ub!xw<>wSCEr>l2_M>7E(3U;4S-AXeVSirq zc)x1AD1Zx^%_8uSo7qA zl5!xVj~PfL{e-3^V`_tLYy4cF-+1oj-w)WJnl|i6;R)Aoo$IgW$v3VGr9cXn=Y=2kkdtNu}5#~Lm)2lJwl;>{>(#QYk>x!(aRl6?Y zXdqwxPKxXwLlF!Dk85W&gZkebmQq>>8Oi z!XE0o-_FxqpCsyhtC%lE&Nc+KIu5DzWrI7B;f(P8GAluokvnVkyg3X)j(-%VA+`1z zhpqAvXCp*6;@DLR=M$Rc*?fAF>d^K5$+A#ac#-+r8YJD z9kZN>+2QeWo)ub)H`I+?vpeEkmaSY3>1fayA~Za*F-_+wunu17!oIjprjSPQb^PVb zL(EvQ(Fp4KDQWvWPY4*%R)1FzzBJvDTwlo>wk`L>u z$iI|jLj>>rlD@mB3QZo>J3bhk9|QHem9^pUlGptd}Qp0?X zc4G;`5YjDlZHU?GkPaWybr~lo&z(HvaihvY3V?kBdZzb*v$1NE z28dcOe7s1^5q^0u(|=o820J7Hw-ZQ!yK25qaT8^&t-y&}t2BW&u)63+Tz=v|b&FQ_ z67Yxx+OxUc=BS8++8La3>uNaj%lMYS>c|TKm~>{|!Kb;F%Shm=V}4U}^L)KV zaivcmD*lXlo%NY46#)4CvcqnBSAgNNaAu_2_ST`GI|JQH)qlv{ppc;YMXw{6mdzb3 zlk|;8H_u}6j}O9DtU4bS(VO*qiR=6smo)&dOZ($sG)hE2m)BRsGwp%%{NuI&_4~db zI7w-O3IFY-mM}>HkABc2YCs-Zv`?cE)WA1qqnlLfC;S%VuYbSiA{B1k8NEGYeDir( z>xMsXU1EG4hkuF+YC5$|K4Lv!Fn&)$E9bCrOmG=prg}Q#_Ro(`211s-HKD(@W|Rb9 zMt#uleK_H#27-H*y06dPuG+ zisTx!m)X#gk`m@^Z*P~Nuzi3hVPJ~_@n3@GY62-wF3JY&3cvJb}&-tJS z4W|@a5PjR;Gm6{+KZ{GP1U9mC_VG%_-kmb$=YQrGa*w8Uh5UkT7;CUJcO^>S(|41lIH3sp{QfI$JSa{9v|STGUNi zxu-HOwNQAt)fEaY(qYiMQWJrG$&QgeU8+wlkOPMqGTF`w+b}wZxfNl1$q_gFN^o>? z&VOT1wY|CQA!kUhrYIABfXFKhO&$5k#mzm9E$#XU{S7}$QaZq`Y$$W(4Y#6H*o5K4 zW;4`IN1PYQiPh0D6~#iS#cdmaF6pUGrs(!9sN~Jv&GYk4p)~W!=g(=2sVFCDj_0r4 zRIy%o9CJ3;5l^+;P)2!G4S%k~s9Iac-G8sHQ3$ChgAe6()HqjLtcXonZ;!qdxADkR zo_vP` z4efXpcHF|Y+MsnlDC_n2fI$-_7k^h~-hp#{Y{Go6+MrS9Pfo-lTW7^PgoI8w2=xl{-uOWR&v*dhA8Xj9AjmZlAwmr3gt>yS?bfH3mM1 zF}Zs*P=MRvL!|TC2iD}Ot^HqCM$F7D1*({{Z*NI|5Jldb-$eX8EUF%KdjNvAAkwk^$n4^H;A<9YoGE{TbtCziX64GF^9&>B+I+)-OH3~E_@fDc;W_o?<(XZ_=+(avO%#KxqZiD*8 z=h45gobgtUx;Wr24->-xPQ)gXCW-E)q391!dw&f#v8#{ zmP-$wg(z%64SRyW%}EGD#p=P`$+tBUKQC|ZdwLgV8}NNMBgm;-5UP0Y$hfkkQDIS7 zCcbVX6y6*I*^h398^5r~1}wCnV0%p7X=0!HbyNjsq_JIY(5{mht!94xPy+IJlU32X z#c6l)jDHI3DA&{-!Y0zS;7Kw~FZ>=2zW5%O?D2ZSFAj_tc5pj6Vn4bfFv2!{Mb8&? zzZ%(x!Fa#+^hVo5fx)}GLu&h2Zz{KuGI89$OdLu-$`^O%o)_P0iKX#+mYI7uD2KuM zq$-)lk;b0b7CJzm^|}V9c|w($K@!0kyqMS~nSW)2jE${FTo~4@pkgJn657Q2sXJw) z+L$d$3;+4s$ud_RB!aorm{Qt89nR%V^0F;%ZXROM##oS-obgZRa>(k``D*)JM`HtC z87?Ra-YY~I5<12O^M}A$1LNMDStX`ANbc|s_KW>pJZZ}XQ=vAnCC>*sGaxFDtAQCn zA%6hYlr?fA&ERdPh_`lq3H*wmC95ft4J8*vm+{05fB?(vDJv^amGBithdes!SKMyh zhGr!%V-29GnkCnAMNBUoneo->#f9muRv=DhWTXzHFxEltFC%rCyHGLKZSe>()-j%@ zAo-vlNtr@#%ULt&NVSjWzYwp76yfn1$jr)dSI6zO7(iUR))Sq<$ z}zca{wEwc+Ws(&U7 z!ug-5NDaQ~P@+Ohtxny4N%mhkg!EjDg{7_jw+^&EcTGK~i6E^1zpwv%EC|c;|Lf@e zD|9yjvz_rj#=fo4l9m{$G24I1{@tPaAD^$j!Eq2VjhsKsCNRsaZ`l_X97)GL7}~ZT zZaT*9h;RUA{w~CeAZ4D+VG=Yb(Aah zuTSt+;cz$U{e{c=NW3gafK2@DVi*WEJlt%$DOBKeX7urT0bB!#7;fwBbr0O%ACC2t zLHqfA9$a>d252ph(Hl3HCaOzoFI&+Bj88R_epwUVK|Shp!^K4f_Y^uES6`FHUJ!%X z`JT{zlKr0vpY=X6BES8X*nhK3+`3f#*axbig+zyw^ZGD_6ZjqI4fvVN`Ab3oNgVk2=8<-n>yiL(zCSyf#NkF~uwH+95jyFlFsA)c_ zTKHD>-+)r<1I!Y>b@l`rcyf50#)0J&VcTNy2bBk(xK%FPU%^dwi%UN%K}XC*Oq@5&zu6OX)_a{Mzu&ATb>_F#{?+wP3;J;8eenEc zWT$jg1t50z=R-BgJg07e*b|Wakx^|^A`5g0grHg zT94Rzj^)6(&8M68k>Bg(f-GRwN3D&{?pol-uBy~x?QT$L;!AiZ!+-Vm;7KvX>ga4z@#9-RrtQuP z@9SAFYkbn#!EkszO~-a8-SUD!a;FYv&uW>oysGL65cfgT72u8d-u0{%TucQXtTj2$ z-z$5OHFv|e&R}Zx)cM$kJb$@RjsJyf)bHanIYF9qvw4h0y|GQq_kXv+OO3anCgaOB zs6e!7V}J1AqN9&m>KxBLA9ZhY*hJV1PhpxdF{$yRlXyJmH&$#u%yY_X@g1CyBt!{7qi04;x{A87E&aF=p!`r*n zn5P%>=>9;>N59*e$`h6-J$h!$TGZ(%@sIF_M(@#j0hBJ*zrHXQfYn%khGK7D89E{8 z9Dm!Tuu0+hpf1rh_GuIIf~tWxaO=$fgRQcNs(7HN(Xd!~dVjjx@Mc5@cg>g^5%#6*x%q% zcbd?t*8YPp!brLI%(VlYUFe}n))^?6hkw5p<1H?fiIU1{IRY22g*eiT=4vLgO#tr> zV6**bm%DmffO0f-gb+S9;qc}&J2TQSu0B*8d%79MhZY5|iT}mfgRMK6+iwMZ{ z%&R;=h$eR}sSO9ALCG(+4>VaP-6(zt7%)^WN$+nvaN57XG;;;gzuUz;O^zF!Ab+Om zp6_{H%W^WmC)xGb_x^YReqm8fxIEXvbeP1;s=M(?f~q`P{LT)+|9n{1O!2*C_aF8=P9s|WC%(7b(|;^-pZau#|8>~K_MbDA#$jei{)sI3KDVH(q^cq8 zrA7Pq$DdoAPj8c`c%*#DO97k?n^d$5w|cy8rzyy3jiG3Sl~k1F02o8f-dL25Ec6Y21ZuDvX7AH)&b=Ec9Vz~Q}tIzIbe{Xmpyw6v&pv7-S;d@%WC>R;fpY~{jzIk(3{dx zh?(zyavumxG}GBZKCdyNvxv=4Ekxvs5j4a~MIm*8|1Ph?{vAzS?wn_Db)sS0k&%Db z?su^$_HsS9!lj)FVAoWW`+tq^OWou7_^^fi9&gnUuzlHS^@{B2qC~+Uf!a73A3UkW zZe%}7yit9~pTz0(pk0x=%}v**QvgBIYO#T>SeWzr+vmfmnEiumZNguL>yYD>zD?N2 z%&v}ME=@Jc`Fe27Kx57s->si)Y=`vxwNtOn1wR3t_q3x9rSs0cK!3KjwG`1qn+(ch z;d$?eawU5uh+Y4-h6e7}>2SxYYW9G0b^sS<=+S?PBO#RZ>Yb^gwua~-UmF^s|J3}5 zS$E`qkBHyQ;U(dgt_6t7_{|)TTk|yA!sx>V(K=z3kG>XhyQ-gN8x&4`7hdKR=Jflo z-=l~>2FPE-zSVsDcYg{qSnX51A?Z2P^tj=2-HWGsJ)){{bjqB4ai(uGy}0Jndm4vX z;`HhRieIc!AA9JZ$C8FAz4x57Qf)t%?+Xv+Uz5)2mT)*C^Y-Yk6CPoSCx5Uw_qOD#(sJV7I4h~0 z=?2iaZqtRQ_4~Y$R%tu2m)$SwGhi1lH>Gk{IhPl07C%h$?{dt~AdQX8G1AX^JLh_5GoYpG0e^JkA|Oy>$R_h8KHcJj zm1s+Ruy5t<%U5O(c!IU0N#>?8a!SGkM4J!5@sjMxlKvvwZYv++2X>pQ?Z7JxcDn=K-rA4R%@V-mKT|(7(GZ?Z_~gki zS038*j$BLNi6);Y zR&DsC`0$y(1pKp2u%^+%AxI$)IOET>*07mH>q&Z(AX~ z%zu)n-LN%V_YrS0qFdU3X&pGdOw_AH^@nX7|DBu%t5|q+`f* zp!5Ef;GOFspob@8h8=f8xn)v0pyOYu7YBFsUmRl0)>ldM$4>P%%BJ!WoLz?6!vbx> z)WABQ>y7p=w1Tep7dynY;3fPQt30~tx__K#*meD{heHs(=o#AXzX;^=W-~zU>;GTm zy~Hc1`9ItxhPpf^ChB%1M;ZP<9lbS~%Q047+{SAGSt39Fhi06!A2-EEUCJ=~`T^Vj zLs5Oz{B?wl9dB-glBO&;^bpJ-zyVsQ#ZMP47AUHiZB#+JD%CY(V*{YP1(hg;~YJuVaS3s!0Hyj)>ZNYz1Q)rmanYGRTsbemJ2-etmNAH1? z<@9QAXJKcnwR%yxzP_Otn&dZvt)NIiVDa*@Ty0Irz7c{$M(Q_ZNeBLSFgXG2XfZTD zraLQ+^Tm39@tI!2ugRAx7b(NIxVWUI;sk>KuU;aVV@59Jq38Vn+%kc4I$?hq zvV%N9cYnGb+7x{eb6zTM2lx*c00st!zu$yp7qdBNs_5VFQz@|Le4#1Cg-tAMoIC1z zN+*fC&1YS7w#4dKsEmDcZ%a(t6=GR(OL`=nn8($SJHSLJlPm5@I%eZn7(aae=FEiN z2Z5w)B44B!8r6J>dIIIN$`u_RD?xwmucV!$Bx(7z?*SxQ;X7V;QG?O{o^q%AD#x4d zdQVm7difxWtIg+RyopIqh_Ft6i0jJFMzuh=7XSOcO_L&8Nk(D>fkk z;$1LeRPqNeW%{MA4-Xi8cr-gRH6vs83o*K*G00(n#I8Sm?OW0?K9GcPYej#$7lOdE zIejq8b;h_%Qxcf``}dGVRfj#32p(hWym?sIf`W!>xFIkkG}P$1{^;=qHhs=DoFCrs z7ztHW>U-}y{|r=AT=(0@t6yN9LrOe>i{cI=_Dk`SBhop(Hc7Mx!bO*~J2#3#%^M}M zm6ku(t-X4xhQdQJn?@eUsk&%(93v@}@DFo5twxNLtsU3OCqeV9b) zR-sh-iROzbQ@i|?Z!bFIsaB#iq0!Y#LwjaQr0K)>0pABDA--QU9hd<5Q-Y2zMBe!r zxTgHg)_A_>4>qkPGP$1T)ZC&moPcnGBY|$iwbjlI`2qaD2Y`)VSh2-%fu4M;-nNX) zTGcx%pyac;DG0*v$Ll0*IhRuN}of{VP>Z9PLu2?^IEOx zt-mId-~%5wU$sMWkN1obGE`jVQ)Wd9sUe!>g=J+CKr!v{?PUG%Z1|AA#f)0p@cmQg zNYAZ!4w`J7neBUEWc-Q$XoRB7!Z*E#AL>;k~iySh}NkK~T*jws$fyga=8&RZm&SH9rHeZz;?oaM^rUlcyt z4+jY9xV;|x2zi@&UK~&NzZW&){NxUP!sIkG-2z@U^E=)i9;nn^2CcXKw*UT=dQx~@ z`68>@Exw;p;!1yC%vgDu#WUV!5%VLKEufZbH!AX#Q#Z#N6wcHiXW>`#O8 zz9ouwgZk**Kb&sY7kImcA3hQbwakn%DwuDsl0Kdfc^u=w`#o1%Ns55+ap=lNf)CI9i&Ei)(Or*aUF~MEO># zo}xfEa-IDwe{%3=;2q>JnXt8iSy&@egZTxDxSc06WN^I=KrTN)q1Uu(0_Iuea z*t_5HnW5=RgM)1@mvW61-Y6+O5wro%h?ef3oM57LPgI9DyfrD1tA{LX#iwppXb;Nr zy~|SAAdi3Q9}gR^v*=3#B}zqo4OZngjo$c3%d9^)i)D{8krOu(?=f^y|U2C z{i)H({!^`}_c+RLsE)ZIRaKPfwz`dW8?EOMvMGN@DJkCa0KGomVxyY%sQB6tzw?-U zk^89T>CDv3-i&S@oyEmeF}lDp9~}JTjL!*OU$f^vIXdD-tm5pae~{iT=z6O6Tw7Ps z0H6(YOi%f|P<@q~{3gQfH(k#A_pc%%%x5(gr23A_Y@sWOTHl~`CXQcgwZ6Uiz3LNB zWFvp!4Vm#-6%WBmHH*WtW_T2XaC5jGH^Z`gxLqyAMHQ`gFTMTs&dHcTRHpAE_chi_ zoJE4_wR>h;RE}#0vOh8Q{iY7wTPVksV+_He=tjd88_oF~_*GeXz^0)^gAa#N z%{tc=9>S=PsJ)=DVoQiYLQ+z#`4SyD*mH`tL02@!f6npcmFxK!f4#Xpe+X9iUo!_S zbX*+R-_k}b%H?120R2<}&ZIzV(Wd(|B67i%NaiZ5uG7&+VyvZ;m0M*8UjU(u7TbST zrZ7!YGbLe6h<}Ip!xbiGKWOCp4#ENVbm5Bo zLrO2=kHzh1%hq5$z_kIHVASz*AP~4&7i+rjNALfX>xQy;x!YYMc4W1{lA*~;b7Q^0 zq|nr}rdil4nftHijm)_50qRW4LENl*> zw~a@o5hgxDnKPL zJVs}ixmqwb%d--zS*Fy6a;<;KN?V&upuTp!#TYS{*(;Q^B4ZBXuZoK9Y(;<_@+FWX z(4gA0;T2<{m4_W2e_LJJCbO6ctet$^uEa;0w25q1{#sKF&!J#1O7YP-Ve5#-(?^%3 zoS$QVT6wZsCwLPKr)GZr02I$l_Xs_RiBRp#ld@U@30H$>hig)~5qp2PrCW53guW7D^yNEX~bQEGgHi(9`NPuF@{3`+U78e=X;vLWa{vq@@fE#YcCz z=KOCJ8t#_edd95G{l7>{KdUk6*7Jt`=p?aqHi(Pl_IAJN>DTz{wJo08QiTbps;{5wo45~KAGGALcgo*G#- zvI6dh^lmTqk*J?&=*~!@rOV(#+wb(XLF?c5GXvca zvErOg@aKcv++2k$H}gOWVG(D{Q0S`sl~3sI-SRo{T(!*IvCrUG-$Wy;_J~#uuW;lh z1}n-}5$6cX4hnyoGED70Fmx~`s^*ICm#&uj42}ozQil)=d)OEs(WTY ziOg64K*Q4;OkB^$8Ys`vsNGj=TJCe6Qhl&7XsOBHzk+!gLJ;=ZGSB4Y+e{^(ilxad z)Do`O;khjv7Z-;(>hu?y1=ZEU1z49pObCf#x>|FNXjXsZX@I&IG6Mcb#?RC>%{*=%z8x3Y`O|70@ruUaCNZs8dgXx=J?{pi)9~p zn?YYDudQaFhf0Kvr+7NfTKH3^Q(A-7&xc?jH8+30B-n#o$UV+46ephNQU@LA(%3|< zcR_ow3doMh6q;)B^Enju%-eJ0$@Zr3rwxhCGSBsVx+^40d?WE{@`s3$pHJ0FNrI|X zT1Zjmise!xsRg-^>F&gOBL3NJ3h&U^$VV0y@(IrNX)I0hhp?9e?UFwjqkQi$2-293 z@y>sBC|k|~tZ<@}+dJa3VzrEFbzb3M(20u|e?Hrq*bB#ey;UsQ7u4sL)4S0L83?OZ z37ryzeq>-Bh2u5@pYmIv3!xU;SeBm4UCEuzdE{f?mj~QI6pn>W5zX8oxWuBvxHHYi$x^<6Iuw zxeTPl#p%%1+Cr67)kv$DHJS?w3T!}y#l_i`RxF6$M=$F$38SI)WIOe$K%N*&g5Q4= zqk$N(t{+zTd1|NGNzQ4V@*oHo$y|P{Xbz)oH#p&`~XC&!Qc+AG&q~z|U*i^LK zE9xMtPqU-a+kVfs39&=Ko&=iGnce#JYf zZKTt!FJAA?mcNq$QudkD8iAIE#>aOSZL2IMI)D0dU8{9>cRLA?3y|Yrp`)F@W4UOr zoBV|}*Qjw9^dMj0S39w8rrfr(Y7mGvy}o{_CyMcszF*D2y# zemMTZn>Uls3N!RQSb~4chKENi>QfsrCVd~z(Oa&=b60YYE{A0lhu>Z1ha@3wNuyb* zGxl)32HBr2uhpsi&O(HgHDbR7^Pu2hJSr*~0|QEbe}9I;lk;<0e*WaKbkIb;%(e7L z2R#|TqtQ&5JQC#2&5Tw+CSaKFw%lK>`j!T`dilQ7#JD5AP_2d ziygi;14wNO1G;}=d)cC2oJ_Qty#XD1U>EPJH3<8UxVSRz{eOIx*Is75z>p0XEdMY* zs;+)2v)}y3EbeBttgkDn1PvjJ1gro!25_pCkSF{cBlIlbe!um z@j>(WA)=?)b zS^7Z}W?X-#d#!+if*G;L!XlBZ0|1q*aQE-79tJkXew&6&L4FF0NRs-6(V_SOPU5I7 z7;Jrle0Ktmg0QD(jLd4OkwWMKi$o-rWJLjf5ODNwk;)eUxb-Mrm|+LoNlz&};8LeKm%+N3iR4?|iS z|I4Pc`8t(kO>|519>lU8+vb%u$fpf{k63%gVSme$<-cK_C+Ze(qUrBX$vIg&Z>M>7 z<`REyKlf~Gy;Ie0eLSK0eytzlgH*wU*xB183P3h5_?@fgurCj|d$;^w=}=LjCW;I$ zDPcH!eHLzurvP@HD;kmRH!F8_N0Bxj=p zzBC-ISYSuO!&aIKNvbu6`(Pa-ov0zvJT-&n?EnBO<7&#qjcnz96?Bs}gIs&=Q{aPg;JFu>c8m`4WFr zD|~DD`R~`N$-m!I`T)1%JK(RSMfUYLxanc{<6@WnlF6q#P+jelb5f8~Xpf4md5;-a zbK7d8^UKQ3ZoutTbeem!^uX z=+;^F@%2~hML2f&Uk)p~Ga=7p{p0X>#pfF)4GqnAkOKu@IySOhTCm%h9H8`!ET7)f z+vM#O^s_ZGLWv}L>g~nQ;*o!Q6m2fCWaqPA`MMZO8%6BQ=$#oOCC=JyQSTj94L$f8 zrd*)m!i9>8nvj%W#LAE}swd~Hf@ikDm;}abmEPlCZ`spOtfPK=%kmOCO8b znV1;2`v>kQCfMn-5nX>qG#yBxl60*y{{~zznwp*_;c?;sAet+5n&S-GeCnS%DUp$d zfg4#6Ffj7%C;M4{+TQXU%-ox|BM2GFT-@9YjLcGueKAME#5`7SRAMI!EX`(^#oNFQ z8=xMN55zokj^YX&-lt1vq)pfx&23EF@5&uC)5WrOTMy*=~eGAKF7yrs%mP2Zo6-gRV=jUClH9c*<LvV6KZAn1SJ zbkHzqW%76*tk7iQD|+VT0HgQ|hx9$L)3NhI1V3q4(+eTZIO%_u*_spa-a3?ow ze&Q#_N=QifrlWt;9gdF_SS)0!gIm5!efd&j+;fYbSy|F*-m~sBvC$jJBDxZS$o7*a zd!Tzu&x)kUpp6ZaUx9&~>0|CKIJ0G@LYX>Jr+eI5M&fE+6FkvBe*7T4W~6$bm7G36 zuMDIu1qfKKy15teynbwU6}+vLb^#g8!^R|S7vh>a9ut2Xp~~CPTuIqSNQW#X=i47W z^8Py~fw+^8T`#ThNTe1<*mLJ92L$%yVybi{|6Uq1$QZhLuj$0F1R>$yQKP;j+w;I~ z7h4F4Uv+i9vffEh#R@Xz3C^v2g2C(}X_l|$KxVM^>20cfhwehJ!c_ilSx(Uh2 z$$jteZyNv~Cf>E*-QBqgamNR~#GNcsJP_KhtwO-3!R!b86_ThAw-=JAvaGuQXrG3L zmXU?w)4CqwzOxH0hvzMR{3~2sPfBR+gcDMZ}g_;*b8-oT!-$$!d|fuMIO8aOS0<`>jI7=+FQF#0>&*y6UsaI=>5p z$yjI-O-@c?*Ck0^buIh}8#0B|Wo{9rVnjxL5q5dLBtsSJy<`}EG!4|hyQ;*v`?l@i9N)PsLVI=rSpg08bjRW?V ze*E~9pqes9l;EQIK7*BPoR|L(x4w7<5wk~V4@prb;z=R6$D}rghDH!TlZh-!QAM}z z`Kki&JP+lzLBgcvGW*OaCPvoJwm-mwZD5eeP{dKx0maZeTU-^rx1l`~aq&Aw!xeuX za$_EcIM|^pA=Rs&UEENb`=4J?3jSO>qasEu1fah1f$QJP#FTjYi#RvhI9W(DUE3qo z^9xeB1>E-uknJtfVMw$e8XK#0R*X40ancg^%2W!?&ZaW-MG)dH!&hjWus`zAB{?T& z+p8?pxxWs@q52?B6A_(0XX+_{WNd$8Y-#D}R;)||2r$zB)AZr4ySJT(FkL+EP-WcS zY`s?C4l5($kj5k{oXwrJ$z75;`$w*Jy#=`vbD8^OUs2xlXSl&Tfc_q1_LuIpj$?c_ zb#*Tn)Xb28p3)__*?EQ{7KJ~CP(6t~+<@iDFEK@i%6w*i1cF8Csnl^G;F5n*m&&bD z4$XOuDbd$k1L$+CisZ7E)p&L+a`mv@?-UZ5rzhv0?*7i;gqv+ti0)JFMF>@gGb$ zN^IFXTpS#~fBZnHtE*ei3ao#hdP{+~@_t3L#ogw!x3^F}IPC_o^f@MLlvGx<*q2pYS$yjhwBauQrNRyKEG&#l=LknG48{8V`1p8#vq@vI%-er9{KFW2HqRkm zcYU}t_OVB%&JMx8EO1GubpsOj4ZIwUGVAKj$GZq_Ao4sI?NMp8?IdHp9BO+In#S5oFu2GoF+WPr<_9Bo`>^UXfJW5YE57AIV{QnDNFA!&RtNv z-QdHwin#T{0k*%{sEpUw6Os~*YjsE#`^IxO=@)KBq+MQP%D!UEm-_Ms%vZT_ z!%nuR>zhWx+~I$@v<6!bt?eCH7tcFpC0lhRBYk#nO^v5|nKS#Bc$}cGi`;7L| z=0%Til2@H}!KO+6QHbXbx7l!JGq5G+y7Q6DRbrpS%7 z_4v5Z?j@$1^hH{?(Kp|RF%w_EdszjAl50D4DXG3H7}9mS?m}4TqUdd?nFgVst7VFz z>k~Y2y7Z=e>3dU!w8%DsEpsWKAcd6(B|!<;w-0~Vp>Z@bH;;{vmz3_euB)#f8XBS& zrOoW_ra?9XKjrX1jr% z=7d{9LPGELWnyBYil(MCOo`(3^3px}W66AjO!2fa2Qe|P%X7!JhpHvMz^=|;!P%U? z^Ams40-mYAqMIO)topD(Kju0(;PHu-mTvxOM%hIMC98YSdj>pt#Qe=x1zI zgtX}^2hP+#(brQJolE3;u4J-W)pQ;5j+%dvg-<^^!h0oOhKGlLRj;rxcn;~tQ^G-L2^Am<}OwngN$#l{@tPUpQAXlgH@!YrMdi<30p5$ zmoCQ#3u!~*mdgl#qM}~z_Xir2CjGx}0sg{aG6!2`I22-frmd#*+_sA4<`T~^oSlE& z$Cb^#JU2Er{y_J^sD7b#;pqE#g>tSnsn7MXyP}`>{tP2h&y>Bq1lB|mA7o`^-45sR z^1FUiXR|;0``;vZYFig9l!)}n%FAzp*8Dd+f1)`ghLl&Q^*VMugpAqr9M^0j6Thv- zZ5%Ur(x?DXZ}Gj7NGXHC>8N;m@6~^+lWH+`?B!^=Vl+kTU0%zMhhgi(rH*8InHY;9 zcJWEt%R`9-pQ}TQ`5O5f^M$vnYAspk&Z0Xnhh8W+@YnErT#| zwL}j{kCKKxiHY6ZA&_VU9NNl2RDN!`<&p5r-HH9V?5BaNWRW~kYyKtQLpFcHjyo`3 z*J0x%gye%q0Q%F!RRZB5Z1*=z(Cb?*;2eE;nB_Y}!Tr$mtZQv8c~Cy*oZ>;YWfu=B z7Ro=`xif(`Z4u&@{}x%QNYzEr!|qZPkd(@C5d01@zVlooD;bifCKjj!z%KSpmvmJE z=+*`V==Ti_aGEaKZ*9X&>vexrFb{EHO>t-1bqOwwH3_iK#nZWxFul9(98ZsH&eT`f zuW5zKj$PrpEJT=*5rbbL@41=dM@LzdGKHixJ^0Mc&8rSvZcdE<-G*3L&;bAdq^j0h zLMVyY4HT@b7%(tS|0p>q`udU^=Nk9+^4xo)?2k%@`tT=%*1Yi}`!;`UCKls>lMY$Y2^0v-+T8KdC_Oi4^ zT2?N(ibc0Js7haTr5o&aym2Tt`?0X=EN@zH%@jQl^$8{5{@zy~E>k(>6%&yif0jf8 zTV%P+4lb*W?r5UGsXTvu>K1BaKYce=__tRC$KH$B)|!;=Dd~By-e({ue$5hvrNzMX zcrVm+;((J>Ml}iX@g-C|sPd3O3|00yfA&|mdxBO&^RNF>Vzs1^ED4mWWs4kutvCeU>0exm zFf4;N2bG2X{T?R%8ps^BxsAE80nD{uy4o_E6_M^!dslYe-E%jde*YRibV=}!pW;g) zdHx#`dCQOgu9E(HwWmL$?C<&rNT{wkv{Sdb?PxV{bW(rBdJq2(fWuzP@J8Os@|TIf zZc~ymGb131BsA>sj_NCUsi^ivN-AHF{H*=IM>YLWCx2fhPUdBBMl+7q*7fPyVP)ZI zNvwj8**kL;5!iu2>77X#T2$)_#X-kuNvWHvJNFa(*E#*8y7}k`*OXh$`&yDH>9hu` zu8G{9g(iQ03c+SUjX7T{7VoyK!LY9(SQOH}63>vJ+W`OY-^@pWvdmk}miqgDH}X1k zA1A9MU&1iA6$jUyjM%uhYEs7LD>TV* z1`tE3$kFJQ9K;-mo4*Gz7!jL!`x^;8uQKLyGBs^$Yxk9sacL$-wvC%w{KM6T_~qpc zx{(azoc?_10R}ckp=7brhXy$s27%|lxeQ-XvwfLOL@4Gi685525WUt;)wWxxi_Mh` zoveS;u!YJ&{++ssN0Ihu&^U=*H)7K2eX~0m3gdb3n~i5%rK8uUm-ca{TJ^u0&I8K( zy60GRi9Lp1#l^*?fB1JY(rkljdgO#CI@)s0dpSEh7P@#~0z%@IGwPZ84!^c}ev8yY zXEVBlg9A=@xU6Cv3G&d2{+Nxj=BKSm;< zq4&jr5yxLAfp2nX1*7kf!K1y+)xoGfOn6^tvNnTp>ZIuxvoDuyR1J2y#7h5Ae#7 zivB#+B$Xgs;?=2)O09v)Cd%oVg?oP?fv`bS#${#pHk6;T$mig@0y;itCHVC30kc=t zrB46&@?L~34=G|jSa>((O*pdbV3wz>4nK*01Muzs-Lllex~< z_IlHfO8p0H^_+clX-kN&X>IR(hrDg5o*(*|^6Yo02D1ZsgmN~SIX~dQR z$P6ni+MHGQ&=LWDtX@%u@UfnpJ12GFwzmHn26(F_jYuM=4!{wUGa|Testd_x<*VW5 z{kBlRvd2+5_x$<3yo2#{lJtM+4v$^>h(rMv&xuJ0VmRqdm4evg&5GI<#$4XV@aqQ=NfkBLuJujfZ#3CK2G`x zeIv5R=s`YK^npDSzS@*M%3h3$q!7KQWbsx(8OJld?n@iq z9JUcMP&D^!{sVEe=&slGvO8wNl*9bad(Fuw?)L)Z>wJ-M#uD_VTffgc*x_btZ@*=U z>b)zR>(P6R7@1(NcOa&>E7v*JmSE{V^qV@+ghEiQP2raX*HhfRpk^L4l=z|E`wIy= zX#{v9MS)JsIKWf&`R9K%s=v+Su~kQcV9G-6>vww2O#S?+3M>K|gF(CXdkbTsuOf)U znt4_>Wo;T+e&vOH)2RW=c_;SW+|>z`ryPH#11^ak=`IO+$6Gp91tJwb1p0KxWjYYu zvnJkYnraveGB+~M`tOV_2?M+o5ViJ^p2sX=r9sb^H(F2z=+%GW5$>di9VcMG;9Ll) z3a36=20Q$=c+lMeCT7;{O63mvqRnq&09T8?g_31vJP+_#rDORsJI&XcV`}C-m<$z~ zk<51LHLFLwf4v`0_uhImU^*>P&hNuJUpp8RW&<%Q6SBl8Ls^#yHPhNNz;Lf$RM2CZ z>Ry+fjEmVKt;v6bfW5xHO0a9+7U#vmWTwBQ%#1c~4Lp94N_A}cHThn&iX*D2CS-9#Y|UiwxBl~6%m&aHoAP@Fg0>z{ca6~Iku0R6?C2C z6Q9Gzyb^zLKz{o~h5)M=c3d#sV)oN9WHUTwy~-YOXHZ&aXuqd{^>pIJ8G1}EQ}g+y zT>kD2*q|8o_iv$~jv^e?&bW@4`8jAVrP%WyD#blj*2HCk9`42s+Y3wo0zJA)HPz7E zm35n9rkcEp*gy@S$LU}{P+obMMZOI=6crSi{n&rq!0HHLxzDG|cFhWYBaxvomgj$* zh>dL2oS;S1qOW%sK=ic7On-w()b{S2RbiLD!Ti4-wWQFjgWF|}0 zI9|=?mOdNbPi(#FjbHY*riw8m#3Rq_onU`1s&oYd4!j1E3_djHjamB3bbwM9*^{IU>~Zdysnd~M6RnlIQ`E3 z$;H;)_W0v~$?eAxPiFxR#={BzA}QKIMFa>0pdl-tA8>Uggd`Tza(nOI#bMzRLu7x< z80h~0eo-QSLU-k++|K65vfMuv>BbjwxqQezTb_TuC;c(#4R$Xtna1kR#AO~pf-PT} zu4DFGLExGkw^+_)=f?u7`;ws;gwF?L=1dZZ`NH)<3nghS$U^#R(rtL;z9=nv{~Lbo^rpRx78CML4q|rjPtgT3}@Y7ye;WqMQ{6MNn+}A4j`lZex2b(bMr!lAt>f}#rrP|&i)^3 z<%l4Osj#20*U#6_8V~v_p^krm&vE&Su`w!6X#NlvJ#r;yVl4FT9@^cRQtsGTyr7^E z)UT=RNS@2tAHFa83;5v`%=Fdh8;AW8h@MRhCw(kNm5U+|`RG>{-lFa8{y{;R4^y%K z?NK3X_?~Xvd9*)uqHanRD*g21Q(9G*6f!8(IFl1KFyjCJQT+wyB4mGw+#EDqWwP9~ z|0BqohrzL-9V;EubdVh#Gk1M|6MEp!u)(k1SG%$!1s`%+P&c^VfBQcKZByGT{touw zO^#|x=uKkfB*tP;lw=H+Fa|ATLJ~uIj{gqE(pG4i8n{vTasXU9g%#}}emsZ)CsN`-Rm z-M4_@Sy)B=-*$Vmv&I~X)shoj7mL+kZ1aa6u-8CVvMHe4|1BU|NFXLA2Kxi-GWx{$ zq6x~()-){Lci!}Ed=Db=Xz<@YItUcnp8q%g9CYj*jLNVfL^z zP03R_)=VYX>8X!8)K^1 z%fl?r#y2+*)W2pUqFn2wF!jdA+l}m^4|7Of?wzC24a@?L|CRI|Ky5ui z05iVd|5$%&Trs?->hbwQJu&dr%tY()bdIU|Ow-{(7&wuyfh8tQWfBi|g$E?hFajmQ zLJ}LCsrjQwJ}IQQ0>qyttZt**e?s`oGhrFw;$^*@xb+ApI=;~8(VldGm77H7R4kdX zM27fuv9jer37E+cI=GYlS- z*&bnZl-`yY2y=@mKEKaXSuhf(C%M0N<-s6UEdEPy#P1-;m9ct@L( zwFYd^lAr5%Z%jnYk@aKJ+qrR{3`OObZT9Tq=032!EWw(C_|JR^`;(SnoK^kC|s!j=dG-Po@BCm0;*{I$I( zlmZ)wJg$0!j)XE}^w(PZZ+_~(I=%kL=>7@>myK5XeinnO3ME3;Mc@_b|nKh4wn(@@x|qy$>bVv-?PHup>fq{ zY$vfvmi>?<^IIfyFp0wC?9Q0+n0nEV zE2M|)VS9}$#%lCel^VEF)}?P{I^dY?{G4A_z>M|%ZZ^Y9Q8z}Hf3NI70tYLV8KrwSAZAR59_ymNg0`LcerE`Lc1-}tDjw#87SSW zb`ULg8|TGVhL#kW&i+}^tkWg&HPNqDemMJ$8Md1*c55EWR6DP}(-nWcUz&c~+$i%0 z{AKLPJ(;O)KCzNV*Y9lbJ)!u$B=l-ie6{qMNoaXBKcyy7x)jCYNg^pJ{`)n>4dp$A zWws_xsHAqKra51_hPHJn6C<0ZRB&)v&3i+0^DNC`?kSDi()j(E@Xh_++Wh_Ri+Gp! z^~&WLhb))l^oC{sf}?+jURkSZxF77=VY4_KqRQk5XJ%@hRUFRKSRpc=Vh-%e!9ow5 zI=GZ8o@V^C=jIKx24I%o+(%kJBpRB@@Ls}kOZiuIb3Dk|%RIy#&yHooRH|K={Nx4f z1mzsD+~s?8_9CBuOZ-)a&8+3(65e90&Q6H8dr)>U<6+;bQu}|laGFH@OJw8zur;I< zp9svXl!BaZ7h^MB!s=)&-8NkIr^8|-_L+XzIm@EiH zgbqZEh3c!1mg-K+nUvS;T5k7*gv369x*2h5hUEqG{`;Y(Qp0f_veEWS27aDp1^rx~ z>)$bDu7c#6K-+(VZ5UnqlPiL=4&u;Z>C+*&20YS1O^`2Cw~2qCHqoNI8HlZgL7P>@ zyEdD7-MpiZOqw~Gua$$KCWECh>tTY4y^JZrWS%mxG%v--rbja#-Ix4wNAt~?gt|3LM*`$Hf4G0;3vAQ!l?KvIZf&ku{Zrdn z(dL_W{rcUawug(8X0Hiaw^mt4w$@dBT5fqCq$o)_V)JrwYY->ahiMXmaw=uU=)Qtq46$_#ymD zKJ%`Kq7c_!W;H;_Uu3CzWt+%f*Y^$Z-uD;4R96#Rjcn&o)gMXpGLuAQPOh_PQEIj- z={SEpo{7Y27yl7yrW5*+>f?gYg4PG?uV%e_71rKJS?YZ?UQ5Guoc$%N3lYjJ#5Z8? zBblM>{x~J_JK$*0!UDJ}w0+b+|LM`uk@87N&?nR7dekl`1Cx5ZPrp(UU^XNxMiT$s zd}-(-@a^I)8`O6D7Ic;@GiInHSD(ZETpfQyxqUyt7jR~12fh4Dg&$vL7XX-f?{a(- z_ar}qpH8f-;6~8(Sfm3f6(Y@X{E==qtkV0Ctk-k7_9O?&DMOs@2*}l+Y?YW*`I|GZ zjqR>CR^~#$G~i!)>C#QL$Iz~H9viUq>e+FqGAn=gu~+&SRm=x!A%Z|AS0DD_XbyjB z(ikPrD{hV4I%j_yvi=|AzP#o5$*Teo*84|gstABxL^gm}_B?`b&_HmHQ$WXJ1;P zS|j||+QxP%G04}>&_D){hIDO>;23{KO-J7ZanFt?=IS+p-`$esO|GN(4ol_2RGCUz z@I7yM032sAru7%4;i$1h2Mz(%TK@rLd1w<}dCKH?4M~*?#Zx0bdC=9H6MY(32?=+=&$mv(&~yLN4^d`#TY2a>MJptze6MPFW?4CnfS?xB5T{8;br zOQjSX2=%TvcYVF?!O;qedwnmH;XD0&mby`-x2?=AT*KL^cP@Z-`O8XF>{w}gXi4ti zKWopue)4Z0zuR|fsVBTS<0OBh8ht7n8nA1!;=6>-t!p$EvI684o0`foFS(iW1H$&b zPoH1jf`s*!uG<2DHcKq(dypttNrrzPOt`~GQjs_z@0TyuFuQ=xW%D6j14Cs=|DV=j zpO4~gEz${px)^$3#Mi?z%B=dSgI31EnSFjL^-@;a#LtfEoRzAxQON;G{;b-m^pc{t;R|t>=uw z3onjlDxS~d(Jfs(9T|VH`Q#Rq)?Uf<8t|{759%4yRnGb(`KDwoPHHSnL82LL^4>_6sI&rno{&J|i3c_@w$xi&jzi zevF~o%}?Aa)t_TBWpEIshGx2Uq5YkdsF%jItK7hUX@QjMr6YeiMt7GXG^Y1;9cf^b zWTyH>jk#P!2ejVe-sdIhs|Hna_8y6~j?HPyLNlx@rfbS-sI|!@j(ijJzLmG6BTCE){yPsqQ>kPfW2S+UHxg*<<)iWS>_(Bl;d|6-<|nXd4!#dN`*v{&O{L8QN;ZarNGJH}4&62=2@ z(F3n(fACis4s37IpFFT1)X2DP$Maii>V3W!iGK6$e+{r62h$w$_z334e;?a=Pn9A6 zV-g+^66$~OjmsPS8<4XVTKPueUQnY#YgaS`^M76M7yVrk)_pBw9~Bi9H4B;l9`$PS z`L94S&oMHmYOO&O=l>fRcq;Nq@4qjT{%zH}%z}^Uf4>BkPyts;%ziZe-xbFyvQHFZ z*S2<|rlzLMjufW=JwU?0MBM%R#zNx$)GOn*v9#YVC@AQE_xzE=A!U)FIFu?G8(}(= z{zpPWLPX3TxSv+NKVIwdv8qvEI18eytdJidr<>Q^W0f?KHBxjRt(;6%a@~wU-3wpI zM)X6ok9>pQXk=b|**5yf?{~RWtETYrfi*()g2{ zZ61xu?u;WAmE)N40X>AHNmnLWkZD(dR$H}A^s+gx{@5$A5;N0LTz0gTRYG+nR9eo7JkqL;2$Tg`ojPhHbk$Ez_V zCk%`3RHLp`jxI}-Z{K!jQSES;n^Eb1^nRIaezJOWTqgnvj0r26sbv+)8Q2xxHRZ~* z>dxaH5V=0IoPWcTc`a0)KxM#Guxwidw^qoyyW_T;X6BKcYxpFczJ?jn<|CEA2 z3A`(Mi$^kB!Wl3nLbDS34HCQtJR1>2hY z&r6R)Y;Rr4z4UD(z(FX(yyfnbRG}{)Bu;@Y2!}jtIY`h0qEIZ+hgACB!A53 z)%Hgdobi0TNWOfj&3td2$+XyuHROOmz{UylfD{n4?h8i z`{!;NHVz?!VotjeB5PAc&yE7Si&T;wJ`~knclrbOHuA&6neA_XJrI1a189p5!mH7T zzSaB#HH0>bVuMddrB-Pzr%*_Y9S~RVt(U=*YGriH>3|qrXfU+f@9m%^)yQa`53VD9hCpx-+I3H((pGFWmQ@SX(Ks0WLL?mFN4APcqS&%H96Q1;yoU% zH8n&bD^{NIGL!6-kY24 z9Y`Lza6wr;=b>KHXtf(1^4#;OW{+^|#V)nRWl_)7TCe{Z-JkDa_{-W19j;$c7_+PK z0h;Zc=h|illdjz+6{5Fya5D;pL`WSYStxemEt}>wTkbMzxb?!KDoIzD2z*}W>S(W- zEfzQizL$T0OsbiK<>naeODY}r6J;f|9m(!iMip1FZ-zv*e_dL~s})oz{?>DMll^UM zdDhifb{OWZqrgIzFxKC8%H_UdKz(W%X1kQUhPf4R&V z)P;X~B>Do7eCBW>@;AS+ujJQ#|M^Z1!gnC(Z)zVI;qDEOgzL^3fq{*zRAeukT#y5p%aClr@~kg5x~I6Jh~Go|58 zT=Q*z52^L5a&SPkQZ{5PIs&>vl%8x>Gbq+6K$&A261k2ZF zMbeHrZD?9-XjcONe&x{Ej97_rP?Jd@ud@CT%0*|(G^&}^U~Hd%fvLB1#)9gzdnU>k z+JZraV#M+cy#1c36e|C4S$A!MZ%3R-tF4Hi|EiXzmDRz%_*KeUSu!y7QZr*Hv?6J6TZ;ScMLfW9a8`V^5OBZiZcAN&oPU`!Vi+si7G zZiDUH<1Yn_mTjHFI$;;)m_3Q3vmRzDUdcAcquHbd^8{6kBlmXumq?Szn2T!T0TU<+ z6nqvt(qpo|@tLi*YXHXD5g>pviu3`0wA^<2NFBk6wAD45e76A;lma&6iKrwThm`wS z;pbt(RK>yWcIaxHGH$;c2|e>F1B2&d5vkD!j0&p?9?0JN?SyL!ooc5;IgI1S4i*BRq6{ z3-eEu-@dI>R<#)9&M>kOt)(Iet_}%~e7D+76!!6x4RouoI(@j%8OywX$ah)K8=b82 za`$w;SV2Nu(>1W5oc>u=9|HPKfSMgGVxMxboX`V{=nY5Z7F4#nfH%7V0_(C~3C?MI zu{U4dQyMHo_>3+lh8_@%E@nbfpewx_n}$%4$&G*i%Z3;W9H%y8v;$!v&0xjXEFaES zsD0Y1tM_H$Q?$uM=E3fNO3ZTe-KkD}#pS0(sPXFwH{R);==(BuL2nS{Lex1Nw6=Dj zejebhngdAh13iAy`lr$W&+9ios_%0(!^e`J#6DuK9yaymg>Tq5x`jOSiJ3QihhBJ0 z`Bg|)P6T`lE6LvYY9k@xjLQQbqYSXBU>XI&c$7uvvh!jAC8j2S3XfK+Q1S6~rmmB} zH8bKwD1$J(H62dhIOG_J{1BZay4U+*&!J@{T@(WB-ira_470cqE=`nr_p9@-o3i4ln5I)}r5wM}=MK2G{IR?LADBeMwA!NB-p6=IqLPM@b7FT2Oe3v_)xMREjr z3>G#1l2|$wKp5{R+17lmSnwwC1h&!H)AysIy+}O4!Jgz*lpAUs;JxW2aA{HEx=wB-ee3^FD51+nbq0OXX{h`L3QcnVgDSzyQYzzfm#I5-0s81nloije>a z0@dMI0gZ%#LG}=Fhh&iR`*g%T7Xdb0@E9RO+x_66AY-7su5@N?khQwUI`R9~8B)co z3%nep&fx5SoflWLN6ukRt;XFsesczv?v1nOByt+)4N9l&0W!sQoY|xs`O(l3(BZ<+ zxu(#D+j_0H`g?EH*Wfj2(&5+#-+B$#VD7G812jB@`vlP*m8@p6M(o3Kg|tI~$dN6+ zUlHb~4ozsyJb+C{ROn4hXcSc&p-dAPed>n7#E5Nwt@6Z=7sWDw{qgu`{>pk?_s6e~ zVmZ#-Af{MgH0_T&hQC$eOu2?pwO95Q4#-Eifb|Dm(ds@-p6BP zR~r0(uT4dQ>b{8zX*>*4^k%@X`f4^#HIGsnh{RugPT2E>s4|77=4&qO6IA==6`=Y= zy65V4Rk4PTvAmO-?YhW~7B(IRdkAh&+RyRPzF`8drSJs}Y z7PFD;S88^5{$q9;OIF>3Tny*MU4SF7=}DC7wb{qib=gzsd%5*Z$uu}cE0OY#`|ofT zHQf@T?y^0o>uYVd-2-d=AmictBKYMFjE+@yzjPJ2Hmzu8pKTsvI(Pw8xKlc`aFyzR zow?M)V1k}LaNR9yBc$+B3fzW=?u2vy03+B^WrL_*>5U%ghI3+0mgyD*Fu8ZWFXwzZ zB$(3MC(}r`KHRE#?<+UQb$hO8oRfGk+D_UCPxf?Zb_`HpLv_N;#v_EU?k5sM_10OP zK!d0bY{@LhE~JaJ7AEjbqUP|5c9}JQffm9A09L+hdAwu-9bLuQ(yVfAalaP+=5K^V z2}IGh1KF*E9T;i0@a-`Z73KfF(wx6eF};|xK<(UNYc=HRZIdw5B1`uXgI^G_uLqGT zJ|Q!3=nua+$_+#7Bs`dc^AsiNyma>P`oN!oORJ#1B4PkPVW_XJU-P;h4(6zTLMEIn z?{N?Wz$iz7)`c;0i37H`vo&V2QD4~9mXgs1gy64_(4Vv(4`pb!BIe z#QU;=pzh-R8cSx5QZZ(NKdRGz1!AhH1A5GawVB;I@}YCHoXvD4F!Sg-0gt?&(h#W6 z6*Nt7B23!wHE|;F>Y+m=aP^H(-mi3bm~ud)A=jtk`Z_}hPhLD8^hB4Gh9ZxN__bRw zspam6H}CV4p5w5K=$!$C_R1ZX2$`LpILdIvij{1&P5N`!IR&LNKmVkEea9V&R~PD}d?Tb+9M+VZ#KOZJKP^=@3}L;oUw zTYG?3v|d$hdwDcX2e4azs?`+)yFctiv$H9}UeL*bsEwz^8p9eZ-ljQ&*QH zVwet(ifThRAE!0RSHzZ`+sZtk$EVF%k?&iro4b`EgyHy-vbC6kcuLJelJz>NpBqh; zKQw3u74G$FI`!Ce(A#^4qs3tZ11(V;L2wi%TE+%VlPlP5G}Yyf+X%}Vf50P=j$Jwu zV1Qbh>3|Y0lcPd^E7doHrT?}GlDUjoe3u(Ia_F7vFoJfzjKHGZ{}%Vt^J{!|9$Pla^7XsB%TxvzK1TEpf{?8y@A8^v6LjYd zBJj}kN(b{jsI#nDba26_zBym0UCk|Pq4Qqs@~1NpFXQrmHz`7A$t;9$50U8I#Ag=e zP0xE@GXa4pfzB8Ey%}6Css6HkQ$uuPnj{55`FPw;jD|KSQa0OAS~(xJPp&?^Sn$<% zJ^8!YC+mbt1tRoLAxiQ2Y|&-5Nul2mb*G=)AvbIc)$=xpIO;_bBWu&nOiM>HvOOTw z8j45(Z>8GJ zm$7Xm*+v&v00-hL)Du_i0NK!{+|c~=oc|fA%kCAiQme^dg)&fs9_!cTO7bZ74)3S# zTvV7zhyF(WRJC)auvHFkA5TbDuD5wka?$Co{XV4y+J94?;q{WeEC* ze*Ws@$CXjc$UyX3lMUjfpUdC3UKu12^zug32|t$GvlBIf$UlN^6*`!Y7o!@e8?OK6 z8xkmgdV51vD;XpcY^Hz#8jN04#nHQ-pPdv|Jp?=GnIDqldFX0>qzAvC z7DH@ORWlN9tl@D-=f(5AaUo;dH(GWu!^MUqUXmCq(!kL0Q@Seep4kQpR#zG#=rrO2 zapn6?6mpI0tsLZ_G0aG@os#u)EkVs18@il-np|4LBor@Fba#;drolybSB=>ab^(I6 ze{+=kD;GUx{!2BDlPk07+dt5xvd=rHeH=z@3XT@l$OJ?viT{R^Qu&Bj%((t%*7$riZ}gTETn%5I zlVzX`{u~gdjv6iof2O;EPey6;@eP-M)t|Yzs+dwPd1Cjhxo_%}uBt(d?QHc&-*DHh zjWs+OaD}sCXB@AzmmE%b66$Vphh%%_$vh2Cre;etgipxldXmX%%QmskkfZ!`Xe30p ze4>sY(8WRZQ{VN3AVfw!rq0G}zHU%oOaJ&?e`y9h(T6Lb{uevGCMPTsL*xj5>zu#` z=CQk=BB;H4)74r$&uYNP6wKB=S+df*M0#OD?yk;lSh%+XG!4#V#^a8n*?B>~P&%=r zM;JezZE-AB;Dj(BbJ)GVzxF7%%Q=`-ZD=+^7TGe8MNbebj3#dHEMA`)37T*z~l3p z-BFqnGdm=@L-DjO4sg#ZYfjpfI3C#fDLZ(e&l*(rlZ$_PAA;_yfXJ#m&}g;{apa>jE_^dVM5`BdBCzWbz>zk1~vPS*?`i28cb~H$I5y2 zA<}zRGaYQ$gk~!1)4H6o=>m3cI~!c8h<-Z|R!tBF-4|aH%g4utS$VRU9wB)>J>XHy z{2W@VIlhsz#%70&y^Sae)2jva{_X|*h4t6d3>9hTR?ht8FOb-O&7TF0J6P6JteDy5 z)uEIn-v0slezbXeLEKw^p9verr{SMA6vZwO6t)}6dkar95c22;LwU7JSaDMWjSF)& z1qRUzrS7#nXPE|xj%Bm)pLty}Y83AUt`CUj+S2jD`<2RO=OR0o@V{Su3)EVq zyFK>J0#Yo9WxYm=-&xBxnxZA7tty;mk(uB7YnR>UW|%4OYBd^vlcJU0lnp9?+^)Jg z*z+XlekX(vkFBJ)BK(q(Ae+4(n9ooM>rQe87$`fx1UMjJ=8UADeOO`3Q9#Hb(Khc6tjN-`8>i00^g~H`nR^C z>^$FY-cF-5Dnngkzs`0FsWX32wfs#x^Q7nRc)<4A=cCns5uS!?Qr}wijMkjPulntr z@2ZbTN3dVg4<@^saJX;TurEqH(gI>Fq-7f_NlU1fWj!x2K zL(|wVCswMuG{68{_6rVo9xY)=RC)sb>y;%TRb7e!OU4F=VA0Xvw92zxew^3Gu*dn* zOCEek4O(}9;_}%8OD^OXVBb|I;bmowYT4LZBCIrPe-#?y%a50ySTYaPPXP?Rzg}ww zEo_Kv|H6wLN(*&&r-E2+X&IWFq|>Ir=__J9+9<|bBcP8<$BvXPW+G;k&(+#A-7@DA z`_)s5`|e>_Q3no~E+72r+`ukoYszYyC8#{FYFIIUF!RofH^0Y9dymZCl**IiT^CZ* zkVL}7_8Hkuzdt$@7WeoqkT6GN7OI9b)o^v8GER#t&pUOZ^+J4n};NL&DOUc}fi2Gs~^cW+`{Qn{p(IUsxt_nx0`Yx_7{ITQ#6rnQv5 zb2UAGIHZndXsiEqG9?f!NSM4fxJjKKl5h>NFhxV@l;>!zl*5vDRfv+(xPW}iKoaFb zl=2gpI1*4uLxZcQH$N_`m?6Liol@pcZ6sj2DxC`doE}_^Fd<8H`=tLX`Qev-x-}x# zl%k<=8KJ)Q(`KK`QreJbkbi={TtqRAPBoK%t-%i)edoDU_;sjaahvHD6S5`Ek+{_K zh_E&g?z&#oyzxHAv5{gq-bs;8cW#c^K3Xj1c6j;Ba8yTNZ>?KdD{fQ=$_LS$KN%Bu z=+Ii;Z3ijx$&CaAi`Y2dUqs4jzBrsaq|nNyYPE2Am;+`U_rUy6y;pZe_NAMBI5FXW z;t}q(?}ab*5Ni&Nn-}lB0Y@$)Ng zjzc-bl3o#C)r+Iqh@^(-Z72xvMb<=lRT^|WKYRs7*Kwhsgz5ytEC3nJ*Ye;|Jg~v+ zd9MEUo$k^#E8ve2*3iHvHQF^8;~H*%E97U?y%|jGWB+OiJK5N=wL1&h7K7#OcW-MF ze)}$gnvwJwK9uKZVGwWqH}cj@K7#dn>-=|Z3uzCYk^xaBE}7YcatL`C_RIkxtVbzgndX!8iydK!4AEn8%m4FZ6Fqh)hc zXb8!l!6u?t@{Hi+m$cJK0c1EIp4U5G1F4Fj3uiQEv4KPIlf#dl4GR3Qij+~h%EhyA z;ePvk9d&~9V5vy0v(1UX-T5S-6<9PR`6C4H%O{lNqPH~Ls6(5bk*PkEoUY1IH1$mZ zl!aK)G-d;@aL0&4^c8g}ZS?_v%TJYNoMpS_yBnooedLFqz*y0YQ0#9ALmn(*tUN!d zT6~&>CSzziy1U+dkuMb+5}T`Zy271B{`z66?JvU9jryKpgqg~SkbJzYq>qoEyYJbX zoPtA(src{~APV_~+%;f;*|B1-wRSIVN{-v}?VJ@4bk3#8;cw7M zN8EqDT*Rad$wbg_F}&*&=*sqU;XEO5-vk8uYV8>52tH_F0``~5bbNs@AU&2)PZ4DI z`lApzU4IEw0~mPt!MY^tz*YOF$IqgNuZuA)IL$=vNCbmOU_Ni$1S%{o_b-1;(8kt0e2^>go>V3M-1x4hweKgDBCtR zd?GJjGaG%#Sy?_S3N+fR=4z?6Go`4%MVHbUO;S`oSgU-Ky@UTY-QEZQ+#``6^nzm` zavIJ-;ervfR0mIgtgm#h_am`>+eTdaDIs;w=V8%=T7?}MBWK#25(iN`hA4Xt=4BpAc#dexJr1E@ zxSx;-i!ool%_s#2f)m}C^X%Yt)}6+`uN@Ga?!3Nt#XoOSq$+kVZtX8ZFJ2HR6rzU9 zDt4J5a}}<2XBk2uf^oTDw4Q9r6X}H1&zge`czaZTz@n>%z*wBlptT}9-;>2JK@~_= zCq1W1_!?C3C=;od=!&ZngyMx@3Qn(9`7%io=?rW~#>S^7BBO<~7`&GMxLxbSh$dOj z*k0)*UgER~O&fg|pZf~=>1%;^(YH*}L!1f1sxxGurUq%Q@@n~OM5QuZ-S%=_V%Aw zPYG>-1Yu+x4ND^j_jy5r^#(>mnHsX=l!Iu0Gu zGJ3~Upu%L>XWFShmM2S!x}Z`TU42M^TC%u}D7;Wk;b1Ve<$YgOeIUz>^jto_%tycf z=jsSb0p}@0oeh$QYjYO-k(ZcTnkY{r#Xu)aCv#;=H-YhYCe4b;)mo>YZc>|PYh==s7V!#f@fM^6tvdeShn~eksMSwUqyc7H*7d#wu!PMU6N{4o`F1B}(mahYD;l z{j_yyqa9y-xYgitnr(j0hR?6(=;v#mFwj~g@MiD>gz!EN`J1gSE-@p}p*p319jM>+ zlf|L%)F)V2c%_xy;qy5J#G9nydBp1-G(}1|`hxmMZdDZjVOEAdif`%VsJ&ZFfFyZ9 zav<*ypiM*=9m$Vd(ZiAH=~+y}cowo#)Ic%v7$KykPB!gc6WMR& ztZm?Z{WVS@l9Z(b7M@2(R+b$2Zt+LSz3rw^KV zNyFUN27j{X=qF?NDP99^aK$BeC{nqy$*D3FNpAytAAm5vUWtnCh{Nl4KG=WSG-{Fq z4(9fWXqzIN(BAFU&X=n-KXg($tW~XEaOW1&e8=2i4hNFN!H(h}$83;)vL-2<1TEZP zcMqvry%o0ukwl%8{bkPAgk=B$CF5)9)Gu(mnGV4l+f4DKm=_4bf`eQ!Z|P{0A|OLt zs*n2phUf{TN!B(~Ysg5%kYY}0gNjl5SZitbaH(*tBc{2nl_ha9TKBs|+-3oQFCuw< zU>QL@9}Sf#J1nZgdPv%TA+h(k7xW!;{MGmy{*?D0Nrdx7_;LPq1Ih(oQHEd5JWd;7 z;pK7Pb>OZBJNb(hnoMHR{yJQtVLhWcwtkb~HdaE*jmRC#7H=V$LerWzAWup54w^_mp z)@tF-CskRk5qeBrQ4YG}aoNc+LsMWm-b8^eQoiosM_d@GBKJh*cch$j8z9zBPy8e;{tfN9EJ|jLLY>TbA3fNaNx_Hss z_MqU*o+=D!5Ico|_RxJiTXTI9B}B&i^#chPQIfvK2yV@9me>qMbVMivR&$-I{f|sY zL~KprNbR!4Dq{r1`wh;-NK%HrAD+bk*VnJFtaAo<79XX5VchdPS;-ERU|JDQ0>zKb zP~Pd!yNbIw{*3RwfPs;s<5XB`k^#8KzVjm_yBu1QhXBuGAVKBs2??L!c>&HqTmO>s zo~nH0cK}wPx1RXx@#setgcC0nyTvlN5O^rZOgt-IY7EpLvz#wk_*|jZCf%uhR332b z)kd+}wKQ>mT1(yen#121NdRGAWOVp@&wZ<3-2&a69$il&nk7&_z)Wwx8BM<Sdur8W!OvuglF;w5PNd!Jy2A~B10&K%gW(WA>onCxqy`u!=B_FB z_*-;#<}59;xvPhyB}9*8MT0izYZ>=D1zk6oQaYC`9HQ@P9~?M=oeM5tHHTBfO7pdG zRW|gUufrXuT+WxR3-w@eSUvOb_r^!sXx9*R1ZxxL?ZKO z565LD`0;*0+J5&1ICKGj5+&qaZe3BlEe^rc(6K$U%4IZ&3}!)0uS$iqM`7@_yTAbq zSrKg*!HD_!zz&TGrmGge-ZdtXl3l|RhFA!H9?;(GI1C8lZmjd!p9yz=J)Rk+JGyry zYF`<}SUwJScjtxiYs>lFP}YsEK2YDlf^ZHY@>Wu_xp?b|**|$-f{Zbm|GvMWk6j+} z!FouEx^URvE1!-|vf$OJJh`}d<{$NM80F}lzGfTn+dFN7_wB2Xf&Wi#n@{XylNaZI zZ%nH_^o!Gm^x1sG(`vAVD3yV#)v#vv&b3l!Gzzg2Uk7 zTLE$?Um=~LXtMvR*PL$ieg2j34kLkoo}7=u|H*yn7W{SHf&blFEMJ+Z{M!yL_nx)v z@On(#rPRq|KEKr(`JYRM!os&PaSDuIiS9`Gt?U7%a|qFGF#}Hp_|f;-u8v}$j0n-9KZ03z&Mb zH{znIx}OKI>Cm$f3_m7qTfbSScpVr`(Ue%@vGH~3=c?gQsCK-&6${wcEX)8BW#HDJ zvY>ELKCU{aR}c_UmpE}~>tq_q$%n_Hraf+5db&*(BJEpYP5C^`?w2Z&MkS~3ISf@l zw2v%PcP#cayK8E#{UBSE$TF3GvizV@IAJCd$QYh!Hwf2okWz|JMk}ToFO4A!4^vy; zN#kL@GR5QZYPuCqPQ-GBL5Fts zuZ!j;FG?|=+klpCgg&VN7@a*SD^mr2EUjuMZCg}CNeMoxC>UJllI9(2wpT3>_O21~0MzhQvhOib0MY5Uq((cFFKQCrD z4HubVVl=Q!g*%%4E8YLhRC;PeI3UDZP&^x%b6e37%TYPMCP$hpBzj5jU1&))pmDE~o+vapLC}M7Y08}ZGao3O$!s^T7=3?2q-25Ynl~tI z8<&=5Ucuy*E?Hn-a*MX{be*v98vH-iE-DNh?1c%x=LpG#Bwj0j=i8ysQ%DUd*Q<_ZXYN<_2)#J$%V-*NH^XFVhX&**IhI5ZuMpaUni8(Kh zQAN82{`z0}XdqGX?nsfHg0fFpOlx5x{n^JePN`1$_zx+Oqb&%cU-vCy?7V~KW*7%| zz7Tb|kM-t^FJXdz!npiq+_9o@2ntEWrkuhSn# zZ&oXHCP-CLkp}an_AuI!)XpiM{vgdWOI24WpB{A~Ty5wlCbi^tWc zueq46mPEyWlqE`eK+!16Z~GW?t#X(g?0o1zyKhD@l}&`4k0S_uTv6P)zmg($o-Mv` zA2Jh<(@D>yeh57h@ zV95SeR%162XmPDY)nC7p(Os}Vx!w_%YDi^eN=zMpQ%%oJPX7{Uxk^fLvnR@#vcIeORiLl`1e|RE|dmi?Ol9P15cJxuR=AN~l|7Y|Jx?w>vAM8 zQwZwzr4cT;PZwr;J-sp&Y_cAk3k+zhTg3)0%w})iI$5)5555_JJiR_4(akwFUtEcQ z!ta_Ecb_lc6c(4U3`asFtrbt6@f6uIt%8!+4DUY&$?^LK7Bg+HOpiYTJBE+gFNs}! zFLaSyK29^}+1T^1e{ulZcNXj?F4zGCp#$HAM=8@hnLl}k)QgV{A%^k(Bbpw)TV2uD zY(2I=Sx^$PH!X(kPk9OW_5T>9^MQ?j|5j_1JJ$nyAQy-VIztb9>SqPKy4UY{8{eEM zw6C~P_;mb0K|)JJJH78$*b6dRcuao;@L~are?t)qOScB>pajbK%cKiDn$qKZLm9kc_3ci zedc87;HC4H*m(Jbo z-E67m4TX@8C&oK+Af?4Ns`ey*-=39PJ}Wd-9SAn+?J#LY(Ft_y-`NtiP6xm=nsR9p#`*a+Qs-<&(USVO+tv#s< z1wefps~~Ht59_6P)3Hs(1pwbS zvn}wK*Jrez>fLf0J@Mq(|9_?N2lGG{5hg#5ijLP7sm7wWwo|TT$Rv_p;P_92r5k2d zPjN6xLuGd056o)rz3;w;jh0V87u$N@M@6oz%q!WdJF&C%-6QmWUwLx1A7ZXbwBglE z(W3cUN>dF?i$PpmBg6R8B8dno`da8Z^fk0Hbv8;wRY8TPqLs%k4VXqz$$)4Fv2A|5 zSR*3!M}EBE|HP>0OvwJrLoW2}%J{>cYWNaaZwa&v$)Q36yq^s>LETmXWb*IgWIq}y zwb@|5joFmAOrq9*KmTFK-#I8;FL3kj7@AfRr$l43oGOF%u6+vFc;T^SybwjBgLTpJ zQa19~8E2R)Psa-vquf&{rs=4=3)|odIjOdKk)AUfY?`Yx;ZF$f-&3gO@UCI}Q{ota zT$PK;uN9vxBV)QSF=w)6%!51pV8g6NMss^qIpE4}yDBn&PkR5tjr8vJ!B!+fH%QFfCvX;o(dsE$eR&CkkP zJvttr+bfJ)>&4Htba-})aWKMTHl8Q7dEbHS4|VGZl=AyRWbA2C6=Ch%|f;*MDx?){s!v5vU& zU*4d^3*t`l4c^Wqv_Sbknxw|@k^3D3^8c+m<_lC&|41Q<<@o1;=XPeq@4nKK(83{$ za1y_PX5mw&u;Sw4)K1rb$Fv+?S-HAI2LCgEl=~(m6%YVZpdu^;Mg!aO6cIoKr)tSa z1(wRB51GSVMU88HmHsc`Sn{25+Ebv0l`6dH0--zJ>?zQe_BldZDXVstfj&F@%SxgP z1ge;)6J!3>Nu{Ep|I0^&`=Bnsp4!^l(i2)0Pt-O65p86^(#ndOi>k`qdDHI;<@?uv z)_2|MW_{KH?DFt3gR%=uCvf;a5&w^l#c z4V$gKt*AzC${i)gn1N@zA0CE}KUXo;05;VT)Wu~ghd?Go5}T)q3XaDkNoFNwWx8DP zzcZab-aZJj0f~!zlM>b6gezX*FK?B9;*cst=1jUV9y?kGZ`(OB>W@(l3zru)KEkBW z;K%Mh-7GmfnS(j?rXuyedVq;V?9Ee0V=;IXpKmScurrWV@_l`C9fhM4WMHW5E9arR zd{%XNQ4gX!_Q1YPP*znJskvDzR-N}P@7E99!&vSp>JEE)3KJ#4t0>jjF6BL*U!Kd936}y-@tzl&-vTo+v?%$d)s6znqrtB(5Mm9lp?hwUlSKPlz%GUl_0db5h64b{ z%Cz$no)aEI+6!L71wAy_P@Ty3!-Nk#cQYg_12Ud;ELR99`bxZag|Wte%~33aP^8vS zU12!L#JGe3v2c1GN*Gue9gP@M?M`%_(cF8{#U#_ul<1+iqHmr}C##LcBq5|?*b&zS zt9#GsiucJEgvPJ+7ONH6 z6Av&y0+?e0?;VVZcz=<9^?qa%2cZNuP}!1%PueF-smhC*XTX#p1!}2ztGEzVGOoQ$ z3VpTbN>EBbA;kAvep~y`VbrQR0=XkYab&(UJTOFQdqKbhvU_HOin$s*NCGyO+njEv{f9gl7Tjun3=$+ARqcxX!p&{&D1l@KxsAP9Tw;$LgWWQq&{H z;)Mj+wgb6q^{?Q6$2T^PnIsn|8A)wisr+h0gmY=IG>-vPU;Xw_3HnL46z{xi(?^+(dz0tue@;tHH!aDz1io5lCObDxFbgaf@e-Q3L(l!(SZDcy9=> zEF@|3ENHuWtCfIQ9+JVBnL8q*ii}r?SI)OEx%>0n^X?;m^~Mk4e*W{%hs(>Z-1p>F z{tRSpIv_($`=w2)@1sVoXQzKB#OMrMSMU&qY6G+Pn#XsxR{A3ARkW>SoubGR#jmWe zP89%$W2p@Wv+_>h#lsn#7|5pO8QXtzpTV&})aiwQ?#Uk55lFXkPZ-RPJQu@2{$q7C{f09uDvZfCTi;k+OrKJ_zQPD?v$HhJWy|uJ~-eMsbCfWq`&@92Evb5|0 z>?m8}y6j;XHW$(lh^0-L!egqj<5Fwnd+5Vp`kIXp}jrtHQhDk&c4pSHVH_=Lcz$K_sJ> z*eQXOJNjRoKI}nf8C~DLm9ESNpQQ<_T|ih&2BS#H$QAG&x+(j*Nk4B+phRm_yI_9} zCBm{X+u4O@Z#*Q=Jg+S04@xnkmb*G&QCanWEwI_~Mt1**b2jZ3nRXhkG_0T|kn+NUdOB&%xa-YSy5>_s+Gc#8@k`Yg_~J3~vB zSKjD-;b(gfLVen2ioVlqoBWPNw4;YQdGkb&(TY872$YPr)=q=*gZH!RA^)?f1a+kV zzEHJqqbx_!k~?dJ*Q;sV-(1>gUn>EBuT?EDFns*XxU4L_0g@=&hVyfKK@uD_!#6=v zjlpiDrriVsCK{>YB&y!-LQJIuLokdeDCOB1cGGod2I&{OkcEK(DAaE>_DL9-b0i+D zXS!Ns6f`R(zh~>m;L4e*FU>>QO@t6gl{!R8(F=--U}Ey=WOL7goZOA(5b(QyFyS8> zA+BbDm$mKEp3ZBi2rp0T_SQ>GOFa3!jPLA(mxM>LHBOhGz>vl~J}W;I{BgS@cD7l> z()D~0iR4M)8J!+bSP!Za4G=6*9EMEg&8D3R!97Y3zz?O)0!Qp(}5Hrwl46 zJ^dbv=kSdJSY9dOoq5mMh>-h#B)vNLJNs96#j*a@Q6aD71Z~Xi(*1T zE^aTx#?I4Vc){4gJMTAp7ZXY?1mv$<4ais1X@bvfSXnZU2ut~dY36#%RIbGinE*SF5G!iK&>Vp8gnPJLxP5dnBj+RsB zBYa|DW)+!MfDwI(Jn(*h4o@?vAUG{<{@3HowXIhFdYq0JP*LQbp|idI-1h9c(;cKD zpK-s(1r^I1#9yqI(;1j)*%Bw9lQozcVQN$P76I>)C;&ny3k6DOsdXxL5&Jydh*hL5 zBZJjkieojtwPGYhY~<`faitlm3v*JoX(h3KvS^>>G-i2knhHLDAnyG(M-2n>Bf$^K z)G*)57{RGH>+$rAVgAJ_8~Dd-)`aZ8T!27E=>SSVwZEFCNO(Sx1Qh$Kz_)u-vXHDxh!D(!H~O z+0#aSD9&v@Sl(9Ysgia4jPTuv?DB7`>|S`94h&!z-lZ(n95B#bf-y0fFFm6?pJY?? z#C#d95m2?Vaz|0$VR zVZXe!lDI4}!3gRwqp~A(z_@kO>5iz?C7zHL*?UWnuVJqT1tpOc zWSf%}bm2wVlvLiMe?GhARgu1!JM3RSX#Q*tc{U^Q0D8;dG~&`to&|M?-ZDavcsKu! zWtvQsBC;O)xqy!@$mchVH+Uj@cxW7xoICuOR~TriDRmUf?1rm+z*Eth8o;Do(%;dA zhE-La?76ILsl6i&8eC$pu}wdrLk-UXBQ_pNz_|tJy)mFmfAkLiO-u$?crDjiZ`?>* zSil2|%W%YL;M0c?Kwwh#o`d;G_E$&Svix1K;6&@S;_8D(&k8Rhy+d*-Xnbs+q!124P%x&6L60)IOHNif+ zcSWo(y5*$@e;=Gtl)h`fMt&X6H4Kaw+?k{jB-WV2atfWNQ}qr?DYjauiTmXz@vXEb z@#y`N5p@VlR%kd3iA_1=_dGKt+wrh>$)Eq{|1p*B0EvXCU>Q)#qdKuJt6klX4|)>k z#}0AJ%{gLi3Ht8{=Yk~rFvnD_*e91EhIp1%-ce6&fAlKp-t~O%0@COo=R73bgsT_d z8Di9`3r1zbuS(RJP`Z~#B~0Minx0|0o3DQ06YU$+b&8W)uG7#bgv`26AOWukFA5S~ zenS8EHs;ala@zGXiryO2M{<0mhyWcL36&`W8Qe~+-qZ<3CxV4%x$bzpSYq{&>!Sfw z8QezPe_gds^$U~9HFkIjO62}YPbLxy?U>gyl{LPmFLi^?Y_xJ_Rydrmco2oTK}oT( zp%Y@DY}fpGUwtG~K-1u=VCL5!ay)VsKk$I#5skT{M-R0xV~7RDha&MAF{e~W!ls+L zWX75xn4tQ?IQG_+KU1Cb$g0cl1GIn5c>#U?e~bCLH#$siB19=G8romt3Ydc)! zjU!(?W7z#QUdt(bE5gR$#X+xAzd5vdx!#h-yIwr!!qUj6>qRhLbK~P!da8&OjE=er zf52fuy?%#&G?`_DTwf0r8KqR0>Yx{h@N^A{VkT7ZSZsjJX&iYz-?~pnUQfK zWb<;u#+9>FI{4A-F54S^`VgO#5KtU@u{+l(h+wO4F+yV{IK8-u*v~n)@SJpiSy1+3 zF81b)dy)-Suk*}p zeg{-7h9!TF&cX~F@fBnNe z6Ynq0oaQlZovYzkb`=2H3Hi;ga1Nukp6&%TyTjJDZH}|LUjg?%h^nI-uV!rYz)1;+ zCMXU2A>6J@Z{-HtS&){|!M$G*|u$VnO&|f+qP|Y**3eZ zF59+k+qO=1|7)%__n7CLu`l-Bf6nn-M}21H5YGbT5z)fbw9_o$W4v@7mU zg6PXrLB}8FN@6TeDQ^0_2>0S8I4f=at3H>A111Axpg1jpQhu;1m+{?8f3t19D~4o@ z!R}gYaIW2WRE-6))T40Azy|uyn`P^a&a`$a2Dhh|JvA@aq=wCtFDl<&VLs7^pNA`L zj^D&q%@8+b-Z*B-mY@s)fhFg`%hu!21I}X*SD;2pR8iV{GH*egnI|5n{BI82aIXBX zKNuRWM!-_Ft-QJ4&}W_(e`xKwDb3xfssV_wZ(VIDg6;Tt5<9&Wh;Tf zT!Y00>z^St?E?pKEtuho9vPEqq~hvYS9@ei-ad3n9}z88M@1{+e_-;Y(A~dTwOA64?5(=E>XNId+AzOHVp@S)2sy|Ejx2iPHZ{oks(vK)tpYEqP#Ug zvzmn#dXpAlwtcqhL417fvbN&pRuB+Vzz+(vF0t6bwa4AT0MQ=qV5AaH$Y^+^-E%eE zq+?Hz8*OWNrlzK#e_%rW^8y?7@ygm?Zy%5Z?&xdBWh^``EsI*GYYAi+J~6Ckgk{=v z@7x0K7oFV&u*!p(Yz}?&nV^xAN4Y66cfZGR9Pb3tgSCx?O_*)2MV$$n^`vkHr8bNk zlJu(MBGUV}0+-5vy^@9hZ2X_IBSrAPZ*2cwya$G3 zp^O$KE;*)D;JCAdeK9A%Y*Fdy?G-$6|EC5|)wCZvmb5=3nt)kQEn7pB;<;&ZFsXQavxJFb=L=yDkq3eVs} z1WS@;XTO#^Vr4%>Up;O`#SIdzJr%UpAZn+>1j!Z8KDU=ZU_gfo60$LQLD|u)n4aof z3t@XO{yFD+sy*mrc(p%dyT{}C2_z!Dby+3PX1C2Gf0e}!^-*(RLyHgif=0W!-3Qg^ z@I*+f-Co2jl@H6J^new?w2=@j?jC3eghXHRp*GhXtQl8HX-f|~YN2^H0v{?m!DYEP91-IiOxSs}FvELov4Z4kGbR)|OKW^)(UutLc{Cd5*x;r6*JIpcGkT?L z7sevDe_|=ie4Z_0hB|-amMUx;L#qE14VmqTw0{ujcgtK3r750tKgCQH5Uq5+l3TYKsIC*pndREc?;PYB{p* zc+^X{Du#vt5U`Cn-Z4H-IORcN#zvRg0THb7e|XW{_lq#~cK!+$+{)-sU86n!^PY{q zvD;V5HCX+SUPiY0`|nu@@>OT60unJ7y*?LKiHk-tqQD?A{Xy~1FZ={8Njc7Gp!9KK zy2_;p{d5{Z79^&&JK0T7}#F)@u=IHJ%8uBnvAn&&PSC zf32bG+Tjp)Ig+4?&U0mDkYwq0)0ta`fgf8Brdr82FKc2{Sq%5s|0}nb7qUwXrC?F! z6BGDG z`=w_Dm*caS;KTNG#JF)$8;oUxTWU13U(u8~r-N10BnOIe>RX?RkWEYo#eRo=Bo}LH zFQYOc;qXMOz*yOD6MdJGd5>Z^xM~0QjG>|B@Loo!Ym0>-)DOq9;bDBrM|CQXe~@0p z>WVf0buC+2{WhMyDE((W1O&~;Gos_g#RvmEj3(xD(JZUh-xx9}6$piw`O=1U3GmCu zsacLu#QT{g4=>|*d9r6~Kd2cB`!hhNBPWsPn)`S?1b~+3Ns4E~F>8;7c(FsLv05JO z^m%h(X*`2co0nqL7ebKXGqSyRe}L!tL@g{|8Xw!|QNQgzm=Ys~K+nfj4c8j>a6CUO zqd>M}2of|{LwH#(RZ9IgrDX=_?=KZIwF+?cJ?IJ?sL7 z9ZdxptHQZBqw?$_mP$PC5s{iRGnFkrN6n@~-I(&Lih64v%;1bioG9YCf5Ume&@^vi z!t1+Uv3!D+$dwyri&hMtG^w6>nJEkm3y+14cp9!b?(Z8$Us0nuEux9?$KP^$-)7hQ zp;<&z#48pWaw0tFYpA@7rM+F@%scO|4%SPI#VQu zFUZtJlPcBgQdYLT)fjW&e+PkM(K(V-Q}KbQ*^<~@``%y^vdsg<(9QJGY-*K(rg5s7 z=1WM{O#b9RJlRCH`@y^kwA`?JB|^JC*PN>%!J2Ej*pn*6?ZH5gN&f_&uyt1bUZ7r* zk$R@47GIe#9onsHuZp3Y71$@2D*SVb^rKJi`jpF8iZ`UdD{}vKe<+}^w$%^niJId( z#Zs}uCKjIEQKd$L^#rGu!Tw@6X=_XLyv1{xl~AFwDTW{jSootyKtH3Q7h#I%Dbuvc zi}MwmViOMkA&$jvUtCD9u(_Im9}HMAL`a_=VpyMno*qA8Op(sLj6qHene>nRVPg~Z za7+t$+3Ph$gAE(Te?3a^aw^LVO1)15VlrDYiVDSuutrhmFSoVNwy%Hp5~x}))0fmP zk>rO*AlZ0H{e99}=$4g+`HSHSKM!`!v73VRTZmQWionh?TkM71nf7+V-=Ke@O8MYK z!AhZWoMHw8=m_nZj=q~E6-QcZsT_+4J-1>f1>43Ft=a^r&MmQ2M8RC zO5M#WEK4XScL(jhoE zSZ;wNXmLj`e!O`WI~bIZld3 z^Xat8g)}?ny)c(1b@bmqR$5LP$)|Z?H?#7E_~hV;fz`WsCeFJzEl$s^-dy)H)rMUIt-g8bvDaNn6;k@nd$D2eJuuF7m60;A@-of?kh^*c3T`u?RC% zpMa3@!TUckr~BWlS3oAwz7uhIJ}Cu9NGqj?Bw~|ktZ?&JI!NN^<(~u)SPoD{W&eba zDZeRn9rNOmn`YK?*Se35vC ze@5c@489_*iA2al0x|7xvh|uM>)RwyN?iuzqjN4J&1Q4f6rCPR&DG)bz34=T_Llcm zjv%6>V3^K-4s=e8PWnKGSbI?*tG`Zu% z7ak#rn%FZGxjbu$U|EoeULe4pIon_>9y9iwUOVUzLE2l1SpUY&3eZsbt|1x(SDtCXOA{&IP#^_^j~hK}~&if1lOJ zHLO;5d>nz<47?#2dwY$ovk+2O`6zk-o#v4>#s@|!2k6~6fp@l$BOO6hNVblVE}eqe zswCSz|4o^$=faooY)vl7GR-G-Wu%IQ)HQ* zSMS#KpCwK$;QvTsvuE34hli?={O? zqDs8CxiS9ZhetsEj@vK2E8ohRdV#KOlqvmHxmGEOsU~VCf9lW1Ss7nFZMcQ+kNn-3 zDRT{~_-*VeM~;652P^PCD{biM=>Y)zVu*yitz8-B2MCQ805LF@z62oq=mpW7Xxf%I zlAv7U1WNE?4rFuK2|);DbHO$bpRq8JT)Vk6@aAgNdSUH_iV=zz-(WjhOEeA_+~IOL z`Wi_gjVjade|pL0oRMH(o65SM`5<%}2(t4d)4B?X0!WLy&LU$*nw94&@EkurzK1IFjwWWw74^&ZH#(96| z2yLzjRSxS^S?wq|xBq5yqR+V91J~JA45}xOY+W-Lf4iQWoJ*G3E1odi+)|11exDp3 zCoY^F9t0#2E)hME%Op(A^OFKsdD3l)d&<^pX}{LlXZivPz}E8YU9`UkfklPo;-=W+ zKj%&PyP>wWcdo2vvN045+v2y*#bM<0naK9|fWg#De6SZ60|Nu4cD!dBJ1aa`7+v?f z;>^@ke*=#g8WpgJJ63X<;n1BRAtA_;@pxb_vH%e1&U#4zrSe1R3P>Ui>2}sY1^oR! z$UQY~;3SX$^7P|aThIqcX4lGO0~;0_?m{7R-=RDK=#hH%0#r}G_8=|FJa2m^;P4X~p=^y|f3ge1QaruOoO{ZXD|I$>I3-#noP#7d zM@hWvF7Mlbjo`gK*7}Xxj zXH2sY5sK}0hix6owXo+|V9C`>QSRT<+{&vz&GJT6y0!2NG5vZe+W-Y`bj4AiknuXn zesRnLH~z4cHL*V1YGpi}dC5`(TWFH^&{OS!#7) zr+FuGxq8w9Yo*rCJPKjUr!Skc{zyfNn~15(5Bxmp>Mrpmp|WAH6n#(31H{%^<}Pjv zf}M5r2`lgKIlLuF*FKKxt=ERfkzoaIe~C^_B}`HEa6;=$jvmlFf#VUBx!-xz6J8>N ztF`WrECBS*r@_60JCqBW!D50*N^`nN1IU4-O)^Cqnxo*YzoH8+@US-J=V3^NNo}Z3 z{9s;QbVoMxDMz5%tMF(_kwvVK1U{WTU+Goa)z+~F;QPy*r>)y#g(&BW-b^DDfBLtE z#Np~l5z@|yE{!`D_D2fKI9l71YLn3~w`&~`W5X>yy@SB#duh5e@9U5HwR$3!PgQd! za>e9!7+9UF{V?3d*1|567Ef*rpZ}L=g6YV(erK~ixcdim7>Bx^Oic*niO3lg--W9B zCDSg>xaAW}SD1Rv$2nTg$m8uZfAW0&X?Pgk_TES=?|PR{{m9io+^p1(%XKYuyXCKG z6B`3>0yXf6lR&vj8=${DriAB&uo-NEiY&jNUat&kn+4>t( zmozs|Bh?XQIC}c}cS_m$`T5InKdITVSzyKj&p%U)8+^ z7kW4JDIPiqC<;44b|bNWV6j?ydYIUe$*=cHu2(#iYFo#;qhWpI8V987 zyes%_>NDcr5&-<`e=Sl6RivmrB#zwp7NGTxMn4$&z)sy>(pm@Uw%lK5jloahVlU3C zD@Z2W&gkyabpB}(2_8*;btstuLWB+3f`%A^d86Ik{N|~hKFpWbv@rTeNa&cDp|meq zrOK1D4Ils=ZyD_R->GSB=N7$f8_@D6fs_l(>NbcAAIW~9f3!_DJF}>@#hX8+zD<}@ z$UcpHpdp<&_YPnR*lvx>3knb5lOA&e^O0)vnhAY7J-l&!oasS{n{+YNt}|q=W$C$p zu%%q+YuhMyO6%<{##+NYNT~7@6Xb1<_eVpYD~353Zwi{5=VQq)Yskr8pj0 zG{@{v|M(X}^M;--<88V@%MbXV_VdslH)^PRfz_b1l*EnignSy!EikC%Z87k!3i?YJ z?4wbfx;$eXMdxqP>P-m+Z zz4;uOa3@Z2pCspZlBZD=#1EBadknF=wOp1E@s#C5`2rRIKEp92Ha90=Cu?Yd&J{VJ zn8b4TA{Un~ut@+c!O+s}4M95a^=sHid7y_!8=r2Qd_*5P&VDEgo$%%;DU=1~NfApq zUt3t0fAu5F?Z%S0=~^Vhh|KQ^mH@-$ZKhb!=&#>3d8;EdX{o)?Ln!j6mGkf9zPMl@z)+z$Cw?RJO#gnY(VX{4f3C62fQyqV@x2C2yf=aDD4&)M(=Z^~^#O7J;aJinEo^XqrDSP<1eYFW5&$M8bf&AdTxA;;0zFMCIACV=^f& zYADwV%@JBYrrc?LrIWD7T*cgzOyfZ-)@WqN7PRLG-kzaeYf4f^3hT-W*dhuIpyp-*`fv&G3tCm1wd(H=R z)*AMEheKaXT37UN9(cPeu%@?ai1t3LGFC37-rotBsc0SW)gIm|%o^!#^8vC8b2*mn zeS4~OxX8+8#DvBUi2*t;(Ks+S5A2H~a@+uqu`Mu+9f4%#oZwq+S<4x@shJ2!f0#h& zP#EA+|8nEum6F(D%s@rGUijz}9n1-(qi7P{U+u_E>PwCLO>H4)X7}w->)D=+I7tBK zRO9NKT5W15o9c1W+b9RE`O9q3+=o+kfI4o%i6pgnPhlg%YN`~!3e$lFyrGEd^iuSO zQr$?D9dnv)|MLv_k}ZW5UIy7me?-LX{KI{}ZE=eAzwQF8tG>yulHgsVQAcPu1nHkF zB|w_iM^Q#@a4rP4MR1!ryy6&=Vt4w2f+!@idVdfC)17@GQ&(58V1cgZW+l(RI&B5* zE)`K>sch^&W1z1W=-d-G(Q`xN#!~dp%^;#=ISt_?LIybVkf2GZsfqFml z3Y1)LrL?AMsZ$9!%N5skJ6Nu4s24dKpV?wI0(iPu93Ay+Gh&aAUxE_ve}V$s;imTB(iR}aJzh3vGZsFl+r{yP*zJi{_yk1Y8;y4^ zihzx$2bBfa1K(q2=ok#8x5(DZ{J=;SHuKUJx|7k?^EzIBUIGXx+i;K_3JYyW+VU7Fw6sj z_4bkY>h`p8VI!@ose?H@EmgwLlyhoz`Un9JOmIgM=lMpL6bDJFwoztbF(ig zw&%f`0YgYQe~fE4ER>LrXl(QtQ=bsb7$rgK_xW9JcpEZe0P_X*_6p`Z9vhV6-4Xq* z^&)7P6HAXY@-O*AFzx;qADn-GdqKb`eiX=%m6c_)+YO#?{TD-28;HUanK2sM#fcmo zB(F7{K{XyvpG!^p)BIfTHM-bvykak$a>m-oEah*< zj?vN4b(W^{RgNyA0-*N8j!gik7KaJcM>xylt$xfcpo2+2h!GPiYH_oc{8~R zIWqyASR8WBM>;qvr0;qPr^7b&%?m0uwieJo-1FxgmKkc3ZN)5`nod*oy+TZGd0&JJ zU4ny|Vnm7Q8}9g8ryZd&n%UG3Jzz(1<>>27e{Ch+cNi$2@4K%%*BU)`aMy)Brp?P* z7X<~`Qv?b5+?0y#1so^@ z7c0XH%}9=XmG1_nk~-#qMkZ@6b{O|#wO zA246KxyGVlEQ>3~Fxr82$~Wf_TziH*j1BO%C+C#0uC`+Pc?oQuSep@Y(+A3s9a zudP2_UemNQi$fZLh@jw-)-v5G`_-rL+3RwuK~Qib8NmxNl7?Ac1&O&XZc=Smcj-$1?Y=J(1_sR8vozlx zzDfFiO43Q_bt0A>Ur+G~pR0=n#Ee_sARzrN;bPaK;QA&W#L|ar0aWUNP;yYeP0vS|Vjf9usGt zXE5imJu_LK(_>XFeAOPKLc8M~6yZopF^%Mp+x{JA>deB=&(By|WMQiR!V_%yh;`1@ z9Pz`EaI!_O?pA-No{NK`pgK+MMnme-|zbo1LVq0I(s@fy7jx zg<(}@by2noR$Z~8%;&A~pe{+G0ZsY{-0N+J=w2L`l*x(a)L4bg^=i>=e330-jH;>m z#udgQY!UiPrkwf-Xc&z)!Wcr%K*7#|{=Pf|ssj||)3Ni0cjvs<>FOH&bn{ChyneR> z_%OXQG{f?Se-?8VbgSfOC|O*ZLLV&xYYB009&3RsV%GOvzcuWhP_bP0tk$_BU}vOf zt7K$k*jg^|*On+_WLnXZt282exWB?Z@KRcR1l-B<;=!S@#+R=GW>_>7$ahA(J6aXy z;t0XTPM8zY>Ma!aj+$Xu8^-v1vf8%xpPR}lzMu)7fB!Kb;V`6I8veTH5Ky?9E4*|j zcUN`-k*&Rxx&+sY62aIZ6w9K^F^AS0EA_#FQ;m$}T zJRu;6e*rwscK0x6kOCddCI@EO)r(tW&xF!5439U@0$d*tuq+d}K9xQCdnc@tXW@;U zFO#k5Xli$uemGs>Y< zKrYv>5U`JM17}Z~46m05o)3HF3ZkOHuL)Yue@uGAW22TX?oNcuqwOIvrLbE=HDqj? zyoe8|&I?Vre~j}S_{X^cr$eH4_wWZ?R?6t^G|%~RNJ&ZM%(JtzLv(CJ$*AC6=>*E; zy&42C1$FPtC6a;rM#o~4Ho7S(r;$Am>2=MNHsDLf8EegLch@^-)%L&iy?`b8=gS8{ zf6ldW1*CS|!Y5jD(zZ%RQ|7BLb&8ub?8d{#!4suxtSViaHHv|^G|60&udBJ-y~j?r z{6Og%>ys=xoe^(DjKQB!Uaj-7dC{+)XUn^~2+&tgf>`r32hY@+3&@sFf=t3~T}Yi6 z8v4P8UC@XZhm;9LTb{prF_1_>{pv-he?cJmxMs?~#i)-mj3BS9rY&#ve4k^9MVdsH zvs!RI0gu9pV3-+kqBO!wH{H(U=>(536-97nEZAABlWmp8=evGxaZ8u3yw#?d{T>Xp zmR~Kbe0A&ge*s4OD@@A^(z%n znyyV@{vlT5SCN)`0SCY0#+wTq33GHm9@BmM(F+;a_Jm{IL4S_P0DnRDl`~ zlSME5ukUO@<}Ya3{zFs}r!pwKf2`+4wpf790VP{r%#>y#Axr}A4-r8wP}C|VQGG=R z`fVcQ3(O>VjW>e!5xmgDG`m{k=GofQKpRS6!8r`@a+(IetS#_Me`ieey_zxBB7C1zMa?9mx=Mm1R@L=$h# z0_=&cAlhYuAqn)O4`N1ltt9si(6+N<#_T)|!0-V~wf1$s(jE=GG+C20O zu_fa08^XlgxO}!C=lyP>3H$HDbGn^h0>3b^yHH^;X%0Ro?9M<%9 zytM@3tw5)Ws~ITSf3r0Lm+%c-PQsk^i{rk9FoZo3ptDm?3BCE6S`SIzcHW!(cPLCe zS;dSiHLON!#Gwm?T&$k$%_u{%$_KUf$K|!I1lByrp7>nnaNLA!#|PJHo8y--GC1Kq zy=_jZROr_-hWWaSFr)@8{?G33l_4Fj@Bk#eq$6rPaP=)9f8BsI_Y1-(oLx-SZ!=pV zDsmC=<48A;#^TVI-QverCatZ+16b~w${jh9{`uu1$1@^oqeK)Rk`(|dyp8Dlx0aA_ ztZ+={++gdu_4-CQWD$lFi#$*jN-*CMoSkRQIAK{ddo`PA4;!GnPrMl_lw~zp$r65I zP%?dPDvs{9e=o~;mo%nwb*hz64I!nql_fC`?r~-hX z0(13j;gIi3LO1S(bI!S%Eqd!3<={JTis~ZvwYyNp_2K2E8p51f4^dQqND)%1{6Vw>X&8=;efpt zl>_vZIld%SJ|kt3XBf)fjWsYRjV$#pEez3b;Y0)W4_ET!jBU0Ag}`}<475&}h%13R z+X$lNb~CnBX@+<+22G`=2dd(J{TG{s zDl?j}e=7EjvUq57*n3-)&QZXWDh}jdE|wpY%Zc^rwCI`Y`zC$#iwtzr=eGV*Jy}fl z=9=s?XQsc%hWx~%XJZNfFKxtw_|L#$<^N7}@&9lpjwYLP>d`TKsy9hN!Fb$1x$@!y zBhpG<(>^=Qo%9442@!w1QfujFX zxET8d2Rn5C5fP*QdkMDi(Em|fd=5QE>aVC*@83%V$s+u>V*3vbpN9A=QlY%C00#a2 ze>86k{|WlK{xh@O($e8{?n6W5XJvLioj%NspXS75u?qb(*!3r34p!Jo|F`P?8sT3C z`^SA>N1`qxn#>u@jB|6b`j*nf+NnYB6KYahl^v4w9bUj51 zYhRw6A5@UZWxl_^pU!?OI(I-h!&LfQ%~-A8I1-B-+|lKk@d<*TOare|Mq#O3ues zp7&Dk?-t@qkI;k7M0^$Wu@I2Fje5o6=l+?tXHt8XZmV*>4x|8la9@w5`J^gvPvek} zvel@8iOkK*XWFG^`5@sNPtPUz1WhNROxfn;Y##X;llJe&)<+bROHr*J`HgYU3vEYxVi?;A|)*W0^)=^m5K$$nk%qb8|^f@7O){&@Cx}>}a^K{;xbUiMZr3c;= z*XI8U;WP0G$S2F`Z`J*r%1eSuV65lSTvH>vvKH{RpE{f?UGD+@e>k{Q+8w55#=UDx zLHm2HlO+r2r);h`5R6y4VFYg4#y<7>(TOEa#Nr{oKXq{AQ5s#>QQBI=Wj29PQnsoi}1f?T@$T zwVN|8;qWQxIhCtze?B$QvE{GHXjH(`746p#Ls!xu$`6o~JCph49|=^1)GnB1GQzhr zLi{my9cI)oVONGwP)Yi+yBGN(6~M|9YLKq6J4F7TH7k%Puc(xJ($b_6DCtm*=4GsH z4{)>);)Sp%CGM_}%-%-?)EiD3E?M}BVhzCKA8qL3K-47U)*^2ILKn>K>A~nCv!*jKjKnWDm zqR?`?R4`{XTS~NOthA4tG#%yhg6b{H%8e>^mDvbHI0lZSlM=@NxDUn=pJQ344DlC%n`FI&jC3jsI_$r(HI^pP(42$vnS*lfthA97R8tum-Z{ZSSTU(l7-xiqoBi_+`m@;4p_K3X9Spj804><-_ zduC#(SX*Kih{yS^VzJaDprCZK8^p zXSz0m3T+*)psXqDHBI3AdpVVcasenoC)iG6V~ErAo1XD`P$90>+4#IjK!_lrx2c|y zI>;9h+Mx~Y=Qe~)rR2aelvCMfKH^BcA|NPzpxN^d^cX12FOREBCS3Ns;|;t~^4^*v zf0Ii%D%U6U@keOE%tW)&+aK6)fRM(v;u86U`;mrZ&x{zmK5QV%v%{G%@xh&WA${ze zWiirE-<0r=H>Q%`w-}7gqh}h+ucWpqqPvb<_Ae-RRoFk$ScH5J(xRXaYi&Sw<$fOC zAnRN8Dc+kI9gcH~>sLBS5+=d~bN~Vc76SdVe;?iljR)R4@|j21{RT|H`dCf6M=5 zBw)ju4e(mIMk_aKDkTUk^33?67x}Z^>DJ@KzR{UHuPSpinD^TW{JY}V zg1AqJ;BeLI_QL5aj`5s~igWSm*YKkAUo6&dAa6GIcE%QOCkV0fc`g_Z&~MGSokfaX z06+>8CLJBG$U0)C+RmiXg3r-df7P%x`1m^9PX*Gx6L(|!!3n(fZwVcurHrQw%_<9C z_~WZkKNV8_7ar(z-8urrj-bPDbhonS7UxaL*U1XU)5~KPkf|nCMXISmVhG?Wjl`Vu zTlGkT52%zd{K)9~1Js=v8nn5&IJcsXNk(!U(l<|1DX z*0bH$UfrU!C4LL4hWvxpGU!qY-sCI{%)Ug)B}_VgZZT9@91S`5(RC_wxwZXv*Qn=V zel_~^M!)g;JHmYhVj$5Qe{b2EQLBLgjZN-7ExO*=+C{G6t;x-hOqoHFTi@uLl#v|V zaUjf-5HGRnL3S{aCzCIr9_Fd4DD5DP?k&R4t@XA}HK8(In~NpPV;i_wEN=MSnfIzZloIL2pz$to}aKw>zxuR)Thdj_i4~0Wm(??W@jNuyh_6Af>4JSoKum5 z>n&IGK4u+lM$FT%9+@W%wNLn07$)Z<+iPEXv@%6Egd|^f+)@y{3mVXJB>MlN#>70U zG(P@;_S`M?er$k^f5``r!_gFHSP$W_7So#=tM^cv7x5?ch+Y^LI}&+wvRWCPfc<0% z8akbrOm~)F0E>9YK{TcNUTJ>_M9u}+KQJuaRgBoTfD^5?l#dtle?h{9fAy#T26(ss zpw52*(bj)Q?iv4o2=(uY?BYMHg|JQMPwk)S);Hrnj&1*Mf6LS@I@kS)_%}FU|0<$^VJ+i@VwXgM<}f3)eX;U0dUT{h^EXtghDv zg8o568#kOtvL&}4JOCJb7En0Mq6eQpZQ5~o857DyA@zPjq+rIb(xfhMNJxGa6%(Z( z{ygQtz`)A-e|o+YM#IhR;{pbne<+{!(OOGGqZcpwlNj^Qw(Ke?*SOf&7;4FJnKn{k zQhJu5#f7GH1?y0Wz~G`Nm-lTFF^;^>wRLDv&~&$SMQG@po!%$_0GaI1T>xkT$sb(_ zBT2dzdS68bUd?8z{}RpHgmUc`(3b6pX#50x0c#OVh9NdVEi8s zuk2M?rLCW!(ll~FIpSLD-JX%enD5L-QiiCmICiJ7{IE)1rXZG1ZNXx{?#s z0eq{`z@Q9ci~`PDX(!D&=jG;TgW&cqhG8vywV{$j#Sx+IUCBcZV49#k>kGD`ktvDB zI>kws{cYiRi`#)thbTV-LBXKHSxiS6PYnzPe`f5WY#z8bpiMsaaN8~AV6A~#?{u%% zJwsVD{Df-o18-7)%99%MkU%>T-4hGxrC#VL2Y1l;0{kJzaI*P=cr{ckwy>(MM)^rh zToY3ysl;ptgUbx1AGb9#mje^-eoW*oORQ_E3xdSUEcnTrYxFo;Vfe=xBT;WUQg7`K ze}=uouw?ys`KVl;o%1Fy+H>0Dh)RQ$^<(^DD>*qieDJRZjJ6ez{({8B#C)XS939~i z5xNEj#LeXw#aa-=(GXvup<#3k40@GOJD?-NqhoWPZd4SEb4x#XP1p=@eKUb~wi4co z606~0I4$KxXPo*8kgtxS-q5VK&Q^3Zf7qLG701T2`TSC@nS#LP2c`#}s-7ne{aa!B zk0j+0nzOlCKnEz}_gEjGQ(v1!PCG6n;&94QJJ@+4v&1AtJh9}TszdJ7wiEr}?lU_= zSTD4RJ~!n@wpHP<=Q!l+z@Pxiw%W3d*%ExpaP3l-%ntpyse)k3eXBfNp^p~Gf4d+& z!Hs+{cN@`*h|6BkoLt3EQO_561^%hf#%Y-j~vScw^Q&1 z(XEF-{D3#`9jDXJt$69qnmIu+`05Y6s+j$osHDc$@By*5OdfZBpLEc0CzQv&Ve2fw z6wXj=-)DtqtpM?TiPwi(sra*ey=kRS&3O~ZR{C<*M z>j+%rP%f-|E;=Fj`1`cxTGNktha{o3Xa7q98>fn(MdZG?VCo|vu_n}k8Q`;qf+#pu zUo-KqQ_Znp5)l%cvc)K0lN9>434h3#_clkZH8RIxO4ED|uLUL4}{0 zeG0?Ao!+!$8;x`|W|Y%tY;fV!ji9_#gil!V;W(Zl0>;ZS{MGitdI&ZSSeQ-MTqCN2 zHkKnPLAV)=-VC3rMZl7>UB~Qf>_($}`>1j*X1@~;$~}}O-5Y|b76|@C z(;oEY^VbaLl zP;OOCcPVdK>X2O@D$_Igr$jWte$O|H)F~j4V<}nD2gBq9bp&gsGk<#YmWtM?#tm3l z%z)}R<*soR$8Vw?7rkQM`OnY&KW$1l6i(c}trR3{?81OzyXMQRr`hZ4$QcuGjnzss zK)Rp@@YNx&6zG@z40fy3(r=H1I@e!q-f_XW{z^6<(G_t-!*K3!{7$uE2U-HB?zb&o)q?q7=m$!iifcMaW=NN4Z zm@<#tnoHBc*8T>`XV0NG*`-W5;_78VP*SJjtEK+loqnG11(2<5oO3ja53Sk?Hlf`i zJb4sh<5~+IL8dJ`SX$E`O-BBSW&EIj zU4&6o|N515!Ct9^jOP?T^nEvKB?_)*ShNYM$SkYKt-{jPWs+m|+#W-OuH5&=yUI)r z@6CWfjHM}JQ{?1|rHE}nw7ZbMzo zK(u`neScHlwk`EZlF#N!N9ib$IBZayhQrK7;hs1ma8WF#a6 z6zqO+xe<~&7O_?KR}V@Rmbm)qZFWeOBbYs1T?7Jq^7|ZiyY$TuhalgtHU|EQ3n)Jn z%71F!;`uH?lwD3NUQ;dv1qFQdMaI)w?JD`vHd+5dySl!P3z!`J0A82C@Y9N*B4DG& zbvoBNWO897E(|nqcmV*!Ig&(jtLrvbauB>Ia>woHE zTz@xu!*+X^Td?0VGnpbGau)1*4brFW z<3+azXqJ|u5~I!7NdHd&sR>s0F}H9Q0;&lm2MBK(&e|Cd0RZ|G0RT`-0|XQR2nYxO zTsv+=00000000000GBTy0yKYf_jI$cOypx=XIR9};MDtBB<~H2-zEvCves=s7!qHr zHT?Vk|G(l-7Dfi35*-F00I6kQR;t*=n4qnf*ui@0g{;?pU&X#;0S@O?d`%jAR+j8o zwPsBq6N5DXP)i30AyiHCT>t<8T>t<8P)h>@6aWYa2mo9=ZbSe8000F500000moFd! z7ngl+0}+?%O#%#mth#krT+Q<*O2P|)K!6~@A-KDHaCd^k1b25&f;+(nhr!)l5*!8z z?hsrD_d#~Z`~BVBy?5_(cc16ZKXXp^={|j`s;fSq>Izp;l79D=;4K^++&ftr2{kyl z*OYK@ulkV?VJ#9Vai*}pe_X_5HIQIGUnJ8o*gc7>q_(SnxSFJ>hO!!*g}sBF8Iz-t zy_qeOi;1(DnZ1jpgDX)Aj|UvwM>tstQ4PS5_K5M>g!cBt@f3Up>HrT(>SfH2>UM{ zeaS~VcC#*jGF(h9E|&|sgUmDE&=n@5kOg6g2^KSz?Gzsa%q?zr?8zr9P6qQLWRYM! z$|ML;SXh2yljRp5x9!QDFKvxum_8SyuBG0ebs^ACfupr{=XK4@DL|MljW)N+V-XtW zuhmwxs)p|0eFt}}WayzgVop)`cmL5`Q^WbUW z(cD>o8dY6XXyfClwSP|APZ@IJHnjB581>sw;4xjBJU&Vr?FgsrxCw zcjZw16+PpXC$6x?jVG=qs++61=8Rvxq0T&XHGw`uGFw22x~`wW7-C3dZ@VYz!gKbp zu*|@veDn8q*HAj~scSygZ80Qo~OstEfay@kpR!Rnv^?Qk2ge7G=xC15u8%%8sFKLA5Uc%czm} zVp%Tj0N^YyeFX@m$%8yKbdusISK1X?F(p;@*@HAnmDrY53T|_XT}^$gS}KWl){5bO zDJ9mr=eo>|1{i~yWAjX1?naz8swm^Lejw0u5%~BJ5oMO>-0Ta^HEoW+gX6SaowdBX z9`#5jq$XM7dG6kj^?T)MG9oA|7ld(V%tj_FFSmVtb@)$G+4mxKD)vg#xB}JRo*5F` zi9u=`m}Bk)!!u0%bOSQXQl&_!rK;F}H7I1w2~im$)d|Dz4yTHAUE1aNzAMRl>mu?b zsNI^Lxm$0O(cMAE-$^0&ujHE!_<^a;FgAwVIM|ZYwV1!>VW_oyn`pfl@PPkwfFD+7 z@pZ;+CoOKTwt*6$lpCam9GVDcUl6!Rg)DFrX~~(Q(xxw=YBgbY_?uq09V|9~*$}wg zd=Tzq_3Z1aiu6N^NBJ>u4h6EOx|F2IFjsr8P0q`UML;04X<@C_%?vK~-5J#$%MuzN z)oU7@Epehhj_`1#`tGZ*INJr24xhQ)pRo}c(C*U2-kp0pn>mT2!;UF5Ak@)X3w?L_ zE|Rh!KSx~L3D;pbNULX57F0!lL$%KNoYnCYa;b0>+42XANNFV808VhJ{vBLv)M3Ws z4WM$ZSynUoLqi}|!E*cAIr^`jf_eCu91QX*d&8E&f!!N;R0$`lC z%rG4&ZT9zZerJIGh%e2VFET!HBY2ZSdn9Kd>9O)IV^W349`xCD@2H-C*T>9RfQ^Kw zPkD^yeI8PVyu#+DbphPG=fhj(C!^*>*H`R19S69>Gq(9G=>#5O7r=tO#S*^tSI5|O zQ%+asIPORD;N;>@_5&o-X0q#5W9Mg`c-C8xDgBAGUfq27JMFy)!w)rvOWos;jgNwsQc3&K^;op^p(&bL<# zZAWK06lK3-Gjnx8H}~)Q!7-;^qTPf{v6N!=C0hY;R8SN$?A}|-a4K1Jkl#zZ`B-)B ztZopmB(z94<8=Lh$DhA*Dv-JojS*^&voub<17j2qTy* z-xBUB>Ih9EhSr)2wOqD!g(j%xU@8 zS&)22REJW0{8#RUcaWJ+wOD~4TgXe;3{4BncUl6)!rD=Ps#HS8XC>lOb3yrlk4%Jf zg(ruQJL6?SR6Cr(3UMEqA3h9qJ_Zg`a@JNU{h;U6G> z^-!Citqj)wx7QA8fd{|;EJzWpHDSTgq(oRwnZSnkpky-Ss{Lv;gI1$EC^STnldbZhX!ASy9hetC~AHymQpz`N6*_?L0mT$q0)qiIA1KSt({4_N`mIRlNi) zV{x?fTut`oISt_Mr+qHV*Ayz#3zoxA(RmL&(NUQC&piL&W(zexK!YQ=WAe3ZK;MIcxb8Csb3pbL>hh`1h8D3vRa5+x&}NS7)&?yckCi%g>;QpJ*z zI@kQOD%)(R3(g^ zd9CYzYK53*;^z}T*J<5^Fo20hm}x6SC< zv%$F@MlFtt-d$68ODHgSwi3Kp#gl9IIgr4AXw@^>v3G8c5CCwn4#qY4gG=LiuuqTh zp$?;)KZK^5pw&l7))0MRD=Ut-m~Ojt!&?)vb(1B&f+1x1kdt7|{;4OygS8yHj&v^V~PNBwwCr_|2*+f>x5gTrvAJ12nm^Ke14Abk4C9r>xjWuN=h;8 z0$5Bq94CEs8EP+l&ms!*j<5RZw)TI2D^^})C{bmcp)-USTz^g^{ALO{RGR%(xo3X| znk-ha(%7>{%n`T}%x}pVQyS>#fbo&Ii&mX*N=m2(rp!dD-{_58> zQRZgegPGT4sYfGYCmPB&#-JsHbd!j7EU}tdPNXMuu z;H*#4M)}UVvia8MOJ0P3&pUz&75ryYV;DrGR|iMq7LU~1+o$Qc0XnD;d61ZI++FPL zIt>)u7e`LFY*$R%5X(k6ZM`!-e^})5w5Tzt)7xPm<740w88g2(bFLYV7*9IuPrfx=Tbww;%WV+^-q6Uk`m93$h{{bHaQVFw&KtIj_zNE9632#C3C?Wsn-<4RUC&aM zd}~dTY`lEEr^%NdxTNzGl_mpjn9xl`l&WHn4LFw z6xnO*Esrv3*LM_u9Ty_Zl`T7_?8i9N6NyBY{mN2lO?Q?*NV55iMaG*18|NBK5vJSo zNZYm4`*>jWMYy{pa>JgE9%-_<4TQmRB8$!7oq>f*f~n1N?TJdK|2=dpA^F^($25|# zeNm{B61S|APkuIH7GG)M^f=2@D-@HLpIE4&>9yQ3?fFlC>-v$J!n3?KCZ;^ZxOOT& zF0}-Ji3v(d7SZb0(_8JLSAX6rUmN*a%6fyMKXiq=xITy#1=0Ry)&<#~E+FJhb_LDI zS6Jy)@;;aA4lUNFCEhSqvN*JJY5F?Jh>;@?W%9(w2|gf)&nQC?PEjxVDYPR25e%)2 z0oYu;d;;r#D$8svGe~6rz-{|xq&CrfQ(|e{GRTgP%arx?ea+CdHn_$!tP1jV(hH>x zq9yl|lYyIdCx~cC`rXBIlah!brmfb^fX$q3_LS!aLwdPtOY8dG#8o*F)5U*`pT;%F zdQE7?k;5^>u=6nub2YBsQq9qs!5WqA9cW?93n_hnYCJB=k8eKN=>_s{AlEaKfqJY$jpUU>G|_k<|^yZ5KR)FX%s)fwGS zjC?=r<2#P3&X=EOB%w*9Fl$+s~Uvrf(|76%SRMbGsu3_$^31u--?TV z8ELD3fVS}R=I$MZ>}l%+m6y)5{CKec%Ug_GLRvyIe@zN%x!$@8iZ}@L1qTr#V5YJb zs+J+2IrGkZTiH*X&p^;P4`7NGX}*e z-1p}2RXxyZx&+huFb?*nu-7K3KFjhl=c!76<;%WN*NWEa)ISL`l_K*jRo^m7yvorO z1%92ZchC)Oc$SFwx*(V3Nw6iJg;y>6oXGe&qIR1e4&%{bnqsXe&zv{Ja8p ze3bQO@CH@(XgfXVK1Hg)QZ;u_rzV)TcP=ofY$!;}O3X@GdD^;RJDNm|KQpE*JY0f* zNbqaklxm%Qhjgd1B;**6gwGRBz{h8KMaY&o9z$#^avwilFk3vY=a*q1w}4*!4>6bo z;DU|&GGse4jSn43v}=sVg0xD+rb`lH6|*CBVYeEkYQgFQu@{#v@9cznkrAm)Nzx?F?I9H72jiwjnXg-pv_P79y>LwBd06Wjs4k`JI{xYf)G-{ zOu9j+6~di229^Wg!k~OQ#lVPv$zF&Ie=@@(+>ZtKkbDJ8ow3Yl=ET+i=yzzAC}ou2L-`5+$>~!m#&6HU3!3>gRxjk4qM_XzxqV1-Hkho zQQM50fG|XvW@qAmC+N*FSSbe|vC@q0ipponC^Q?h;Ev)w8*b zv(K*%_F~8>TE&o$%ZIqr8|=sPEqQ6r=ZcgPod$L@2F;?;Ll9q9d~hCZP%;zxC(DKN z`?(cw^vbNBGP`t`TPDXTn+2(Non_oQ2uP~RbXF%Bb?~cywt0UZ{#>fGd0lmJ#Ufo1 zGnd9*#N#^_32I_<>LDR}VgsFC<#+$PbyATcJJ5Y%6^7DEKk=>UnTXUQ_yq4QSubeVR4iVL zpy6%O+sG<`cTYEJwX(b}Uu7NKeif~Ig4nYe@kAFU`>w#94{I##4c_nVtV92NIr$_5 zY4mNoXX1_mTGbv0Kkjlo?ecM!;YTENAZk4iN9k98N2$xN&86H~4>q;eSR-U+qZFlr zhzr2eroBgsg(eMoB5)l3Kx%p`iy0bQFp!__O0C z+Av!*P&nZh`sp7Ubh~YcHLh3NGa|Mm+5IIQT%L0FWY_WRlFusLDv?O+qjap3BUHKm zidSZTJZtUnka*#aIHKzmE#3WiSEARx6L|VTizk|?I>_`SkFC9dJvgard>0>J0b&n- z)Ac6_e_)Tp>3wLdWbNbb!mV_G;_eXC$<;6GhY@nrJdsVk;=|b4ya>-XXA(EB)qNtH zs={2_xA;8I=4R7368X!rpX>pKN>MH-*0@c7;;PupPr_-!E-`F-kx4`XB)^mas2`m* zMWpPaxFYTXo}1a9Qy>{J{9Z*J5Uf36p?DAT=fMe+&^xQ0k4hsD2TsI0VsWw{Pa?s2 zGQ#7L_^s>Lr`N6nOH;(8q<}Qnqw(OcSr46CI3V_l<;>_t=$$TsIK4L>lS>t6RJ~1q zS#)C?^dde8JLEHZ|M&nF;AHaF(+dM*IqYZ}bkEL!Y0ps}AzfLcJ4M=)y_Ccqv-FD& z)ozxn&P{iUMV+Nh5XPPtZ868BSRt9ho+3hGUB1tS4wjzX4`$(|H8^Rpt(a-y(6T}9cGb5!6N)$@3-r}wqixr?UVWNOuAf!n%j=n+@8tjt9^|9Hj3G=(;IVoc@k2g11PBW z9}-O-Bfw3vR@$M@uioBt{yDh@^X2dm6A`kme|mkQb@P$Ki$^|j?8v=;j)H+9GH#C0 z(Y#m0wBg30N2|!{+DRSFuO+nHVyWgj6h%;oMVoY&Wo~MLNNt(+*x1bbhkpl-j?VKG zi;ecOXS*g%VGY~-f@j;Gxo-&Qf`5g>?x$uWoONBMS#r5nv16#M?NB)aCK(%vZZ)bu z(wt_@5aI_eAHVC`@NK<+QmcfxUNQHVZ_bTWHmR4WoMV)=bZ%?*r}+b;Mu+j^H>G18 zANJnINRpV(B?D5=L>=0Xj){-&%Asw`l{biG-1b!L=STywN8+lkQf}G;2}aHB3vVJ9 zSRJru{4#l4U5FnSxy%Qb{Ses2)k#YU^mvl+((t^}~|1|l%2^Vxu1xcg1 zFtUq@AbNl=fxi>4p7p-x(Mqsnif*1&?aw749Yi`iy&5Xn1!luN+dPphOaS6DykpF? zK3}5K8}(`94V3?C?flUDub+egz-QTtQUUaLjhE!vW~;#E7%!G9pO~#rgStGG&2xA z?0W6K6S;!iGP`MT15a=8oJCb5JEE(e;nW~>c{uIPe0i;8a$l(IbQyrcvOC!h$?UEl zRd}nueX- zI7LHc>rrukU>t6j@m(0b!ods?K$$e_gzHBsh1RJV^kc%3*9`Gk7S2hv#S@Zs;#r?a zIelQ^gG7=c%B7hvVLT3wgxVIQW@=)f+@_Tt7H+zN)~vB49pY{qnl& zgilmWmwPd438oAjpOi&(qADYNixUf-dUx)LIv)=61+vHUEOnn6J5$mRk4~xiu1q>s zLquzBz*t1LPOX&TA2lZ$+u+W?=2VwV4pex&;yic21Mh}Ai=w_{4 zob+>lKCT?eSNKDKfsMgg>u{mQXd^$(-^L16`p}t+9&W|}A8fr?0Q>wg^fmsAlQ+fR zB0=1Z+q#O2KIpP@UOVoOPXBPou2m?T9saOlk+&b6$f!X;1GD=xgFDU z+px)+a5&t-{R6%VXf-ZTzO&J&K|SXWG_u%#?zv)2@(NgmwhMT3x{0(Z$&PdA8M{ zjCS0R+GI{5-g;?bdB9oNb;W7_*{9AuSwMYPajWb(lj(<39pU9h5v{s^ z;SR_?mv8aPZuR|2uS_e?nW!qZZ3{7+6|O@;nf+N0%B49L zCI6b%gl%`@!!)lCl&TR-Ji!$b7YpV#E^b?pt}xA6{szkhHS~2(r{3|P$&)r_aaSIS59ZNa2V$u zh${Wa4E+qAmieJpR^E1Wqk6%Ad;M|%>!vUsCrGAMCOAwo@ZU*Us?R(=BMy4Yz**aW z=oJG_FB#!aa~??_wM>4e!VsRWmwX3IkaW0O@%Fm@ zIhAAy$l)2&^e^=OL9Ik%&$U(1-t}a_hl4Wy$4j0d4+(#V1Toas7Bli?V3rDf!hi1q z3YUETHz5JL7Br=}`!~IRkw{egH-k|DY(WoKG=916#Tvept#BTZdU;rKaBIqcJ1!a{ zSV47gWQ3A|f#HM)9aAifJV&#vrmksVVxmT7k>k!$2>9`Ro?}5_fz!1DC-mlo>PfA= zq6an~1wk|-iv!ESOqudR?Y5J%yO?TXx83x|8&=Q7DpN`^?Bw!)5rvHnk?iEem^}sGh12A#^?2vS*M{4-uCVPuUY`-g(?h5`J$;GaTu{x+1VB1 z@5RFO5kiCFFak<{WXzpL^{*LVQV*6bn;AADAnO%Z22JG5SV!hFCH$+5po&4%zZbR} zH67|@(pJiPp{Kpx^Zidok-MU|P^d_<9Wq&v;>q-Z>Z1BHJp>}%QhMce(XpUE6T(OOv7OqPGJ2 zWI?nl++FI24Q1hQw2KNG;}WbMwxqh3mt@9XyRS>M!lbY2;;L=Ph*$L`)*KqocQ`uX zdi(nJ=MHNf*z?@PjjgXuCiC8Dpq-HmToKTqL$*SL;dAZ)jc*N*$j*;)`Ak8RynnPh zNj7mSwkBtP&+fNL3WOE}ZFsNfL)Z8B3jm#d>%0VWl|fA@EI8IYM$0?`Q3q`SQWOU% zeDw|*C?ceQVU1GxwbhLvV|$qS5QK2QxlgEn07^l`vZ`JM)zb*z#(-2Ia<}*Y zs8p;+`jR?jhT&jYX*RL@3qMWUP9}9R7j3r$gp`N(r~%;6n4yW(4fGqE5b5AW#oI5x z+!G*XMVXYm)gR_+qb<5z7v@UdYlmQ2Eoff#Oz)E2J(%BnSjpbS!L>hpFP_?>GOrA0 zUF?s4H&@D(ohz;3*$ya6XiLe!}5Sj3vA#1^FvasF$ zwC0*yX!Ya6e$e02Esu97R%cH z-i`!I0lM#G99k~S+{s}~k;qZ^-!(~(CsJD4U0#odK8ejC%irFJG5XAoc3Z7U|Lo|h zt};-Z?i%rO+i^lv&=bAv^UR~*zKGu?;dj%`2LLV#!Ub=R8Og_cF#?WR18uU4mJV%y zq7L@zl)y&~ZDG-TebXrryv0I<6|H6S{&9g8JgmNaT#kL{dAs1%iT`Y`Q3*>*V^nTW zQ7GOcgtWIe(_*SymFTfObm;mhgMqEmmjL8pz^&_lmpzf6L@M1}mpSv;{CvS$ZRQ}? z7!YePFoqc*96?%$zH`9Rqu6f*u^3Q)TgyE~+k_bMM)4$5*SRmL5!~bQ=pC0iD6yS_ zW~LB5GZgg0PEJm$ zL~PZ`XyXERjcId-mPj#Lk8Bc4=6|3}c$kOu&y{?AoD^yY3@HM3`iEpStb_;lFn(Zc z3~?IoVNfeWGxTI-H60R?lZP9b0wzoCe9D@DonLT_+?J|+S2>q5#GP-d6q4iu%RE@e z8@)55vk7R#S(*j#JD&G{bqPWln(>)j%5KrD<__Sdoa<|Ng@g5G#Jt|9U`sx$l^j3z z1F{^`1Cv&qZPT?v0LF0cF=oHb4d%L(<>!B$l4YL`WNj|XjQ+zK0sotZ1dbq7VCpLR zM6YnPHM!_%Wju|S@ye_(N#k0}k&Av))954XlxccagGe7lj29Yz4^^wmhX)QpfdrfV zC5u^J2Lq4Up*lj=7hC);V(I{%M;DP5%6T zSvskZQr+-$JFvjw*5nh_7$b4y2}%Op-5TI__ImSaTs+;XtELIc{d5b33w_r86?KEC z>hkA?k>tvj?7GmgS<@G|#?3cXGlP<^s5{UcgENwBcf2!y*lJ_tdO>gAi2AdLcy+@) zc6^?bUh{kI(V4P@1>LjutINp{ecfgJAU zq2*@DeEPG0QrDkg4DxJLm)Ov)d`)nOf-SgR$)SdSjXcEGfE$;b``o+;p*~x%*Yr;G z;!WLtMGCOZpM__tZb(j^+5V#<8SE!Dzc_J(+m7HvY8^daM+JS|5m|Sl$ zvCd0!iAGnkl8IMm%(K6siwW{z%im0VQ$Er9gd;^1XzptM1ooTv+{*jqpPGHhP4)VI zDo6x>SZhJAXF2@!D<=9h`d14>;;}Sh>1JSZFgFKKT+hGfSHriVTCc~WtwPolMfK$> zy0Rvwoy%#Z_BzL^A@(FhrUIpD-qxtQ_^>*y!CAU|8o>5xOhc4^2e4CL-h-z9v3Yl_ zQ@AdD-9VV5v}mn9<@S2!$u_3Fj?^UPL3C|@u9L3569!*o(ZOb2UhkKU(7+*|%_q~D zPA|}M`qC3h_oF52nOxySoD))3{~V9sEF z_Ogm~k!~ zqi_EtSAj#zDr>gTr*=iQuIfzWm9pMx*FdBz#|}lab(WmVwU$~g`U)ZSZbIXGBrGc2 zlwqg*ino8j(HdTls|qu{NeL~y4shFl;$oJ|+d|6#o~*}H8~*SlicSr@z_wu+b|#UM zbW0jNI+?}LsG|b!D*E`6RHnE-S!Ap%F7l(koF-}yjeO?j4lnqWczxO3SA_|G`tW3V z`1hR9h^l9~XKZUydSvGLc$Mx2@kRn3!a5BRe{T#s#57 z>D*7l`^D;(4G2zPAsEo))vZW>o>DE+ZZXDZ(rX~+paA_|;`CFq$>m|_O#uIz`0?}S zN8KhXaLAQSi|<`6C6!oMXoM8#*V0nDX2lW)0fE#3WGQ&H(CGL~8%9)mK|hBU!Xwt# zH7X3@8x|kLF@iC=HDQ=u2MCmmkAjnG88C5r`KH&Bs)I7)A1OLci$sHeF*a1cr1}i< zQU0y?MCMS2CIw0Sr6L0`{$xs0N%JC(fyg0o?*DKbnW0SGzlW+e&PAFpf}PJ;F8Tb@ z#ce@NRwK*!GLxs+3j-P>e_=QhKjQyA&z(;-IyQ1V^c<22qSc5HgV6~c9UaMYZ3nWT zL52q1=*$kGn3x#J$t+-h(W9IgxrC9NqWtC&(DM3Z4JKeuy-h&CD@zalzMidREuI@~`0ox5B$##HLiVxzUH$XuBGe z-X>r+92EaUwHY0r%WF`I9i}1W|8HiKOG8^ICwkB?-ClOus5^(8Gn;1uYDot;7lD%WPJ3Foy}h0wwF6W8vA^!;z@pi8w@{w< z^iN|CBQO%4x0&Wmxy;uD#VF`_v*62iV*lDBu|r}Z6#L@Hmld#W5K~}E*x=#WXR13} zCFQ8XIzw3h<)JAcJsM(<3d2_Sa|T5Lj}c0v*?9_%tT;A;qdCec_$MeRH88eVci0x| z*(vHK_FcSxWT_lWgs5fg2Wipodth23GFq-bcy7VHVDCB@BhNBbNyZj40>dk%*#py# zMv~QZ$9k-G`$H zvPe=&A+gcVT@lBF5uNMDr+43qET+~sJ2VGgvpNRG?3XpVQ1i!!6GQN3YM30JQil^s z8!?IfqL3l%_?HK-BOgDA3F`h^Xc3!H1!dXV&eo>}34c zzQgYT1Gpvs+r%$4ZTevQ&L5(0&@Cd}NS=MDAX%lKoP6H7E7`l^b$;y)th+qijehuH z$k16RdG+xKa)ewt5r4Jv&`gG>KO#8 z@y=1w1n|Akuj`}0=Ig00HbeKrk#4~Onjp_+pl@@Q!jCZNzKvUK`_Cxb#Gh2LALR>L zJtnkuyU{|>?}9|GiFT!|slQHmf2FQOyU*rA^FaH-+35h}K1`e74t5fj*FL;Xe7J{y zH-A3EqyQk%#qm!upKNs)CEU8KA={_zJ)?)0JgATLSrX1UKYru$vbL~#u!}#`F#V_H z2xf(FoX%``9zLXS1glL7>2~cbK^U>G5@;Iaq{vC$>mpqD^}gRIX45nGJEjO4q8< zKYXa~(OW(~!zZ-h?j8qG!bU&;WPQBEH77xK*S zSl7x>ZZsHf7^$7d?j)Lz$(bzpUHp;CUiQ6YiU<|B-h2h%vH%qo==TliwQYHS)j@x{ zeY?gq+eFSBjQ_ZZq20Qb`2^54ukV!KH})mYG_60{=>lx)7G=uyJ@O)!D&}70m4KbWI7jOMO5!_Y@^&RG;ag{l&xX%x0Q-&MA^i-VujgcBoX6)R$5n*m{9on-t_{+OksqU27)^@Najx~OSKMU9iHt`0`}%+n-gA{A=64)jrm}zsVG`uKAkc;~8M6|3ftI|j5_ zT-w48X(Mrei?6uOy&=LGLeh42ENd7+W zw0Oqa*Vi|^D-rsr4x40_IYT5iwhA!u@QNzs@vUn85d`A3v#>i~f2O4*oheq<@%+IA zHk01}3P0U361KR1wPOSi{GZ^bmy$DIi7>J4ts{xPQ^!)xs&BBU-Tn=>J=ijpq&3aW ze^63<$?(CWd`a-CreaHyQ3wS_U3O<9;=r)txBY~_h=|NqLdhEEZ-v_6e=w4ZIVNU$ zFZm0GqDdUy@{`%B1^ipu*0U^r{5QLdv;>R%Z(pQ0yJgjX^{@227OVc19y9dse4{U( zi>U5>UL4(9AP{J3W`;9r(gBOsvD4OE?$_76{QMsj1F5skDDcBEg6X-KqU$X37Pyr=QmY$Re~g&8eN7YHZgUlg!7PC|Ox$ zvThlIJd5{#T=|&|ql~~iip?!;>V*ol`1rw4R+X2vNiuS9Bp3*IOr8gGPnQAK{#MS( zeiIeFy}hlqhm4~V3FaeVVkV^gi{mEtT`4JhHxG9$UH~__)-N(L%3c6{ypH~hnQ-UK zSZ}jNV{GIWO<4Z6ZjhWx{STmQq*ngV_YY0^OJ;e0CSG&ixfo49e>5YJga!LXv|rYk zhdtXy`#f(zUua zKAm!bHJ``6VeQJuX{|%FLM-&^ccT3r)K|a@vt((UmmR^V&)aY;Nf*^_v>Wd)=hsTE zo>+W;WnYs-MH#GzM@H7UA!+&~8v9L~Qc0iN@7fc&ISl>&mXNAeglQkc&paS;Hn3RG z{xss!&gDQHn7*2hWv8JEYrgmAq}wR-X8{} zOer*G`}%V{w$-MM#!M#cGlS|OWIXk-si9x7+ ztH1cfcrzxQ(L#oHbb3m(_)wLVS;_|bCp~v90tAbpMJvkB_c)npB9g#AU+8B&(?qj> znK_Po3Xr63EX6$+FkT0O&mI^~oEfQ>iaX)U%uk&!5Q7ljs1@qt@VDQIDB&ft;SQ{= z#S}>f9{lqLLA^p$p1O+n;Zw~$6nZh20`jUfmwf%4KE~59lGdsaeh;x}t@ll<{UxeV zxfCS}zQM0(;zXN`D&RWPE2X*X{t)7SY9l`LHus<4#O?iLgInj7_mAF^=_7wW7z|qT zq!X_NNDWXooHFi5Wr{mJfM@gO!tjsgPlXxo8#d;GG!mdaX^-}!!ie*2rmx3EJ}3Rj z`BKVb`RmrMPn@6hy(TDZ4BX-k3m+$L_*^wQFn= zK3|*qvzW#5YMsOnn8u>G)#73C-itZ_O+d20l-< z?6e*D&CRsexxvlhzdF>HN=x05D!Z1l3yd=Q0$xqDeI{v($)tMn#THQ@9hm`yi2M)g z`d=r0Rf%U4U*WZ`Wa0>r%PO=RU(IV1e>m7&OB-c@Xtb~kc!x9|%7-_C=G{-Rcb|lYYw6&d?++~> z@AtMHYDK*EWY0b^NAbdjgP3j=Jke1L=on2A6rcMgv-@R&W z)?WW}$P2q9)%V@~q1}ln`A7-+9*UC@{`MEa}al+Zg-*e@-2_x;Vbw z-aegsylMwjprSFLog0~X_yG?GL~`{(z-@5Js(MTKFtZ1?r{(YlDQ_UL8q_lKy!lA3yIfBCDRH*d~+!d*0&>@8{^Qgye_3_Rk< zzESDSR4@bXF3lD~g--v_%L^Zk-I6L};o?fWFVc0FUb97<96wbTe|F6tZK7Li<=mbN zMU`0U7s}P~nWMkQ?>B+%<%*{YLR{>rsB}6M|3_G{^JikJ*BTxMD;77s)XKO% z3=}z*>C&FSMda-P=w~_zwF;25n>d|TMkF_4Y8ILI|%wA3rBp>KFQ6)X%=tnm?m9b)^0*lz; zSe9?VV`=|UMYmwK`G1hR1hbz^TYJJyh~mb$A5F8BIRM|E?$tbBNX}@dea++3wtm!V zTQWr1+8F+eZ>KSW<$m&o{Qi^K?5vsP_V&^dng>T431e&^f0v1s;zRPmUAqkvzu-(p zBeAYZlQ-9a@LW(t=Z&z|VP(PDc)$q_q;=#VLFmk-7XD$MYoD(N^+Y>*VPS97gP{%N&V9B&Q1Ixm-n%%j6l!d2U zne{gv%MRBCf8HMcmaU|uc7_Z~V)xzFoE7$uF4ov`KzObz?-TjIjS)TBAXIS|_Y$gm z2>%cMXI7A7a&cE~acz#wrvD`}oO%re6L$UFZallzodTvt0<6o!aej_Tf8gA()HPPN_gcKO>7PuyWty3? zp5%A;eP(NToe@5N4=+UUc^9(Zc6o?%Of0RH2z}z^l(AJaPEjj&9eD7V&+on)b+BFz zV(mKx89OG8CR`zV|C-~lyh%YlBFdSdA7Zu9);57!Mh_ho#Mr86478{V%2_8EAm#?V{JoW z_5HZkc)G}YM@jv+?;jVJ2{)U~yzB>-r=fEbvJc~5N`>j}86v#ghdjz>hm{SgJaJ5} zhYq7E(w@r%-WoGjRM6z;ihFC?Abm2Q^dHtde|*l<^+&dYBjrb;UtK;6Voy(pM zEW8&XFsE}iqz9)j(v)-%#&`~XCh*yrl$)eQrja=vgruKnSD4uugw*jpT3miPvvH_(SH{L) z(5(c7nf9w3#_EaxiY_SdPP@h%z0dqXe_3D#8dcai1rRzpw%zpZHbFz`Jhw6vx&Vgt z@vX=rlhxKbrCdkd3lUf~EIZw06dz8Hin`8LIaco?&Y0z)&1+k@I=71-pZH0nVc$1z z62Mk`$isKwrENb zo0PJZShzg+zP6h1VNVKW9(BQ2FUKd8-^`qQRQ)YCN6k#FdH4Okc!?feqVwl$qweuJ zoo1sDf4{q?&fLioWK{iXEPFb2qVWO8gHtr&gU_)S&sl$BXHfQ6e|dQUXZW@C zvGBSIX8Qu$!1*$&++RlZUOt#ckGpx3gM4Ipj(9sH_hq)jywoZcYQ-~2f^u35NJci) zRkfiS(&)hVkNeWVGf276NA9JP6c1YxT*3=4^LVj`EVYWMZzGSx$H{ilA27PNnvmj7-8N5F{qe?j-%#qI4q&Jd}}OX58u_5XgXpsN>38H6EKugg>fQmS$8W7lo8 zmNb`=%59?au*S&?-TNk-QAtwuE8y6 z2<{Tx-90o;aDqb!?(P;mxVyW%!)cyp@AurZ_kPD6yd8rX*nn01ex7!3Qv;yYvMAQ>>dM>fBVzo-~ag{mlZYhQ=-$~LVCjAO7&lXRnh-g04SvW zhku+ibzn^t^&T1aFM(6Uk6EhljEu z;fd#WD4l}~a1zS!`5y!mi}2#QZB&3XTL0=R!`5lpe|U(I1viczei3H5UonKzt57T1 zS$qC!x(Fp2+@KzNhw${!5Ya-$`jv0nE*1aPpDXV@kz4*N0d}Vyw%6qj z99LIYe_Hi+LJs_^_6z~5)9M$6 z(4Qg{IcHDXE>)OpBVH?vQ4UjLxj7NwhJw;0Mn*mqpWJ{F7az~)h^790D;DVrjl6~p z7m@H6S+0?B`2!JsB0O|Z7o&^thyJ}-du%u~e>5~r?5t^7sP+AAMmJbW3`Ir7CNa`n z0qHoC*X&@tW1M}}Li~7e1;vAmD za&}ucXUDz?lCODk5uWGHP9dR+oX*F>$Y#|EVE$rjpClvrWOl#mBb_^CuCYv62&BS9>}nG>xBL%@0dVSU2j^#IqUv#l^(}HhFGxK%f}cb?M>t zJ>iHXb7#>ocdR`pbk0qA&YJ%SwW;TraD-va?52t}I8(-a6!B>2M9G}&)@@@3$@++< z+4)5A8Y+PwQA-D2jNk4J^Q{K_q{8NRe`)7vfq?H<+?$p3I?KFx?*FV<~safNy9D^D(gLzFqfG!Ou+vX&^QVovw zOc`QJt+el91_Oae(Ef0eMx!2#g^+n9aAcvc26tp<6IS-)#Szdi7-H)Nk{ z2RP{ak~eBNa6QB0^uRYtyb@qLDmBqCM!$8-4oz1b`Cl zCp(LiV{_w6O;cSoXx-|ItC%p93pXtOcsAEB-@sDzOW&*W1@53xzXn~h>$-I7z*x39 zO`~ugp1i<=GA7jK7b9_qEVAO`Mag)@#bA`kYGNSmwmu;8MZ3i8l>9 z`(^93;jYV{j)A4g5(f|je+H0~tdM-G^UE=lmjd|PglNI0HS|(`dp;!1jbossgan{s zVg?TkNCP_WFSgL|@GO?q(66#Q9jI zbd|tNvT2g_+za z3LQ{~n21@9@j4yev9jyFE;P1?oAhE*B=T4&Z`>s^Wd%ac>jkA{?6(N>A)41CH=>VI zs!S?t9T6IvA(hc*HnKx@hl6`2#3TH_vj>{y%-`55GOjv8f8Md(jGO-4oDL`h?k_F> zOkW=R3g^lkb?}t+BHv}#lF;4l)Ve5g-5N&;7e|Y24tF|-()IF))!0fIj?EuUNK@xH z@Xc{^e>>d<%s-XDY@=_J?A+n*H%}D;_q~+xVIM;UIHTVC|NwFd|F`L0Hdle{OUZcWd!< z7Z8s?nZm>(CuTVPwZR?N*XzxOamg36DAjYH{dDWP>*W4CgDa$X@5SS#s(6g_+4&xv z!xJK|BCET#vixiK4`6s2r3~swqlRp>7}p=EeG3oyfAv}vcLHtXcAIM3*>jp5r=`1t zn+l{y%qJKh%jf6wS#pe?-G-=vSA{^a4%jiI^u+f4ctwMcng6J(ip7AwRFCedBvux?ZmTtl=SVK4O!m zKGm)B;_+FZeLaXfZR5|4NrFpB zFmfA>@zlP0=8`KA$S4wM8mjh(YA;wkNon77e=hqh^uFyZl=&0C2O1>UW`uoMBG7~; zY?q*#6;~WK(3ChJmh*1FF&XJII=PcFeWJaSlT`Oenq#P_IJ19bWaw9~DLcnWT^=4D zt!+s9eg?``aZwW?%Q}4dA6z}<8B2y{b}$`7Ul?7XK{pUPQ6l8hZrE-T5%PONe$Z|R ze^AS#yXC6>%Z3gQE#j}P3c(&u<1N)c2QM|)^%$@W5MiSUhI)I`8>}pzT`_A&2a)#9G*6X2N2O%smTRMxg^a8^HWUx9(eVL2nutFzI1SD*R7`w~jwB2IYmquC zC78iM8SIYmVNmN~8?oT>d=eAy z?bEs9SEa{7gbva?97XWs|EuXzVq+J8k0zx*(4uFNth#zekTTn6#(zDvf80OLIaUAO z0)dfSi@12Nd>myBljC|UQff${Vpm~(ltbGp%b!8olkO-d{Gl*y@Q!DF&9Iw`MX>4xH(`r+@ z-!6HfUUF)w{_fJ27tbF3%0i&4H62ut#vtHboMZgvz!P82PIt7we{HQp?6=xRN{9sh z3}Qn>#kG2A_LNK_;3B_!Zvh{Z* zw^Gx}fsP9-S>ad`Wv^#{#)=9+dSIJ-G1fn9Z1_Z2>H0=Txg!7jXE8Ucb*RM>_gz%T zmm`n!8s$O0<2+PV`-`$D6ztNj6Nv8%^}?-J5cSFU!C(Pre>n{G>!JK8HHimR_PnDC z_`nFfCK~lUY?!UeH52O;R`9x)D#${(xJ~GTG-i7(`rFm^_q<8afY!Eq!Dlp9IL*CeKkg0YU`0E< zefK|7;6IPydIvS-&L97v0y@v(T&hfF2dzz2^C7A%Te+d5AE@RQlf7MtdxVkb>&?Rk zF2TXU-^nH=1$V0%w1b3#A|oaJ*f-$V&r3;Jf+T|ne=PcHS3SDwhshRq2$Axou$hm4 zF~wU=Q$1KDIsMF+h%ob5z1q`o%AHZuH8N9EA~+zPfuWbGpb3{3 z*$e2o+~fewAWQ-s`Xf)COU4LVXhj#Apr8dD;NASGzb)*H%($X6&O@o0 z-$M)^e^6D5bn3sl7MQcN0R~NMtM>4P(KJ6vOTz-*!Seg}nDWAC5@F)+-@o_SP$6NU zvqjwA&dw(!1b{K+hie4wFyR$v{aAnK3REy>vxfUh_yUQOq#*Ld+|F(F^x)$m{E}b6 zbP{7Tah6gl$H$5H$So{pu`$sFJKKI=s|HVAofHQ}K-9kIZScMLgb|BApIc-$LV3N(-nDoW%6sK_o6Kge|2?l&^z*bmRsMX-kH%}7{Pdir;czHMv&(R zsksA+DAT@aSMh=1M4L*Xx&CYJCsKz_ zv&uoXZL+LSQ2-e#3J-9p2Gww=}yUa-zv0nmRPw-@XMqKrE*0WdjS9C}jf8`y`Ol#YDg6sq!0+OI@+-=d}*ke|g){-?njc z&Yc{xak5-35v4p#KUTG6ePS80skWHCN%T_ety=x;w37M7@elkwXI7B9Y!QO$>ZIOV zD~=Gd9=LO6G!?sI&feo!-XtroIvOE&C%AE%y_P8YwkFJx_QJ5U>eA1}gy+5GJ{s(1 z(0w;&{s>iJN{fp*o+s4%e=n=#@h`kZiPFR|6|t?-DY2-667i1sL1OhA!xUS8R@Hp< zmz!)F?y~$5{DdDpT>tdy+%fAvi0MQQ<}ro9v!lGme^~fjoX%pf%!oLUhmhioIw;My zHhi-Uf)iQQYn!hYOp-ilud9MyABU8gsGCUDff6{h?WQ{Os;yCkm zGJ+tHU{Vu5^`s^T6^8Fnw288fO-&RVyYfw9WVtvWCHur`+77sR510rE2|xIP_rBZy zY_*b!pBC)Li%mqXx31?UIuc3jsN|lkDHNKh5^!!9XY2D56y^)fNVV_e@g3)#JPb^2 zknHS8AYBe4ZM1#6e@~Vg3|TO@S#89{fBnsan|^_{q_C9@HT_odX27$_tHw6|QB zph^vhT3g$!>*qm(Tg`k^8Jtidr^kyZuicl8?|d!zo2de`Z7rrbI9$n)1lVha`(s zMf26tPHeh83`Ipv$WYkX>~}7y2>D$h;kYs0MW@WqLPA)7R4PC(K?4=tZPz&WZ)s{$|MZ zxyg_D`1n|wjH#iFQ? zguKqMf@_|`xo~ib6QFDVv(V*>m8=d*>9+xkeabgrcvRD_TcIjFE+TZzbOz3=E9C+Y zAMY>`I2u|a>bn^h_hC~Tft5P?R=2*f3$3_jX+HI$f9w5n#M>msfGS5NmzkM~Z4nC8 zV+3)m%XbJ2bb8lZA*j4XuD(8gp_G>u1)YeFFu4L`gT8@io~s+wrXH^Y^RukJ0*c36 zk!)e_R_}F^d-})dd&~lrx)A!UgM-wqxI`1_9_}n;sd&B_<*t65iu%)l{FVwF+EE5S zo6gvBf25S3Xl*}JVwI}+|9g}R6_y_&elg@~t}TR7@UtmKuNOrUBSh> zGFwN9&SAT3Z0tsd&*=A#E2>j`PKb07dcC?Ze`310xcFM~RHew@9x}y5bkTDr<*?I- zMfh+6<803x)et1~K{d7iLa5E;W_UkZ!*LKPg6ph*$11sU>qs&7-o~%A>3fo0I>hdY zME}K6_+EC{ep63yaJcStwI9o2%_tQ8lGm#yVp<(`vJr;;!Ef7Zd!b0ZHZ}Z)xq}Pd ze;-kL{-2ZWNH;7IMUQmFI>6H84`G+~{Og_+$yhIt0S4|*U9?L#VuS)tP;hfh1}n=- z%PaV{j9KoK=ou7>2HVe3jrcgB7#$UXcOlH<4wHs}kCQ9nTUjy5{o(w)gPxqECy!^i z3l$jPC0_z#>`Yr{Uq3KDKKzt<5bk)ue>}mT6NNg1FPv#4`c*0rYezs}G*xw+=Ucd~ zf=r(ezoYvy{+3q}OWcy9WD38zWy5`bQhiZ)a)g+u0%f+gcyE8e_6KPx{;VB_OFYMG zD?G$9X5TdF--JKNQ0x7jN_L4L;^=xP`WAyFbZ2WNta?i-S>AgCgKb&LtaO`Yf8T=v z=+=n=lKe8rLTkct<6~J$;xscAslTz1%lDPxOVIkM{Dx{Dd|={-=fm3W=?Xt?+qcUX ztdwdGu*KPOSgS<;OJYtI+g{6beZdR7nCFFH7rbz`jDDlDi>t=RGmFwxRz$ak7SsSi62yP5G=-m;wZn|5 zk>C^~0yqjE%%uw!8E(e6GA8D|r?10mav^D}C9=hb7QRRvpp(<*`uhXkS(BQ&uaSwG z8d^j|1Qr%HmbH5MqFz7li=1&1{e~v7X9F~zh zex8)ss%$?&=fWxUm1eh(L5p?cl@bKg=k9TprLxlfFFz7l;D4FnD$b?Fm#WK!FLkLR z&AQlt_fN*WYO58mpvNcGaoFk$T;L!+Zm{sp+5-Tpg)3;ozOW*B>k=t*7M|rd(0(uM zw+*%-zaskZ=Mt}u{Dpnbe?Awo%`BmG&l`4`tJJVT+OR1cFNGHcX>Vjbc(LT%Z1u-TnV9@^ z(3a_8pj16xT+%lFtRh)8&B;p(c_1%kpm@!@Eb~cxGDAZ;?jYh|e_Amk&h1AXgw(9x zx5w3b;6e>{8-aR1KYJFU4KC&Sew6!ilMh0eo9&kECegdMvm)-%!LfH;7GaCDWV9VT zc5xE3WG}Q4FnF64$IjAP+&0M9Vwp1_{Yp3H>4!IiVD_@w6&*z5Ab88CK)f6PmN=R# zwI3~-_;7MmWUk(Ue=n;IS4p=ODVYIncrr$^o~9fhWg3Wm+G(&xfO{+X`ChFsc<#vu z(sT(Gj! z9)mrR;#v+m2}w+h+i#S+0sbAYLyE0-`!pM?++n?!1;-n`APHfZ#@w>7f*`6q zzS3Gge|q$^9G0Zi3c;25MX}ks6_b1mT8sL9y>f+@5uy_8mIHe4_IQu`OAC;3} z5t5Of>=;Mp_$A1R(xVfI)xM-4yEN-8P65{b>XBPX58@2!u`! ze;S0B@L$J}#Kf;V#aAfXVWE=E(H7&-2xJ&PcxhwJ*li|2-4r7 zuTBp@orvfn91NtDZA^2A>5nEB8J@Mto-q$^i~38i1Ta`xxqCg47JfFfUb@7vU28`Q z>LPX15Wgn8yeRT_vFc#H^@I}fe{ahW)U#SdB+krqzh4)5<;S9U$A2SZD~LCIPE?H& zt_0cWBy{Boa}InBZSAytTV>3gDa#L;k$`u4m5ie_XX6|<(Yj@$MQd~CNWE;e>q~e4 z@xGo{Z7eGKKX=#~z5y~y{Qpv;RVgRTNY6TY3-gvlM;zwz#5_oZpUCnl30O!OPdQi`L8w<8Y+@sA<(;MqrJVNK8I=ad<93WA-l_@H zF>*-bW)5mr=DK8hvebKR0j^QJfFD>o+1LrRTk9d%E6_#{vlP@jw`KQ`ACA6+mPGIu z&sc>hwlCUM3pUj3l^zjgf23D=iSXb<-ghl5^ftae*GstP&6J!wx{2**jj-NmPu2e? zu>QlZJyJ3H91R1Au6RH!JACXJnSq!&tn2>0^HiP4DrGI@mlDPF;jn9J1dCW`X1wZ+ zCtYR^uc4ql(JVh;hm3aIe;?<>FQQM0sWoe}RcusBobT0!mbGrSDGLq~C}=FiOsigCADnMlocj4JL57WQ~?LOmvJh0Kk?cCA{8Hd&2F|^4UueIn+-Nkd~K)KTJa$CcZa-fy?VhQQp_P z@%yY~-Dd;AIo+9Oe~#<2q=vNL>FVxc|5lTu&*z1~_P2gdIhL`5r-EO+>mM`%z;&h{ zcF)(c-u!t;9lk08!E}^7^@_y46BkeK=&yM=>(e^~(vA2* zWt!8>pRX=1apN(_>FNHn<{Hjr7ajYEL=O(uU~H?f70OwO~!jro+`@VJIAFc z+A>a}+~9=6QBDB#?_4xrWI^T9oU8@{^b=lK@#Db>Bah-nKS^dZkgWGDXab0R=uBVY zJQl4Y@Jio~++T zTo+w{-leZ>UaXHV^VCe3Tiv>yF!V?M4DYORtTEldnuFobm5!JYg!Ydb_Zse=9$21! z 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 literal 226795 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�*#xlaG_6 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ℜnCzI1TgiG=!4M*4Fr0{UDIup?AX^qp;+A60 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 S85ZEn9|8zS$p%0g1N|Q}3-KEO diff --git a/Documentation/GUI_Translation_HOWTO.pdf b/Documentation/GUI_Translation_HOWTO.pdf index 484c38a277c8713a31fdc394c83fb21b41c59002..6e6e408defa0f8b2cff0b19677f68e1d1863f632 100644 GIT binary patch delta 193759 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 +`zyEgJ<-)%Dw`O|NtZCD%Rpr?ZH~ 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 gjG@E?dDDTn#P?k}vP;!jFU6KRWewlqbj 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�C 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 z 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 2.9.3 +use *only* wxWidgets >= 3.0 wxGTK Use wxWidgets 2.8.10 or later @@ -21,15 +20,6 @@ So use a very recent version (>= 2.8.10 (that also solve other bugs) wxWidgets patch: -wxMSW, version 2.8.x -Some zoom values smaller than 3 to 5 create artifacts on screen, mainly values < 1. -(corresponding to draw scale factor > 1 ) - -See http://trac.wxwidgets.org/ticket/9554 (and 11669). - -This is fixed in version 2.9.3 - - wxWidgets 2.9.1 (all platforms) Has a problem when using the built in string to double conversion: In countries using a comm instead of a point as floating number separator @@ -41,7 +31,7 @@ Use a version >= 2.9.3 ************************************************************************************* -wxGTK version: All +wxGTK version: All before wxWidgets 3.0 ************************************************************************************* Patch for printing wide traces that were shown with missing rounded end caps. Without this patch, printing boards and schematics under Linux, and perhaps OSX @@ -57,3 +47,10 @@ Add after this line: PsPrint( "1 setlinecap\n" ); PsPrint("%%EndSetup\n"); + +Known bug on Windows: +Postscript printers print tracks like tin line. +It happens only for PS drivers, and PDF printer. +Other drivers (PCL for instance) work fine, +so it is unlikely a bug inside Kicad/wxWidgets + diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 37d10da7e5..509fd046d6 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -149,8 +149,8 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP { m_canUpdate = false; m_parent = aParent; - m_currentPad = aPad; // aPad can be NULL, if the dialog is calleg - // from the modoule editor to set default pad characteristics + m_currentPad = aPad; // aPad can be NULL, if the dialog is called + // from the module editor to set default pad characteristics m_board = m_parent->GetBoard(); m_dummyPad = new D_PAD( (MODULE*) NULL ); From 59a0ced0a6853816df3afe4cd65b77c843410d83 Mon Sep 17 00:00:00 2001 From: Orson Date: Fri, 14 Mar 2014 21:32:25 +0100 Subject: [PATCH 17/46] Corrected the error message about required OpenGL version for GAL. Fixed pcb_calculator .desktop file. --- common/gal/opengl/opengl_gal.cpp | 4 ++-- resources/linux/mime/applications/pcbcalculator.desktop | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index f9cccbd365..0884ed2345 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -941,11 +941,11 @@ void OPENGL_GAL::initGlew() // Check the OpenGL version (minimum 2.1 is required) if( GLEW_VERSION_2_1 ) { - wxLogInfo( wxT( "OpenGL Version 2.1 supported." ) ); + wxLogInfo( wxT( "OpenGL 2.1 supported." ) ); } else { - DisplayError( parentWindow, wxT( "OpenGL Version 2.1 is not supported!" ) ); + DisplayError( parentWindow, wxT( "OpenGL 2.1 or higher is required!" ) ); exit( 1 ); } diff --git a/resources/linux/mime/applications/pcbcalculator.desktop b/resources/linux/mime/applications/pcbcalculator.desktop index 7c449f3fef..4ae5e3e841 100644 --- a/resources/linux/mime/applications/pcbcalculator.desktop +++ b/resources/linux/mime/applications/pcbcalculator.desktop @@ -2,7 +2,7 @@ [Desktop Entry] Categories=Development;Electronics Comment=Design a printed circuit board -Exec=pcbcalculator +Exec=pcb_calculator GenericName=EDA Suite Icon=pcbcalculator MimeType=application/x-pcbcalculator-project; From 91c53a947aff2097b8933eda0b48d1df7fb0e9c6 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sun, 16 Mar 2014 15:10:42 +0100 Subject: [PATCH 18/46] bitmap2component: add management of image resolution: Is read from file, when exists, and can be modified in bitmap2component. It also fix issue #747631 --- bitmap2component/bitmap2cmp_gui.cpp | 160 ++-- bitmap2component/bitmap2cmp_gui_base.cpp | 87 ++- bitmap2component/bitmap2cmp_gui_base.fbp | 888 ++++++++++++++++++----- bitmap2component/bitmap2cmp_gui_base.h | 20 +- bitmap2component/bitmap2component.cpp | 20 +- 5 files changed, 911 insertions(+), 264 deletions(-) diff --git a/bitmap2component/bitmap2cmp_gui.cpp b/bitmap2component/bitmap2cmp_gui.cpp index d83a0fce8c..52f5c134b7 100644 --- a/bitmap2component/bitmap2cmp_gui.cpp +++ b/bitmap2component/bitmap2cmp_gui.cpp @@ -27,10 +27,6 @@ #include #include -#include -#include -#include - #include #include @@ -50,7 +46,10 @@ #define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" ) #define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" ) -extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ); +#define DEFAULT_DPI 300 // Default resolution in Bit per inches + +extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, + int aFormat, int aDpi_X, int aDpi_Y ); /* Class BM2CMP_FRAME_BASE This is the main frame for this application @@ -64,11 +63,13 @@ private: wxBitmap m_Greyscale_Bitmap; wxImage m_NB_Image; wxBitmap m_BN_Bitmap; + wxSize m_imageDPI; // The initial image resolution. When unknown, + // set to DEFAULT_DPI x DEFAULT_DPI per Inch wxString m_BitmapFileName; wxString m_ConvertedFileName; - wxSize m_FrameSize; - wxPoint m_FramePos; - wxConfig * m_Config; + wxSize m_frameSize; + wxPoint m_framePos; + wxConfig* m_config; public: BM2CMP_FRAME(); @@ -109,27 +110,43 @@ private: void Binarize( double aThreshold ); // aThreshold = 0.0 (black level) to 1.0 (white level) void OnOptionsSelection( wxCommandEvent& event ); void OnThresholdChange( wxScrollEvent& event ); + void OnResolutionChange( wxCommandEvent& event ); + + // called when texts controls which handle the image resolution + // lose the focus, to ensure the rigyht vaules are displayed + // because the m_imageDPI are clipped to acceptable values, and + // the text displayed could be differ duringa text edition + // We are using ChangeValue here to avoid generating a wxEVT_TEXT event. + void UpdateDPITextValueX( wxMouseEvent& event ) + { + m_DPIValueX->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.x ) ); + } + void UpdateDPITextValueY( wxMouseEvent& event ) + { + m_DPIValueY->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.y ) ); + } + void NegateGreyscaleImage( ); void ExportFile( FILE* aOutfile, int aFormat ); + void updateImageInfo(); }; - BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) { int tmp; - m_Config = new wxConfig(); - m_Config->Read( KEYWORD_FRAME_POSX, & m_FramePos.x, -1 ); - m_Config->Read( KEYWORD_FRAME_POSY, & m_FramePos.y, -1 ); - m_Config->Read( KEYWORD_FRAME_SIZEX, & m_FrameSize.x, -1 ); - m_Config->Read( KEYWORD_FRAME_SIZEY, & m_FrameSize.y, -1 ); - m_Config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); - m_Config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); - if( m_Config->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) ) + m_config = new wxConfig(); + m_config->Read( KEYWORD_FRAME_POSX, & m_framePos.x, -1 ); + m_config->Read( KEYWORD_FRAME_POSY, & m_framePos.y, -1 ); + m_config->Read( KEYWORD_FRAME_SIZEX, & m_frameSize.x, -1 ); + m_config->Read( KEYWORD_FRAME_SIZEY, & m_frameSize.y, -1 ); + m_config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); + m_config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); + if( m_config->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) ) m_sliderThreshold->SetValue( tmp ); - if( m_Config->Read( KEYWORD_BW_NEGATIVE, &tmp ) ) + if( m_config->Read( KEYWORD_BW_NEGATIVE, &tmp ) ) m_rbOptions->SetSelection( tmp ? 1 : 0 ); - m_Config->Read( KEYWORD_LAST_FORMAT, &tmp ); + m_config->Read( KEYWORD_LAST_FORMAT, &tmp ); m_radioBoxFormat->SetSelection( tmp ); @@ -140,34 +157,36 @@ BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) GetSizer()->SetSizeHints( this ); - SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); + SetSize( m_framePos.x, m_framePos.y, m_frameSize.x, m_frameSize.y ); m_buttonExport->Enable( false ); - if ( m_FramePos == wxDefaultPosition ) + m_imageDPI.x = m_imageDPI.y = DEFAULT_DPI; // Default resolution in Bit per inches + + if ( m_framePos == wxDefaultPosition ) Centre(); } BM2CMP_FRAME::~BM2CMP_FRAME() { - if( ( m_Config == NULL ) || IsIconized() ) + if( ( m_config == NULL ) || IsIconized() ) return; - m_FrameSize = GetSize(); - m_FramePos = GetPosition(); + m_frameSize = GetSize(); + m_framePos = GetPosition(); - m_Config->Write( KEYWORD_FRAME_POSX, (long) m_FramePos.x ); - m_Config->Write( KEYWORD_FRAME_POSY, (long) m_FramePos.y ); - m_Config->Write( KEYWORD_FRAME_SIZEX, (long) m_FrameSize.x ); - m_Config->Write( KEYWORD_FRAME_SIZEY, (long) m_FrameSize.y ); - m_Config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName ); - m_Config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName ); - m_Config->Write( KEYWORD_BINARY_THRESHOLD, m_sliderThreshold->GetValue() ); - m_Config->Write( KEYWORD_BW_NEGATIVE, m_rbOptions->GetSelection() ); - m_Config->Write( KEYWORD_LAST_FORMAT, m_radioBoxFormat->GetSelection() ); + m_config->Write( KEYWORD_FRAME_POSX, (long) m_framePos.x ); + m_config->Write( KEYWORD_FRAME_POSY, (long) m_framePos.y ); + m_config->Write( KEYWORD_FRAME_SIZEX, (long) m_frameSize.x ); + m_config->Write( KEYWORD_FRAME_SIZEY, (long) m_frameSize.y ); + m_config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName ); + m_config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName ); + m_config->Write( KEYWORD_BINARY_THRESHOLD, m_sliderThreshold->GetValue() ); + m_config->Write( KEYWORD_BW_NEGATIVE, m_rbOptions->GetSelection() ); + m_config->Write( KEYWORD_LAST_FORMAT, m_radioBoxFormat->GetSelection() ); - delete m_Config; + delete m_config; /* This needed for OSX: avoids further OnDraw processing after this * destructor and before the native window is destroyed @@ -246,15 +265,31 @@ bool BM2CMP_FRAME::LoadFile( wxString& aFullFileName ) int h = m_Pict_Bitmap.GetHeight(); int w = m_Pict_Bitmap.GetWidth(); - int nb = m_Pict_Bitmap.GetDepth(); + // Determine image resolution in DPI (does not existing in all formats). + // the resolution can be given in bit per inches or bit per cm in file + m_imageDPI.x = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONX ); + m_imageDPI.y = m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONY ); - wxString msg; - msg.Printf( wxT( "%d" ), w ); - m_SizeXValue->SetLabel(msg); - msg.Printf( wxT( "%d" ), h ); - m_SizeYValue->SetLabel(msg); - msg.Printf( wxT( "%d" ), nb ); - m_BPPValue->SetLabel(msg); + if( m_imageDPI.x > 1 && m_imageDPI.y > 1 ) + { + if( m_Pict_Image.GetOptionInt( wxIMAGE_OPTION_RESOLUTIONUNIT ) == wxIMAGE_RESOLUTION_CM ) + { + // When the initial resolution is given in bits per cm, + // experience shows adding 1.27 to the resolution converted in dpi + // before convert to int value reduce the conversion error + // but it is not perfect + m_imageDPI.x = m_imageDPI.x * 2.54 + 1.27; + m_imageDPI.y = m_imageDPI.y * 2.54 + 1.27; + } + } + else // fallback to the default value + m_imageDPI.x = m_imageDPI.y = DEFAULT_DPI; + + // Display image info: + // We are using ChangeValue here to avoid generating a wxEVT_TEXT event. + m_DPIValueX->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.x ) ); + m_DPIValueY->ChangeValue( wxString::Format( wxT( "%d" ), m_imageDPI.y ) ); + updateImageInfo(); m_InitialPicturePanel->SetVirtualSize( w, h ); m_GreyscalePicturePanel->SetVirtualSize( w, h ); @@ -272,6 +307,43 @@ bool BM2CMP_FRAME::LoadFile( wxString& aFullFileName ) return true; } +void BM2CMP_FRAME::updateImageInfo() +{ + // Note: the image resolution text controls are not modified + // here, to avoid a race between text change when entered by user and + // a text change if it is modifed here. + int h = m_Pict_Bitmap.GetHeight(); + int w = m_Pict_Bitmap.GetWidth(); + int nb = m_Pict_Bitmap.GetDepth(); + + m_SizeXValue->SetLabel( wxString::Format( wxT( "%d" ), w ) ); + m_SizeYValue->SetLabel( wxString::Format( wxT( "%d" ), h ) ); + m_BPPValue->SetLabel( wxString::Format( wxT( "%d" ), nb ) ); + + m_SizeXValue_mm->SetLabel( wxString::Format( wxT( "%.1f" ), + (double) w / m_imageDPI.x * 25.4 ) ); + m_SizeYValue_mm->SetLabel( wxString::Format( wxT( "%.1f" ), + (double) h / m_imageDPI.y * 25.4 ) ); +} + +void BM2CMP_FRAME::OnResolutionChange( wxCommandEvent& event ) +{ + long tmp; + + if( m_DPIValueX->GetValue().ToLong( &tmp ) ) + m_imageDPI.x = tmp; + + if( m_DPIValueY->GetValue().ToLong( &tmp ) ) + m_imageDPI.y = tmp; + + if( m_imageDPI.x < 32 ) + m_imageDPI.x = 32; + + if( m_imageDPI.y < 32 ) + m_imageDPI.y = 32; + + updateImageInfo(); +} void BM2CMP_FRAME::Binarize( double aThreshold ) { @@ -514,14 +586,14 @@ void BM2CMP_FRAME::ExportFile( FILE* aOutfile, int aFormat ) /* fill the bitmap with data */ for( int y = 0; y < h; y++ ) { - for( int x = 0; xAddGrowableCol( 1 ); + fgSizerInfo->AddGrowableCol( 2 ); fgSizerInfo->SetFlexibleDirection( wxBOTH ); fgSizerInfo->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - m_staticTextSizeX = new wxStaticText( m_panelRight, wxID_ANY, _("Size X:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextSizeX->Wrap( -1 ); - fgSizerInfo->Add( m_staticTextSizeX, 0, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + m_staticTextSize = new wxStaticText( m_panelRight, wxID_ANY, _("Size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSize->Wrap( -1 ); + fgSizerInfo->Add( m_staticTextSize, 0, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 5 ); m_SizeXValue = new wxStaticText( m_panelRight, wxID_ANY, _("0000"), wxDefaultPosition, wxDefaultSize, 0 ); m_SizeXValue->Wrap( -1 ); - fgSizerInfo->Add( m_SizeXValue, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_SizeXunits = new wxStaticText( m_panelRight, wxID_ANY, _("pixels"), wxDefaultPosition, wxDefaultSize, 0 ); - m_SizeXunits->Wrap( -1 ); - fgSizerInfo->Add( m_SizeXunits, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_staticTextSizeY = new wxStaticText( m_panelRight, wxID_ANY, _("Size Y:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextSizeY->Wrap( -1 ); - fgSizerInfo->Add( m_staticTextSizeY, 0, wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + fgSizerInfo->Add( m_SizeXValue, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); m_SizeYValue = new wxStaticText( m_panelRight, wxID_ANY, _("0000"), wxDefaultPosition, wxDefaultSize, 0 ); m_SizeYValue->Wrap( -1 ); - fgSizerInfo->Add( m_SizeYValue, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + fgSizerInfo->Add( m_SizeYValue, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); - m_SizeYunits = new wxStaticText( m_panelRight, wxID_ANY, _("pixels"), wxDefaultPosition, wxDefaultSize, 0 ); - m_SizeYunits->Wrap( -1 ); - fgSizerInfo->Add( m_SizeYunits, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + m_SizePixUnits = new wxStaticText( m_panelRight, wxID_ANY, _("pixels"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizePixUnits->Wrap( -1 ); + fgSizerInfo->Add( m_SizePixUnits, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 ); + + m_staticTextSize1 = new wxStaticText( m_panelRight, wxID_ANY, _("Size:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSize1->Wrap( -1 ); + fgSizerInfo->Add( m_staticTextSize1, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_RIGHT, 5 ); + + m_SizeXValue_mm = new wxStaticText( m_panelRight, wxID_ANY, _("0000"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeXValue_mm->Wrap( -1 ); + fgSizerInfo->Add( m_SizeXValue_mm, 0, wxBOTTOM|wxRIGHT, 5 ); + + m_SizeYValue_mm = new wxStaticText( m_panelRight, wxID_ANY, _("0000"), wxDefaultPosition, wxDefaultSize, 0 ); + m_SizeYValue_mm->Wrap( -1 ); + fgSizerInfo->Add( m_SizeYValue_mm, 0, wxBOTTOM|wxRIGHT, 5 ); + + m_Size_mmxUnits = new wxStaticText( m_panelRight, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 ); + m_Size_mmxUnits->Wrap( -1 ); + fgSizerInfo->Add( m_Size_mmxUnits, 0, wxBOTTOM|wxRIGHT, 5 ); m_staticTextBPP = new wxStaticText( m_panelRight, wxID_ANY, _("BPP:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticTextBPP->Wrap( -1 ); @@ -75,17 +85,38 @@ BM2CMP_FRAME_BASE::BM2CMP_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxS m_BPPValue = new wxStaticText( m_panelRight, wxID_ANY, _("0000"), wxDefaultPosition, wxDefaultSize, 0 ); m_BPPValue->Wrap( -1 ); - fgSizerInfo->Add( m_BPPValue, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + fgSizerInfo->Add( m_BPPValue, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 ); m_BPPunits = new wxStaticText( m_panelRight, wxID_ANY, _("bits"), wxDefaultPosition, wxDefaultSize, 0 ); m_BPPunits->Wrap( -1 ); fgSizerInfo->Add( m_BPPunits, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + fgSizerInfo->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_staticTextBPI = new wxStaticText( m_panelRight, wxID_ANY, _("Resolution:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextBPI->Wrap( -1 ); + fgSizerInfo->Add( m_staticTextBPI, 0, wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); + + m_DPIValueX = new wxTextCtrl( m_panelRight, wxID_ANY, _("300"), wxDefaultPosition, wxDefaultSize, 0 ); + m_DPIValueX->SetMinSize( wxSize( 40,-1 ) ); + + fgSizerInfo->Add( m_DPIValueX, 0, wxBOTTOM|wxRIGHT, 5 ); + + m_DPIValueY = new wxTextCtrl( m_panelRight, wxID_ANY, _("300"), wxDefaultPosition, wxDefaultSize, 0 ); + m_DPIValueY->SetMinSize( wxSize( 40,-1 ) ); + + fgSizerInfo->Add( m_DPIValueY, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 ); + + m_DPI_Units = new wxStaticText( m_panelRight, wxID_ANY, _("DPI"), wxDefaultPosition, wxDefaultSize, 0 ); + m_DPI_Units->Wrap( -1 ); + fgSizerInfo->Add( m_DPI_Units, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 ); + + sbSizerInfo->Add( fgSizerInfo, 0, wxEXPAND|wxBOTTOM, 5 ); - brightSizer->Add( sbSizerInfo, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + brightSizer->Add( sbSizerInfo, 0, wxEXPAND|wxALL, 5 ); m_buttonLoad = new wxButton( m_panelRight, wxID_ANY, _("Load Bitmap"), wxDefaultPosition, wxDefaultSize, 0 ); brightSizer->Add( m_buttonLoad, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); @@ -98,18 +129,18 @@ BM2CMP_FRAME_BASE::BM2CMP_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxS wxString m_radioBoxFormatChoices[] = { _("Eeschema"), _("Pcbnew old fmt (.emp)"), _("Pcbnew kicad_mod"), _("Postscript"), _("Logo for title block") }; int m_radioBoxFormatNChoices = sizeof( m_radioBoxFormatChoices ) / sizeof( wxString ); m_radioBoxFormat = new wxRadioBox( m_panelRight, wxID_ANY, _("Format"), wxDefaultPosition, wxDefaultSize, m_radioBoxFormatNChoices, m_radioBoxFormatChoices, 1, wxRA_SPECIFY_COLS ); - m_radioBoxFormat->SetSelection( 4 ); - brightSizer->Add( m_radioBoxFormat, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + m_radioBoxFormat->SetSelection( 2 ); + brightSizer->Add( m_radioBoxFormat, 0, wxEXPAND|wxALL, 5 ); wxString m_rbOptionsChoices[] = { _("Normal"), _("Negative") }; int m_rbOptionsNChoices = sizeof( m_rbOptionsChoices ) / sizeof( wxString ); m_rbOptions = new wxRadioBox( m_panelRight, wxID_ANY, _("Options"), wxDefaultPosition, wxDefaultSize, m_rbOptionsNChoices, m_rbOptionsChoices, 1, wxRA_SPECIFY_COLS ); m_rbOptions->SetSelection( 0 ); - brightSizer->Add( m_rbOptions, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + brightSizer->Add( m_rbOptions, 0, wxEXPAND|wxALL, 5 ); m_ThresholdText = new wxStaticText( m_panelRight, wxID_ANY, _("Threshold Value:"), wxDefaultPosition, wxDefaultSize, 0 ); m_ThresholdText->Wrap( -1 ); - brightSizer->Add( m_ThresholdText, 0, wxRIGHT|wxLEFT, 5 ); + brightSizer->Add( m_ThresholdText, 0, wxTOP|wxRIGHT|wxLEFT, 5 ); m_sliderThreshold = new wxSlider( m_panelRight, wxID_ANY, 50, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_LABELS ); m_sliderThreshold->SetToolTip( _("Adjust the level to convert the greyscale picture to a black and white picture.") ); @@ -131,6 +162,10 @@ BM2CMP_FRAME_BASE::BM2CMP_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxS m_InitialPicturePanel->Connect( wxEVT_PAINT, wxPaintEventHandler( BM2CMP_FRAME_BASE::OnPaint ), NULL, this ); m_GreyscalePicturePanel->Connect( wxEVT_PAINT, wxPaintEventHandler( BM2CMP_FRAME_BASE::OnPaint ), NULL, this ); m_BNPicturePanel->Connect( wxEVT_PAINT, wxPaintEventHandler( BM2CMP_FRAME_BASE::OnPaint ), NULL, this ); + m_DPIValueX->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BM2CMP_FRAME_BASE::UpdatePPITextValueX ), NULL, this ); + m_DPIValueX->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnResolutionChange ), NULL, this ); + m_DPIValueY->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BM2CMP_FRAME_BASE::UpdatePPITextValueY ), NULL, this ); + m_DPIValueY->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnResolutionChange ), NULL, this ); m_buttonLoad->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnLoadFile ), NULL, this ); m_buttonExport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnExport ), NULL, this ); m_rbOptions->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnOptionsSelection ), NULL, this ); @@ -143,6 +178,10 @@ BM2CMP_FRAME_BASE::~BM2CMP_FRAME_BASE() m_InitialPicturePanel->Disconnect( wxEVT_PAINT, wxPaintEventHandler( BM2CMP_FRAME_BASE::OnPaint ), NULL, this ); m_GreyscalePicturePanel->Disconnect( wxEVT_PAINT, wxPaintEventHandler( BM2CMP_FRAME_BASE::OnPaint ), NULL, this ); m_BNPicturePanel->Disconnect( wxEVT_PAINT, wxPaintEventHandler( BM2CMP_FRAME_BASE::OnPaint ), NULL, this ); + m_DPIValueX->Disconnect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BM2CMP_FRAME_BASE::UpdatePPITextValueX ), NULL, this ); + m_DPIValueX->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnResolutionChange ), NULL, this ); + m_DPIValueY->Disconnect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( BM2CMP_FRAME_BASE::UpdatePPITextValueY ), NULL, this ); + m_DPIValueY->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnResolutionChange ), NULL, this ); m_buttonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnLoadFile ), NULL, this ); m_buttonExport->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnExport ), NULL, this ); m_rbOptions->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( BM2CMP_FRAME_BASE::OnOptionsSelection ), NULL, this ); diff --git a/bitmap2component/bitmap2cmp_gui_base.fbp b/bitmap2component/bitmap2cmp_gui_base.fbp index d848aa0d8c..c53486ff54 100644 --- a/bitmap2component/bitmap2cmp_gui_base.fbp +++ b/bitmap2component/bitmap2cmp_gui_base.fbp @@ -20,8 +20,10 @@ . 1 + 1 1 1 + UI 0 0 @@ -506,7 +508,7 @@ none 5 - wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + wxEXPAND|wxALL 0 wxID_ANY @@ -521,16 +523,16 @@ wxEXPAND|wxBOTTOM 0 - 3 + 4 wxBOTH - + 1,2 0 fgSizerInfo wxFLEX_GROWMODE_SPECIFIED none - 3 + 0 0 5 @@ -564,7 +566,7 @@ 0 0 wxID_ANY - Size X: + Size: 0 @@ -572,7 +574,7 @@ 0 1 - m_staticTextSizeX + m_staticTextSize 1 @@ -617,7 +619,7 @@ 5 - wxALL|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT 0 1 @@ -700,173 +702,7 @@ 5 - wxALL|wxALIGN_CENTER_VERTICAL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - pixels - - 0 - - - 0 - - 1 - m_SizeXunits - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Size Y: - - 0 - - - 0 - - 1 - m_staticTextSizeY - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT 0 1 @@ -949,7 +785,7 @@ 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT 0 1 @@ -987,7 +823,339 @@ 0 1 - m_SizeYunits + m_SizePixUnits + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_RIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Size: + + 0 + + + 0 + + 1 + m_staticTextSize1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0000 + + 0 + + + 0 + + 1 + m_SizeXValue_mm + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + 0000 + + 0 + + + 0 + + 1 + m_SizeYValue_mm + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + mm + + 0 + + + 0 + + 1 + m_Size_mmxUnits 1 @@ -1115,7 +1283,7 @@ 5 - wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT 0 1 @@ -1279,6 +1447,364 @@ + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Resolution: + + 0 + + + 0 + + 1 + m_staticTextBPI + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + 40,-1 + 1 + m_DPIValueX + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 300 + + + + + + + + + + UpdatePPITextValueX + + + + + + + + + + + + + + + + OnResolutionChange + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + 40,-1 + 1 + m_DPIValueY + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + 300 + + + + + + + + + + UpdatePPITextValueY + + + + + + + + + + + + + + + + OnResolutionChange + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + DPI + + 0 + + + 0 + + 1 + m_DPI_Units + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1461,7 +1987,7 @@ 5 - wxBOTTOM|wxRIGHT|wxLEFT + wxEXPAND|wxALL 0 1 @@ -1509,7 +2035,7 @@ 1 Resizable - 4 + 2 1 wxRA_SPECIFY_COLS @@ -1551,7 +2077,7 @@ 5 - wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT + wxEXPAND|wxALL 0 1 @@ -1641,7 +2167,7 @@ 5 - wxRIGHT|wxLEFT + wxTOP|wxRIGHT|wxLEFT 0 1 diff --git a/bitmap2component/bitmap2cmp_gui_base.h b/bitmap2component/bitmap2cmp_gui_base.h index 301a63398b..0963e547ca 100644 --- a/bitmap2component/bitmap2cmp_gui_base.h +++ b/bitmap2component/bitmap2cmp_gui_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 6 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -47,15 +48,21 @@ class BM2CMP_FRAME_BASE : public wxFrame wxScrolledWindow* m_GreyscalePicturePanel; wxScrolledWindow* m_BNPicturePanel; wxPanel* m_panelRight; - wxStaticText* m_staticTextSizeX; + wxStaticText* m_staticTextSize; wxStaticText* m_SizeXValue; - wxStaticText* m_SizeXunits; - wxStaticText* m_staticTextSizeY; wxStaticText* m_SizeYValue; - wxStaticText* m_SizeYunits; + wxStaticText* m_SizePixUnits; + wxStaticText* m_staticTextSize1; + wxStaticText* m_SizeXValue_mm; + wxStaticText* m_SizeYValue_mm; + wxStaticText* m_Size_mmxUnits; wxStaticText* m_staticTextBPP; wxStaticText* m_BPPValue; wxStaticText* m_BPPunits; + wxStaticText* m_staticTextBPI; + wxTextCtrl* m_DPIValueX; + wxTextCtrl* m_DPIValueY; + wxStaticText* m_DPI_Units; wxButton* m_buttonLoad; wxButton* m_buttonExport; wxRadioBox* m_radioBoxFormat; @@ -66,6 +73,9 @@ class BM2CMP_FRAME_BASE : public wxFrame // Virtual event handlers, overide them in your derived class virtual void OnPaint( wxPaintEvent& event ) { event.Skip(); } + virtual void UpdatePPITextValueX( wxMouseEvent& event ) { event.Skip(); } + virtual void OnResolutionChange( wxCommandEvent& event ) { event.Skip(); } + virtual void UpdatePPITextValueY( wxMouseEvent& event ) { event.Skip(); } virtual void OnLoadFile( wxCommandEvent& event ) { event.Skip(); } virtual void OnExport( wxCommandEvent& event ) { event.Skip(); } virtual void OnOptionsSelection( wxCommandEvent& event ) { event.Skip(); } diff --git a/bitmap2component/bitmap2component.cpp b/bitmap2component/bitmap2component.cpp index 245cfc3447..83014cfa93 100644 --- a/bitmap2component/bitmap2component.cpp +++ b/bitmap2component/bitmap2component.cpp @@ -138,12 +138,12 @@ BITMAPCONV_INFO::BITMAPCONV_INFO() } -int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ) +int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, + int aFormat, int aDpi_X, int aDpi_Y ) { potrace_param_t* param; potrace_state_t* st; - // set tracing parameters, starting from defaults param = potrace_param_default(); if( !param ) @@ -171,8 +171,8 @@ int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFo { case 4: info.m_Format = KICAD_LOGO; - info.m_ScaleX = 1e3 * 25.4 / 300; // the conversion scale from PPI to micro - info.m_ScaleY = info.m_ScaleX; // Y axis is top to bottom + info.m_ScaleX = 1e3 * 25.4 / aDpi_X; // the conversion scale from PPI to micro + info.m_ScaleY = 1e3 * 25.4 / aDpi_Y; // Y axis is top to bottom info.CreateOutputFile(); break; @@ -186,22 +186,22 @@ int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFo case 2: info.m_Format = EESCHEMA_FMT; - info.m_ScaleX = 1000.0 / 300; // the conversion scale from PPI to UI - info.m_ScaleY = -info.m_ScaleX; // Y axis is bottom to Top for components in libs + info.m_ScaleX = 1000.0 / aDpi_X; // the conversion scale from PPI to UI + info.m_ScaleY = -1000.0 / aDpi_Y; // Y axis is bottom to Top for components in libs info.CreateOutputFile(); break; case 1: info.m_Format = PCBNEW_KICAD_MOD; - info.m_ScaleX = 1e6 * 25.4 / 300; // the conversion scale from PPI to UI - info.m_ScaleY = info.m_ScaleX; // Y axis is top to bottom in modedit + info.m_ScaleX = 1e6 * 25.4 / aDpi_X; // the conversion scale from PPI to UI + info.m_ScaleY = 1e6 * 25.4 / aDpi_Y; // Y axis is top to bottom in modedit info.CreateOutputFile(); break; case 0: info.m_Format = PCBNEW_LEGACY_EMP; - info.m_ScaleX = 10000.0 / 300; // the conversion scale - info.m_ScaleY = info.m_ScaleX; // Y axis is top to bottom in modedit + info.m_ScaleX = 10000.0 / aDpi_X; // the conversion scale + info.m_ScaleY = 10000.0 / aDpi_Y; // Y axis is top to bottom in modedit info.CreateOutputFile(); break; From b436924380db1ca8a42ab01996f2136084487d0d Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Mar 2014 18:40:23 +0100 Subject: [PATCH 19/46] Warning removal, patches from Camille 019 --- include/class_layer_box_selector.h | 2 +- include/hotkeys_basic.h | 7 ++++--- include/richio.h | 2 +- include/wxPcbStruct.h | 4 ++-- pcbnew/exporters/idf.cpp | 4 ++-- pcbnew/exporters/vrml_board.cpp | 2 +- pcbnew/exporters/vrml_board.h | 2 +- pcbnew/router/pns_line_placer.cpp | 2 ++ pcbnew/router/pns_line_placer.h | 2 +- pcbnew/tools/bright_box.cpp | 2 ++ pcbnew/tools/bright_box.h | 2 +- 11 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/class_layer_box_selector.h b/include/class_layer_box_selector.h index 27d19b8a18..4a130c8654 100644 --- a/include/class_layer_box_selector.h +++ b/include/class_layer_box_selector.h @@ -5,7 +5,7 @@ #include // EDA_COLOR_T definition #include -class EDA_HOTKEY_CONFIG; +struct EDA_HOTKEY_CONFIG; /* Basic class to build a layer list. * this is an basic abstract class to build a layer list selector. diff --git a/include/hotkeys_basic.h b/include/hotkeys_basic.h index f070441de4..80ffc0ad28 100644 --- a/include/hotkeys_basic.h +++ b/include/hotkeys_basic.h @@ -143,10 +143,11 @@ wxString ReturnKeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ); */ int ReturnKeyCodeFromKeyName( const wxString& keyname ); -/* An helper enum for AddHotkeyName function - * In menus we can an a hot key, or an accelerator , or sometimes just a comment +/** + * An helper enum for AddHotkeyName function + * In menus we can add a hot key, or an accelerator , or sometimes just a comment * Hot keys can perform actions using the current mouse cursor position - * Accelerators performs the same action as the associated menu + * Accelerators perform the same action as the associated menu * A comment is used in tool tips for some tools (zoom ..) * to show the hot key that performs this action */ diff --git a/include/richio.h b/include/richio.h index 6440fda7b0..64c842fcb2 100644 --- a/include/richio.h +++ b/include/richio.h @@ -155,7 +155,7 @@ struct IO_ERROR // : std::exception /** - * Class PARSE_ERROR + * Struct PARSE_ERROR * contains a filename or source description, a problem input line, a line number, * a byte offset, and an error message which contains the the caller's report and his * call site information: CPP source file, function, and line number. diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 219c411523..f3a3367277 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -61,8 +61,8 @@ class BOARD_ITEM; class PCB_LAYER_BOX_SELECTOR; class NETLIST; class REPORTER; -class PARSE_ERROR; -class IO_ERROR; +struct PARSE_ERROR; +struct IO_ERROR; class FP_LIB_TABLE; /** diff --git a/pcbnew/exporters/idf.cpp b/pcbnew/exporters/idf.cpp index 21e4af1c9d..9ccf20eb22 100644 --- a/pcbnew/exporters/idf.cpp +++ b/pcbnew/exporters/idf.cpp @@ -568,8 +568,8 @@ bool IDF_BOARD::WriteDrills( void ) fprintf( layoutFile, ".DRILLED_HOLES\n" ); - std::list::iterator ds = drills.begin(); - std::list::iterator de = drills.end(); + std::list::iterator ds = drills.begin(); + std::list::iterator de = drills.end(); while( ds != de ) { diff --git a/pcbnew/exporters/vrml_board.cpp b/pcbnew/exporters/vrml_board.cpp index 4ef750278b..e8b13de36b 100644 --- a/pcbnew/exporters/vrml_board.cpp +++ b/pcbnew/exporters/vrml_board.cpp @@ -712,7 +712,7 @@ bool VRML_LAYER::Tesselate( VRML_LAYER* holes ) std::ostringstream ostr; ostr << "Tesselate():FAILED: " << holes->GetError(); error = ostr.str(); - return NULL; + return false; } if( Fault ) diff --git a/pcbnew/exporters/vrml_board.h b/pcbnew/exporters/vrml_board.h index aa7e935abe..9cb4a26f4f 100644 --- a/pcbnew/exporters/vrml_board.h +++ b/pcbnew/exporters/vrml_board.h @@ -58,7 +58,7 @@ #define M_PI4 ( M_PI / 4.0 ) #endif -struct GLUtesselator; +class GLUtesselator; struct VERTEX_3D { diff --git a/pcbnew/router/pns_line_placer.cpp b/pcbnew/router/pns_line_placer.cpp index a03183c45c..4b9b616f3e 100644 --- a/pcbnew/router/pns_line_placer.cpp +++ b/pcbnew/router/pns_line_placer.cpp @@ -31,6 +31,8 @@ using boost::optional; +const double PNS_LINE_PLACER::m_shoveLengthThreshold = 1.7; + PNS_LINE_PLACER::PNS_LINE_PLACER( PNS_NODE* aWorld ) { m_initial_direction = DIRECTION_45( DIRECTION_45::N ); diff --git a/pcbnew/router/pns_line_placer.h b/pcbnew/router/pns_line_placer.h index e4ab966e59..625e6451b2 100644 --- a/pcbnew/router/pns_line_placer.h +++ b/pcbnew/router/pns_line_placer.h @@ -111,7 +111,7 @@ public: PNS_NODE* GetCurrentNode() const; private: - static const double m_shoveLengthThreshold = 1.7; + static const double m_shoveLengthThreshold; bool handleViaPlacement( PNS_LINE& aHead ); diff --git a/pcbnew/tools/bright_box.cpp b/pcbnew/tools/bright_box.cpp index b0fd4aec81..ef76a91647 100644 --- a/pcbnew/tools/bright_box.cpp +++ b/pcbnew/tools/bright_box.cpp @@ -28,6 +28,8 @@ using namespace KIGFX; +const double BRIGHT_BOX::LineWidth = 100000.0; + BRIGHT_BOX::BRIGHT_BOX( BOARD_ITEM* aItem ) : EDA_ITEM( NOT_USED ), // this item is never added to a BOARD so it needs no type item( aItem ) diff --git a/pcbnew/tools/bright_box.h b/pcbnew/tools/bright_box.h index 14966db9ac..b963b0409c 100644 --- a/pcbnew/tools/bright_box.h +++ b/pcbnew/tools/bright_box.h @@ -54,7 +54,7 @@ public: private: static const int BrightBoxLayer = ITEM_GAL_LAYER( GP_OVERLAY ); static const KIGFX::COLOR4D BrightColor; - static const double LineWidth = 100000.0; + static const double LineWidth; BOARD_ITEM* item; }; From 89be32714b0bddccb7f279afcdafda299c2b24ab Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Tue, 18 Mar 2014 11:31:13 +0100 Subject: [PATCH 20/46] 3D viewer: fix 3D grid artifact ( bug 1293873 ) --- 3d-viewer/3d_draw.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index dffd7e17cc..21f2f86211 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -52,7 +52,8 @@ // Imported function: extern void CheckGLError(); -/* returns true if aLayer should be displayed, false otherwise +/* Helper function + * returns true if aLayer should be displayed, false otherwise */ static bool Is3DLayerEnabled( LAYER_NUM aLayer ); @@ -144,7 +145,8 @@ void EDA_3D_CANVAS::Redraw() -g_Parm_3D_Visu.m_BoardPos.y * g_Parm_3D_Visu.m_BiuTo3Dunits, 0.0F ); - + // draw all objects in lists + // transparent objects should be drawn after opaque objects glCallList( m_glLists[GL_ID_BOARD] ); glCallList( m_glLists[GL_ID_TECH_LAYERS] ); @@ -156,22 +158,24 @@ void EDA_3D_CANVAS::Redraw() glCallList( m_glLists[GL_ID_AUX_LAYERS] ); } - if( g_Parm_3D_Visu.GetFlag( FL_GRID ) && m_glLists[GL_ID_GRID] ) - glCallList( m_glLists[GL_ID_GRID] ); - if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) ) { if( ! m_glLists[GL_ID_3DSHAPES_SOLID] ) CreateDrawGL_List(); glCallList( m_glLists[GL_ID_3DSHAPES_SOLID] ); - - // This list must be drawn last, because it contains the - // transparent gl objects, which should be drawn after all - // non tyransparent objects - glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP] ); } + // Grid uses transparency: draw it after all objects + if( g_Parm_3D_Visu.GetFlag( FL_GRID ) && m_glLists[GL_ID_GRID] ) + glCallList( m_glLists[GL_ID_GRID] ); + + // This list must be drawn last, because it contains the + // transparent gl objects, which should be drawn after all + // non transparent objects + if( g_Parm_3D_Visu.GetFlag( FL_MODULE ) && m_glLists[GL_ID_3DSHAPES_TRANSP] ) + glCallList( m_glLists[GL_ID_3DSHAPES_TRANSP] ); + SwapBuffers(); } @@ -913,8 +917,8 @@ void EDA_3D_CANVAS::Draw3DGrid( double aGriSizeMM ) double zpos = 0.0; EDA_COLOR_T gridcolor = DARKGRAY; // Color of grid lines EDA_COLOR_T gridcolor_marker = LIGHTGRAY; // Color of grid lines every 5 lines - double scale = g_Parm_3D_Visu.m_BiuTo3Dunits; - double transparency = 0.4; + const double scale = g_Parm_3D_Visu.m_BiuTo3Dunits; + const double transparency = 0.3; glNormal3f( 0.0, 0.0, 1.0 ); From 152c97a34fa0d0093bd8b6170f0faa812a7902b0 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Tue, 18 Mar 2014 19:52:29 +0100 Subject: [PATCH 21/46] kicad-install.sh: fix bad url for legacy libraries. Add the same script hich does not need a bazaar account to download Kicad (using https instead of ssh to create branches) --- scripts/kicad-install-no_launchpad_account.sh | 327 ++++++++++++++++++ scripts/kicad-install.sh | 2 +- 2 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 scripts/kicad-install-no_launchpad_account.sh diff --git a/scripts/kicad-install-no_launchpad_account.sh b/scripts/kicad-install-no_launchpad_account.sh new file mode 100644 index 0000000000..3a0d2d0078 --- /dev/null +++ b/scripts/kicad-install-no_launchpad_account.sh @@ -0,0 +1,327 @@ +#!/bin/bash -e +# Install KiCad from source onto either: +# -> a Ubuntu/Debian/Mint or +# -> a Red Hat +# compatible linux system. +# +# The "install_prerequisites" step is the only "distro dependent" one. That step could be modified +# for other linux distros. +# +# There are 3 package groups in a KiCad install: +# 1) Compiled source code in the form of executable programs. +# 2) User manuals and other documentation typically as *.pdf files. +# 3) a) Schematic parts, b) layout footprints, and c) 3D models for footprints. +# +# To achieve 1) source is checked out from its repo and compiled by this script then executables +# are installed using CMake. +# To achieve 2) documentation is checked out from its repo and installed using CMake. +# TO achieve 3a) and 3c) they are checked out from their repos and installed using CMake. +# To achieve 3b) a global fp-lib-table is put into your home directory which points to +# http://github.com/KiCad. No actual footprints are installed locally, internet access is used +# during program operation to fetch footprints from github as if it was a remote drive in the cloud. +# If you want to install those same KiCad footprints locally, you may run a separate script +# named library-repos-install.sh found in this same directory. That script requires that "git" be on +# your system whereas this script does not. The footprints require some means to download them and +# bzr-git seems not up to the task. wget or curl would also work. + + +# Since bash is invoked with -e by the first line of this script, all the steps in this script +# must succeed otherwise bash will abort at the first non-zero error code. Therefore any script +# functions must be crafted to anticipate numerous conditions, such that no command fails unless it +# is a serious situation. + + +# Set where the 3 source trees will go, use a full path +WORKING_TREES=~/kicad_sources + +# CMake Options +OPTS="$OPTS -DCMAKE_BUILD_TYPE=Release" +OPTS="$OPTS -DBUILD_GITHUB_PLUGIN=ON" + +# Python scripting, uncomment to enable +#OPTS="$OPTS -DKICAD_SCRIPTING=ON -DKICAD_SCRIPTING_MODULES=ON -DKICAD_SCRIPTING_WXPYTHON=ON" + +#a connection to https://code.launchpad.net does not request a launchpad account +#but, obviously, you cannot commit anything +REPOS=https://code.launchpad.net +LEGACY_LIB_REPO=$REPOS/~dickelbeck/kicad/library-read-only +SRCS_REPO=$REPOS/~kicad-product-committers/kicad/product +DOCS_REPO=$REPOS/~kicad-developers/kicad/doc + + +usage() +{ + echo "" + echo " usage:" + echo "" + echo "./kicad-install.sh " + echo " where is one of:" + echo " --install-or-update (does full installation or update.)" + echo " --remove-sources (removes source trees for another attempt.)" + echo " --uninstall-libraries (removes KiCad supplied libraries.)" + echo " --uninstall-kicad (uninstalls all of KiCad but leaves source trees.)" + echo "" + echo "example:" + echo ' $ ./kicad-install.sh --install-or-update' +} + + +install_prerequisites() +{ + # Find a package manager, PM + PM=$( command -v yum || command -v apt-get ) + + # assume all these Debian, Mint, Ubuntu systems have same prerequisites + if [ "$(expr match "$PM" '.*\(apt-get\)')" == "apt-get" ]; then + #echo "debian compatible system" + sudo apt-get install \ + bzr \ + bzrtools \ + build-essential \ + cmake \ + cmake-curses-gui \ + debhelper \ + doxygen \ + grep \ + libbz2-dev \ + libcairo2-dev \ + libglew-dev \ + libssl-dev \ + libwxgtk2.8-dev \ + python-wxgtk2.8 + + # assume all yum systems have same prerequisites + elif [ "$(expr match "$PM" '.*\(yum\)')" == "yum" ]; then + #echo "red hat compatible system" + # Note: if you find this list not to be accurate, please submit a patch: + sudo yum groupinstall "Development Tools" + sudo yum install \ + bzr \ + bzrtools \ + bzip2-libs \ + bzip2-devel \ + cmake \ + cmake-gui \ + doxygen \ + cairo-devel \ + glew-devel \ + grep \ + openssl-devel \ + wxGTK-devel \ + wxPython + else + echo + echo "Incompatible System. Neither 'yum' nor 'apt-get' found. Not possible to continue." + echo + exit 1 + fi + + # ensure bzr name and email are set. No message since bzr prints an excellent diagnostic. + bzr whoami || exit 2 +} + + +rm_build_dir() +{ + local dir="$1" + + echo "removing directory $dir" + + if [ -e "$dir/install_manifest.txt" ]; then + # this file is often created as root, so remove as root + sudo rm "$dir/install_manifest.txt" 2> /dev/null + fi + + if [ -d "$dir" ]; then + rm -rf "$dir" + fi +} + + +cmake_uninstall() +{ + # assume caller set the CWD, and is only telling us about it in $1 + local dir="$1" + + cwd=`pwd` + if [ "$cwd" != "$dir" ]; then + echo "missing dir $dir" + elif [ ! -e install_manifest.txt ]; then + echo + echo "Missing file $dir/install_manifest.txt." + else + echo "uninstalling from $dir" + sudo make uninstall + sudo rm install_manifest.txt + fi +} + + +# Function set_env_var +# sets an environment variable globally. +set_env_var() +{ + local var=$1 + local val=$2 + + if [ -d /etc/profile.d ]; then + if [ ! -e /etc/profile.d/kicad.sh ] || ! grep "$var" /etc/profile.d/kicad.sh >> /dev/null; then + echo + echo "Adding environment variable $var to file /etc/profile.d/kicad.sh" + echo "Please logout and back in after this script completes for environment" + echo "variable to get set into environment." + sudo sh -c "echo export $var=$val >> /etc/profile.d/kicad.sh" + fi + + elif [ -e /etc/environment ]; then + if ! grep "$var" /etc/environment >> /dev/null; then + echo + echo "Adding environment variable $var to file /etc/environment" + echo "Please reboot after this script completes for environment variable to get set into environment." + sudo sh -c "echo $var=$val >> /etc/environment" + fi + fi +} + + +install_or_update() +{ + echo "step 1) installing pre-requisites" + install_prerequisites + + + echo "step 2) make $WORKING_TREES if it does not exist" + if [ ! -d "$WORKING_TREES" ]; then + sudo mkdir -p "$WORKING_TREES" + echo " mark $WORKING_TREES as owned by me" + sudo chown -R `whoami` "$WORKING_TREES" + fi + cd $WORKING_TREES + + + echo "step 3) checking out the source code from launchpad repo..." + if [ ! -d "$WORKING_TREES/kicad.bzr" ]; then + bzr checkout $SRCS_REPO kicad.bzr + echo " source repo to local working tree." + else + cd kicad.bzr + bzr up + echo " local source working tree updated." + cd ../ + fi + + if [ ! -d "$WORKING_TREES/kicad-lib.bzr" ]; then + bzr checkout $LEGACY_LIB_REPO kicad-lib.bzr + echo ' kicad-lib checked out.' + else + cd kicad-lib.bzr + bzr up + echo ' kicad-lib repo updated.' + cd ../ + fi + + echo "step 5) checking out the documentation from launchpad repo..." + if [ ! -d "$WORKING_TREES/kicad-doc.bzr" ]; then + bzr checkout $DOCS_REPO kicad-doc.bzr + echo " docs checked out." + else + cd kicad-doc.bzr + bzr up + echo " docs working tree updated." + cd ../ + fi + + + echo "step 6) compiling source code..." + cd kicad.bzr + if [ ! -d "build" ]; then + mkdir build && cd build + cmake $OPTS ../ + else + cd build + # Although a "make clean" is sometimes needed, more often than not it slows down the update + # more than it is worth. Do it manually if you need to in this directory. + # make clean + fi + make -j4 + echo " kicad compiled." + + + echo "step 7) installing KiCad program files..." + sudo make install + echo " kicad program files installed." + + + echo "step 8) installing libraries..." + cd ../../kicad-lib.bzr + rm_build_dir build + mkdir build && cd build + cmake ../ + sudo make install + echo " kicad-lib.bzr installed." + + + echo "step 9) as non-root, install user configuration files..." + # install ~/fp-lib-table + make install_github_fp-lib-table + echo " kicad user-configuration files installed." + + + echo "step 10) installing documentation..." + cd ../../kicad-doc.bzr + rm_build_dir build + mkdir build && cd build + cmake ../ + sudo make install + echo " kicad-doc.bzr installed." + + echo "step 11) check for environment variables..." + if [ -z "${KIGITHUB}" ]; then + set_env_var KIGITHUB https://github.com/KiCad + fi + + echo + echo 'All KiCad "--install-or-update" steps completed, you are up to date.' + echo +} + + +if [ $# -eq 1 -a "$1" == "--remove-sources" ]; then + echo "deleting $WORKING_TREES" + rm_build_dir "$WORKING_TREES/kicad.bzr/build" + rm_build_dir "$WORKING_TREES/kicad-lib.bzr/build" + rm_build_dir "$WORKING_TREES/kicad-doc.bzr/build" + rm -rf "$WORKING_TREES" + exit +fi + + +if [ $# -eq 1 -a "$1" == "--install-or-update" ]; then + install_or_update + exit +fi + + +if [ $# -eq 1 -a "$1" == "--uninstall-libraries" ]; then + cd "$WORKING_TREES/kicad-lib.bzr/build" + cmake_uninstall "$WORKING_TREES/kicad-lib.bzr/build" + exit +fi + + +if [ $# -eq 1 -a "$1" == "--uninstall-kicad" ]; then + cd "$WORKING_TREES/kicad.bzr/build" + cmake_uninstall "$WORKING_TREES/kicad.bzr/build" + + cd "$WORKING_TREES/kicad-lib.bzr/build" + cmake_uninstall "$WORKING_TREES/kicad-lib.bzr/build" + + # this may fail since "uninstall" support is a recent feature of this repo: + cd "$WORKING_TREES/kicad-doc.bzr/build" + cmake_uninstall "$WORKING_TREES/kicad-doc.bzr/build" + + exit +fi + + +usage diff --git a/scripts/kicad-install.sh b/scripts/kicad-install.sh index 5c6168f520..6dab247203 100755 --- a/scripts/kicad-install.sh +++ b/scripts/kicad-install.sh @@ -41,7 +41,7 @@ OPTS="$OPTS -DBUILD_GITHUB_PLUGIN=ON" # Python scripting, uncomment to enable #OPTS="$OPTS -DKICAD_SCRIPTING=ON -DKICAD_SCRIPTING_MODULES=ON -DKICAD_SCRIPTING_WXPYTHON=ON" -LIB_REPO=~kicad-product-committers/kicad/library +LIB_REPO=~dickelbeck/kicad/library-read-only usage() From 0f09c15f110629926751184249fcaf011e521d89 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Wed, 19 Mar 2014 21:06:09 +0100 Subject: [PATCH 22/46] Pad editor dialog: Better tests and error messages about issues in pad settings. Fis also an other hard to translate error messge. --- pcbnew/dialogs/dialog_pad_properties.cpp | 32 +++++++++++++----------- pcbnew/pcb_parser.cpp | 5 ++-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 509fd046d6..0703edd1ee 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -95,8 +95,8 @@ public: private: PCB_BASE_FRAME* m_parent; - D_PAD* m_currentPad; // pad currently being edited - D_PAD* m_dummyPad; // a working copy used to show changes + D_PAD* m_currentPad; // pad currently being edited + D_PAD* m_dummyPad; // a working copy used to show changes BOARD* m_board; D_PAD& m_padMaster; bool m_isFlipped; // true if the parent footprint (therefore pads) is flipped (mirrored) @@ -673,11 +673,11 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() } LAYER_MSK padlayers_mask = m_dummyPad->GetLayerMask(); - if( ( padlayers_mask == 0 ) && ( m_dummyPad->GetAttribute() != PAD_HOLE_NOT_PLATED ) ) - error_msgs.Add( _( "Error: pad has no layer and is not a mechanical pad" ) ); - padlayers_mask &= (LAYER_BACK | LAYER_FRONT); if( padlayers_mask == 0 ) + error_msgs.Add( _( "Error: pad has no layer" ) ); + + if( ( padlayers_mask & (LAYER_BACK | LAYER_FRONT) ) == 0 ) { if( m_dummyPad->GetDrillSize().x || m_dummyPad->GetDrillSize().y ) { @@ -715,20 +715,21 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() switch( m_dummyPad->GetAttribute() ) { - case PAD_STANDARD : // Pad through hole, a hole is expected + case PAD_HOLE_NOT_PLATED: // Not plated, but through hole, a hole is expected + case PAD_STANDARD : // Pad through hole, a hole is also expected if( m_dummyPad->GetDrillSize().x <= 0 ) - error_msgs.Add( _( "Incorrect value for pad drill (too small value)" ) ); + error_msgs.Add( _( "Error: Through hole pad: drill diameter set to 0" ) ); break; - case PAD_SMD: // SMD and Connector pads (One external copper layer only) + case PAD_CONN: // Connector pads are smd pads, just they do not have solder paste. + if( (padlayers_mask & SOLDERPASTE_LAYER_BACK) || + (padlayers_mask & SOLDERPASTE_LAYER_FRONT) ) + error_msgs.Add( _( "Error: Connector pads are not on the solder paste layer\n" + "Use SMD pads instead" ) ); + // Fall trough + case PAD_SMD: // SMD and Connector pads (One external copper layer only) if( (padlayers_mask & LAYER_BACK) && (padlayers_mask & LAYER_FRONT) ) - error_msgs.Add( _( "Error: only one copper layer allowed for this pad" ) ); - break; - - case PAD_CONN: // connectors can have pads on "All" Cu layers. - break; - - case PAD_HOLE_NOT_PLATED: // Not plated + error_msgs.Add( _( "Error: only one copper layer allowed for SMD or Connector pads" ) ); break; } @@ -738,6 +739,7 @@ bool DIALOG_PAD_PROPERTIES::padValuesOK() dlg.ListSet( error_msgs ); dlg.ShowModal(); } + return error_msgs.GetCount() == 0; } diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 8ca4bd4cdc..11b4035090 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -2426,8 +2426,9 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) NeedSYMBOLorNUMBER(); if( zone->GetNet()->GetNetname() != FromUTF8() ) { - wxString msg = _( "There is a zone that belongs to a not " - "existing net (" ) + FromUTF8() + _("), you should verify it." ); + wxString msg; + msg.Printf( _( "There is a zone that belongs to a not existing net" + "(%s), you should verify it." ), GetChars( FromUTF8() ) ); DisplayError( NULL, msg ); zone->SetNetCode( NETINFO_LIST::UNCONNECTED ); } From 898ed7445f200ddf73e4a1aec48d6a31b77a2ed0 Mon Sep 17 00:00:00 2001 From: "maciej." Date: Wed, 19 Mar 2014 21:07:49 +0100 Subject: [PATCH 23/46] GAL: fix zooming using mouse wheel with wxWidgets 3.0. --- common/gal/cairo/cairo_gal.cpp | 1 + common/gal/opengl/opengl_gal.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 5f180d7338..4b3d0bf6ff 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -67,6 +67,7 @@ CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); + Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); #if defined _WIN32 || defined _WIN64 Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) ); #endif diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 0884ed2345..8e603d27fb 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -80,6 +80,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); + Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); #if defined _WIN32 || defined _WIN64 Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); #endif From 2c67c3ff803b0f19e942b6c5024cbb86bbd4b79c Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Wed, 19 Mar 2014 19:42:08 -0500 Subject: [PATCH 24/46] * 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. --- 3d-viewer/3d_draw.cpp | 4 +- 3d-viewer/3d_frame.cpp | 155 ++- 3d-viewer/3d_read_mesh.cpp | 2 +- 3d-viewer/3d_viewer.h | 20 +- CMakeLists.txt | 54 +- CMakeModules/download_boost.cmake | 12 +- CMakeModules/download_cairo.cmake | 13 +- CMakeModules/download_glew.cmake | 6 +- CMakeModules/download_pixman.cmake | 6 +- CMakeModules/download_pkgconfig.cmake | 4 +- CMakeModules/download_wxwidgets.cmake | 10 +- Documentation/KIWAY_Build_Symbols_Defined.txt | 29 + TODO.txt | 12 +- bitmap2component/CMakeLists.txt | 83 +- bitmap2component/bitmap2cmp_gui.cpp | 282 ++-- bitmap2component/bitmap2cmp_gui_base.cpp | 4 +- bitmap2component/bitmap2cmp_gui_base.fbp | 4 +- bitmap2component/bitmap2cmp_gui_base.h | 7 +- common/CMakeLists.txt | 67 +- common/base_units.cpp | 14 +- common/basicframe.cpp | 227 ++-- common/bin_mod.cpp | 52 + common/block_commande.cpp | 2 +- common/colors.cpp | 156 +++ common/common.cpp | 42 - common/common_plotPDF_functions.cpp | 2 +- common/common_plotPS_functions.cpp | 162 +-- .../{projet_config.cpp => config_params.cpp} | 369 ++--- common/copy_to_clipboard.cpp | 2 +- common/dialog_about/AboutDialog_main.cpp | 8 +- common/dialog_shim.cpp | 14 +- common/dialogs/dialog_get_component.cpp | 2 +- common/dialogs/dialog_hotkeys_editor.cpp | 6 +- common/dialogs/dialog_page_settings.cpp | 2 +- common/displlst.cpp | 2 +- common/{drawframe.cpp => draw_frame.cpp} | 44 +- common/{drawpanel.cpp => draw_panel.cpp} | 45 +- common/drawtxt.cpp | 4 +- common/eda_dde.cpp | 2 +- common/eda_doc.cpp | 17 +- common/eda_text.cpp | 2 +- common/edaappl.cpp | 1197 ----------------- common/footprint_info.cpp | 2 +- common/fp_lib_table.cpp | 122 +- common/gestfich.cpp | 75 +- common/gr_basic.cpp | 107 -- common/hotkey_grid_table.cpp | 2 +- common/hotkeys_basic.cpp | 89 +- common/kiface_i.cpp | 206 +++ common/kiway.cpp | 4 +- common/kiway_holder.cpp | 29 + common/page_layout/class_worksheet_layout.cpp | 45 +- common/pgm_base.cpp | 742 ++++++++++ common/project.cpp | 302 +++++ common/search_stack.cpp | 196 +++ common/single_top.cpp | 382 ++++-- common/systemdirsappend.cpp | 129 ++ common/worksheet.cpp | 6 +- common/wxwineda.cpp | 18 +- common/zoom.cpp | 2 +- cvpcb/CMakeLists.txt | 262 ++-- cvpcb/autosel.cpp | 10 +- cvpcb/cfg.cpp | 78 +- cvpcb/class_DisplayFootprintsFrame.cpp | 22 +- cvpcb/class_DisplayFootprintsFrame.h | 5 +- cvpcb/class_footprints_listbox.cpp | 2 +- cvpcb/cvframe.cpp | 181 ++- cvpcb/cvpcb.cpp | 171 ++- cvpcb/cvpcb_mainframe.h | 44 +- cvpcb/dialogs/dialog_cvpcb_config.cpp | 50 +- cvpcb/dialogs/dialog_cvpcb_config.h | 5 +- cvpcb/menubar.cpp | 13 +- cvpcb/readwrite_dlgs.cpp | 55 +- cvpcb/tool_cvpcb.cpp | 4 +- eeschema/CMakeLists.txt | 95 +- eeschema/backanno.cpp | 6 +- eeschema/block.cpp | 4 +- eeschema/block_libedit.cpp | 2 +- eeschema/class_libentry.cpp | 4 +- eeschema/class_libentry.h | 4 +- eeschema/class_netlist_object.cpp | 2 +- eeschema/class_netlist_object.h | 4 +- eeschema/component_references_lister.cpp | 4 +- eeschema/cross-probing.cpp | 44 +- eeschema/database.cpp | 16 +- eeschema/dialogs/dialog_annotate.cpp | 19 +- eeschema/dialogs/dialog_bom.cpp | 46 +- eeschema/dialogs/dialog_color_config.cpp | 2 +- .../dialogs/dialog_edit_component_in_lib.cpp | 31 +- .../dialog_edit_component_in_schematic.cpp | 10 +- eeschema/dialogs/dialog_edit_label.cpp | 4 +- .../dialog_edit_libentry_fields_in_lib.cpp | 10 +- eeschema/dialogs/dialog_edit_one_field.cpp | 4 +- eeschema/dialogs/dialog_eeschema_config.cpp | 169 ++- eeschema/dialogs/dialog_eeschema_config.h | 42 - .../dialogs/dialog_eeschema_config_fbp.cpp | 4 +- .../dialogs/dialog_eeschema_config_fbp.fbp | 4 +- eeschema/dialogs/dialog_eeschema_config_fbp.h | 7 +- eeschema/dialogs/dialog_erc.cpp | 4 +- eeschema/dialogs/dialog_lib_edit_pin.cpp | 6 +- eeschema/dialogs/dialog_lib_edit_text.cpp | 6 +- eeschema/dialogs/dialog_netlist.cpp | 27 +- eeschema/dialogs/dialog_plot_schematic.cpp | 7 +- eeschema/dialogs/dialog_plot_schematic.h | 10 +- .../dialogs/dialog_print_using_printer.cpp | 2 +- eeschema/eelibs_read_libraryfiles.cpp | 45 +- eeschema/eeschema.cpp | 195 ++- eeschema/eeschema_config.cpp | 242 ++-- eeschema/eeschema_config.h | 2 +- eeschema/files-io.cpp | 72 +- eeschema/find.cpp | 2 +- eeschema/getpart.cpp | 7 +- eeschema/invoke_sch_dialog.h | 1 + eeschema/lib_arc.cpp | 2 +- eeschema/lib_bezier.cpp | 2 +- eeschema/lib_circle.cpp | 4 +- eeschema/lib_field.cpp | 8 +- eeschema/lib_pin.cpp | 30 +- eeschema/lib_pin.h | 16 +- eeschema/lib_polyline.cpp | 2 +- eeschema/lib_rectangle.cpp | 2 +- eeschema/lib_text.cpp | 2 +- eeschema/libedit.cpp | 15 +- eeschema/libedit_plot_component.cpp | 2 +- eeschema/libeditframe.cpp | 64 +- eeschema/libeditframe.h | 36 +- eeschema/menubar.cpp | 13 +- eeschema/menubar_libedit.cpp | 4 +- eeschema/netform.cpp | 47 +- eeschema/operations_on_items_lists.cpp | 2 +- eeschema/pinedit.cpp | 21 +- eeschema/plot_schematic_HPGL.cpp | 2 +- eeschema/plot_schematic_SVG.cpp | 6 +- eeschema/sch_base_frame.cpp | 17 +- eeschema/sch_component.cpp | 2 +- eeschema/sch_field.cpp | 8 +- eeschema/sch_screen.cpp | 2 +- eeschema/sch_sheet.cpp | 4 +- eeschema/sch_text.cpp | 2 +- eeschema/schedit.cpp | 8 +- eeschema/schframe.cpp | 62 +- eeschema/selpart.cpp | 2 +- eeschema/sheet.cpp | 8 +- eeschema/sheetlab.cpp | 8 +- eeschema/symbdraw.cpp | 4 +- eeschema/symbedit.cpp | 29 +- eeschema/viewlib_frame.cpp | 45 +- eeschema/viewlib_frame.h | 27 +- eeschema/viewlibs.cpp | 10 +- gerbview/CMakeLists.txt | 175 ++- gerbview/block.cpp | 2 +- gerbview/class_DCodeSelectionbox.cpp | 2 +- gerbview/class_GERBER.cpp | 2 +- gerbview/class_GERBER.h | 6 +- gerbview/class_excellon.h | 4 +- .../dialogs/dialog_print_using_printer.cpp | 7 +- gerbview/events_called_functions.cpp | 4 +- gerbview/excellon_read_drill_file.cpp | 2 +- gerbview/gerbview.cpp | 151 ++- gerbview/gerbview_config.cpp | 2 +- gerbview/gerbview_frame.cpp | 89 +- gerbview/gerbview_frame.h | 39 +- gerbview/menubar.cpp | 17 +- gerbview/readgerb.cpp | 4 +- gerbview/rs274d.cpp | 6 +- gerbview/select_layers_to_pcb.cpp | 7 +- include/appl_wxstruct.h | 450 ------- include/base_units.h | 14 +- include/bin_mod.h | 64 + include/class_board_design_settings.h | 2 +- include/colors.h | 6 +- include/common.h | 10 + include/{param_config.h => config_params.h} | 102 +- include/dialog_hotkeys_editor.h | 2 +- include/dialog_shim.h | 6 +- include/draw_frame.h | 652 +++++++++ include/drawtxt.h | 6 +- include/fp_lib_table.h | 57 +- include/gestfich.h | 4 +- include/hotkey_grid_table.h | 2 +- include/hotkeys_basic.h | 12 +- include/import_export.h | 10 +- include/kiface_i.h | 141 ++ include/kiway.h | 159 ++- include/kiway_player.h | 160 +++ include/layers_id_colors_and_visibility.h | 2 +- include/pgm_base.h | 270 ++++ include/project.h | 255 ++++ include/sch_base_frame.h | 4 +- include/search_stack.h | 118 ++ include/wxBasePcbFrame.h | 64 +- include/wxEeschemaStruct.h | 36 +- include/wxPcbStruct.h | 81 +- include/wxstruct.h | 673 +-------- kicad/CMakeLists.txt | 12 +- kicad/class_treeproject_item.cpp | 8 +- kicad/files-io.cpp | 7 +- kicad/kicad.cpp | 327 ++++- kicad/kicad.h | 41 +- kicad/mainframe.cpp | 84 +- kicad/menubar.cpp | 14 +- kicad/pgm_kicad.h | 74 + kicad/preferences.cpp | 18 +- kicad/prjconfig.cpp | 50 +- kicad/tree_project_frame.cpp | 4 +- new/toolchain-mingw32.cmake | 15 +- pagelayout_editor/CMakeLists.txt | 184 ++- pagelayout_editor/events_functions.cpp | 2 +- pagelayout_editor/menubar.cpp | 16 +- pagelayout_editor/pl_editor.cpp | 115 +- pagelayout_editor/pl_editor_config.cpp | 2 +- pagelayout_editor/pl_editor_frame.cpp | 67 +- pagelayout_editor/pl_editor_frame.h | 92 +- pcb_calculator/CMakeLists.txt | 144 +- pcb_calculator/attenuators.cpp | 8 +- .../attenuators/attenuator_classes.cpp | 4 +- .../attenuators/attenuator_classes.h | 4 +- pcb_calculator/datafile_read_write.cpp | 4 +- .../dialogs/pcb_calculator_frame_base.cpp | 4 +- .../dialogs/pcb_calculator_frame_base.fbp | 22 +- .../dialogs/pcb_calculator_frame_base.h | 6 +- pcb_calculator/electrical_spacing_values.cpp | 4 +- pcb_calculator/params_read_write.cpp | 2 +- pcb_calculator/pcb_calculator.cpp | 91 +- pcb_calculator/pcb_calculator.h | 16 +- pcb_calculator/pcb_calculator_frame.cpp | 8 +- pcb_calculator/regulators_funct.cpp | 20 +- .../tracks_width_versus_current.cpp | 10 +- pcb_calculator/transline_dlg_funct.cpp | 4 +- pcb_calculator/transline_ident.cpp | 8 +- pcb_calculator/transline_ident.h | 8 +- pcbnew/CMakeLists.txt | 252 ++-- pcbnew/autorouter/graphpcb.cpp | 4 +- pcbnew/autorouter/queue.cpp | 2 +- pcbnew/autorouter/solve.cpp | 2 +- pcbnew/autorouter/work.cpp | 2 +- pcbnew/basepcbframe.cpp | 84 +- pcbnew/block.cpp | 2 +- pcbnew/block_module_editor.cpp | 6 +- ...board_items_to_polygon_shape_transform.cpp | 8 +- pcbnew/class_board.cpp | 2 +- pcbnew/class_board.h | 4 +- pcbnew/class_module.cpp | 8 +- pcbnew/class_module.h | 4 +- pcbnew/class_pad.cpp | 10 +- pcbnew/class_pad.h | 8 +- pcbnew/class_pad_draw_functions.cpp | 4 +- pcbnew/class_pcb_layer_widget.cpp | 2 +- pcbnew/class_track.cpp | 14 +- pcbnew/class_track.h | 4 +- pcbnew/clean.cpp | 8 +- pcbnew/connect.cpp | 2 +- pcbnew/cross-probing.cpp | 2 +- pcbnew/dialogs/dialog_SVG_print.cpp | 11 +- pcbnew/dialogs/dialog_SVG_print.h | 2 +- pcbnew/dialogs/dialog_copper_zones.cpp | 23 +- pcbnew/dialogs/dialog_design_rules.cpp | 68 +- pcbnew/dialogs/dialog_drc.cpp | 6 +- .../dialog_edit_module_for_BoardEditor.cpp | 49 +- .../dialog_edit_module_for_Modedit.cpp | 36 +- pcbnew/dialogs/dialog_edit_module_text.cpp | 10 +- pcbnew/dialogs/dialog_export_idf.cpp | 6 +- pcbnew/dialogs/dialog_export_vrml.cpp | 7 +- pcbnew/dialogs/dialog_fp_lib_table.cpp | 3 +- pcbnew/dialogs/dialog_freeroute_exchange.cpp | 12 +- pcbnew/dialogs/dialog_gendrill.cpp | 5 +- pcbnew/dialogs/dialog_gendrill.h | 8 +- .../dialog_global_edit_tracks_and_vias.cpp | 20 +- .../dialog_global_modules_fields_edition.cpp | 12 +- .../dialog_graphic_item_properties.cpp | 12 +- ...og_graphic_item_properties_for_Modedit.cpp | 12 +- .../dialogs/dialog_graphic_items_options.cpp | 20 +- .../dialog_keepout_area_properties.cpp | 7 +- pcbnew/dialogs/dialog_mask_clearance.cpp | 6 +- pcbnew/dialogs/dialog_netlist.cpp | 11 +- pcbnew/dialogs/dialog_netlist.h | 2 +- pcbnew/dialogs/dialog_pad_properties.cpp | 32 +- pcbnew/dialogs/dialog_pcb_text_properties.cpp | 10 +- pcbnew/dialogs/dialog_plot.cpp | 31 +- pcbnew/dialogs/dialog_plot.h | 2 +- pcbnew/dialogs/dialog_print_for_modedit.cpp | 7 +- pcbnew/dialogs/dialog_print_using_printer.cpp | 13 +- pcbnew/dialogs/dialog_set_grid.cpp | 4 +- pcbnew/dimension.cpp | 10 +- pcbnew/drc.cpp | 2 +- pcbnew/drc_clearance_test_functions.cpp | 6 +- pcbnew/edgemod.cpp | 4 +- pcbnew/edit.cpp | 51 +- pcbnew/editmod.cpp | 17 +- pcbnew/exporters/export_d356.cpp | 32 +- pcbnew/exporters/export_gencad.cpp | 8 +- pcbnew/exporters/export_vrml.cpp | 6 +- pcbnew/exporters/gen_modules_placefile.cpp | 6 +- pcbnew/exporters/gendrill_Excellon_writer.cpp | 9 +- pcbnew/exporters/idf.cpp | 3 +- pcbnew/files.cpp | 298 ++-- pcbnew/footprint_wizard_frame.cpp | 38 +- pcbnew/footprint_wizard_frame.h | 25 +- pcbnew/import_dxf/dialog_dxf_import.cpp | 9 +- pcbnew/initpcb.cpp | 12 +- pcbnew/kicad_plugin.cpp | 4 +- pcbnew/librairi.cpp | 51 +- pcbnew/loadcmp.cpp | 18 +- pcbnew/menubar_pcbframe.cpp | 16 +- pcbnew/modedit.cpp | 61 +- pcbnew/module_editor_frame.h | 19 +- pcbnew/moduleframe.cpp | 35 +- pcbnew/modview_frame.cpp | 63 +- pcbnew/modview_frame.h | 32 +- pcbnew/muonde.cpp | 12 +- pcbnew/netlist.cpp | 4 +- pcbnew/onleftclick.cpp | 5 +- pcbnew/onrightclick.cpp | 6 +- pcbnew/pcb_painter.cpp | 2 +- pcbnew/pcbframe.cpp | 143 +- pcbnew/pcbnew.cpp | 517 ++++--- pcbnew/pcbnew_config.cpp | 67 +- pcbnew/pcbnew_config.h | 2 +- pcbnew/plot_brditems_plotter.cpp | 2 +- pcbnew/printout_controler.cpp | 2 +- pcbnew/printout_controler.h | 3 +- pcbnew/specctra_export.cpp | 2 +- pcbnew/swap_layers.cpp | 2 +- pcbnew/target_edit.cpp | 8 +- pcbnew/toolbars_update_user_interface.cpp | 2 +- pcbnew/tools/selection_tool.cpp | 2 +- pcbnew/xchgmod.cpp | 2 +- pcbnew/zones_by_polygon.cpp | 15 +- pcbnew/zones_by_polygon_fill_functions.cpp | 2 +- ...ones_convert_to_polygons_aux_functions.cpp | 4 +- pcbnew/zones_functions_for_undo_redo.cpp | 2 +- pcbnew/zones_non_copper_type_functions.cpp | 16 +- pcbnew/zones_polygons_test_connections.cpp | 2 +- tools/CMakeLists.txt | 54 - tools/kiface_test.cpp | 60 - 335 files changed, 9281 insertions(+), 6943 deletions(-) create mode 100644 Documentation/KIWAY_Build_Symbols_Defined.txt create mode 100644 common/bin_mod.cpp create mode 100644 common/colors.cpp rename common/{projet_config.cpp => config_params.cpp} (62%) rename common/{drawframe.cpp => draw_frame.cpp} (96%) rename common/{drawpanel.cpp => draw_panel.cpp} (97%) delete mode 100644 common/edaappl.cpp create mode 100644 common/kiface_i.cpp create mode 100644 common/kiway_holder.cpp create mode 100644 common/pgm_base.cpp create mode 100644 common/project.cpp create mode 100644 common/search_stack.cpp create mode 100644 common/systemdirsappend.cpp delete mode 100644 eeschema/dialogs/dialog_eeschema_config.h delete mode 100644 include/appl_wxstruct.h create mode 100644 include/bin_mod.h rename include/{param_config.h => config_params.h} (69%) create mode 100644 include/draw_frame.h create mode 100644 include/kiface_i.h create mode 100644 include/kiway_player.h create mode 100644 include/pgm_base.h create mode 100644 include/project.h create mode 100644 include/search_stack.h create mode 100644 kicad/pgm_kicad.h delete mode 100644 tools/kiface_test.cpp diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index d721f0a8b4..3aa20977d5 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -77,7 +77,7 @@ static void BuildPadShapeThickOutlineAsPolygon( D_PAD* aPad, { if( aPad->GetShape() == PAD_CIRCLE ) // Draw a ring { - TransformRingToPolygon( aCornerBuffer, aPad->ReturnShapePos(), + TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(), aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth ); return; } @@ -809,7 +809,7 @@ void EDA_3D_CANVAS::Draw3DViaHole( SEGVIA* aVia ) int inner_radius = aVia->GetDrillValue() / 2; int thickness = g_Parm_3D_Visu.GetCopperThicknessBIU(); - aVia->ReturnLayerPair( &top_layer, &bottom_layer ); + aVia->LayerPair( &top_layer, &bottom_layer ); // Drawing via hole: if( g_Parm_3D_Visu.IsRealisticMode() ) diff --git a/3d-viewer/3d_frame.cpp b/3d-viewer/3d_frame.cpp index 1b0561bb16..c8e957df01 100644 --- a/3d-viewer/3d_frame.cpp +++ b/3d-viewer/3d_frame.cpp @@ -26,7 +26,8 @@ */ #include -#include +#include +#include #include <3d_viewer.h> #include <3d_canvas.h> @@ -38,23 +39,23 @@ #include INFO3D_VISU g_Parm_3D_Visu; - // Key to store 3D Viewer config: -static const wxString keyBgColor_Red( wxT( "BgColor_Red" ) ); -static const wxString keyBgColor_Green( wxT( "BgColor_Green" ) ); -static const wxString keyBgColor_Blue( wxT( "BgColor_Blue" ) ); -static const wxString keyShowRealisticMode( wxT( "ShowRealisticMode" ) ); -static const wxString keyShowAxis( wxT( "ShowAxis" ) ); -static const wxString keyShowZones( wxT( "ShowZones" ) ); -static const wxString keyShowFootprints( wxT( "ShowFootprints" ) ); -static const wxString keyShowCopperThickness( wxT( "ShowCopperThickness" ) ); -static const wxString keyShowAdhesiveLayers( wxT( "ShowAdhesiveLayers" ) ); -static const wxString keyShowSilkScreenLayers( wxT( "ShowSilkScreenLayers" ) ); -static const wxString keyShowSolderMaskLayers( wxT( "ShowSolderMasLayers" ) ); -static const wxString keyShowSolderPasteLayers( wxT( "ShowSolderPasteLayers" ) ); -static const wxString keyShowCommentsLayer( wxT( "ShowCommentsLayers" ) ); -static const wxString keyShowBoardBody( wxT( "ShowBoardBody" ) ); -static const wxString keyShowEcoLayers( wxT( "ShowEcoLayers" ) ); +static const wxChar keyBgColor_Red[] = wxT( "BgColor_Red" ); +static const wxChar keyBgColor_Green[] = wxT( "BgColor_Green" ); +static const wxChar keyBgColor_Blue[] = wxT( "BgColor_Blue" ); +static const wxChar keyShowRealisticMode[] = wxT( "ShowRealisticMode" ); +static const wxChar keyShowAxis[] = wxT( "ShowAxis" ); +static const wxChar keyShowZones[] = wxT( "ShowZones" ); +static const wxChar keyShowFootprints[] = wxT( "ShowFootprints" ); +static const wxChar keyShowCopperThickness[] = wxT( "ShowCopperThickness" ); +static const wxChar keyShowAdhesiveLayers[] = wxT( "ShowAdhesiveLayers" ); +static const wxChar keyShowSilkScreenLayers[] = wxT( "ShowSilkScreenLayers" ); +static const wxChar keyShowSolderMaskLayers[] = wxT( "ShowSolderMasLayers" ); +static const wxChar keyShowSolderPasteLayers[] =wxT( "ShowSolderPasteLayers" ); +static const wxChar keyShowCommentsLayer[] = wxT( "ShowCommentsLayers" ); +static const wxChar keyShowBoardBody[] = wxT( "ShowBoardBody" ); +static const wxChar keyShowEcoLayers[] = wxT( "ShowEcoLayers" ); + BEGIN_EVENT_TABLE( EDA_3D_FRAME, EDA_BASE_FRAME ) EVT_ACTIVATE( EDA_3D_FRAME::OnActivate ) @@ -72,11 +73,13 @@ EVT_MENU_RANGE( ID_MENU3D_GRID, ID_MENU3D_GRID_END, EVT_CLOSE( EDA_3D_FRAME::OnCloseWindow ) -END_EVENT_TABLE() EDA_3D_FRAME::EDA_3D_FRAME( PCB_BASE_FRAME* parent, - const wxString& title, - long style ) : - EDA_BASE_FRAME( parent, DISPLAY3D_FRAME_TYPE, title, - wxDefaultPosition, wxDefaultSize, style, wxT( "Frame3D" ) ) +END_EVENT_TABLE() + + +EDA_3D_FRAME::EDA_3D_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent, + const wxString& aTitle, long style ) : + KIWAY_PLAYER( aKiway, aParent, DISPLAY3D_FRAME_TYPE, aTitle, + wxDefaultPosition, wxDefaultSize, style, wxT( "Frame3D" ) ) { m_canvas = NULL; m_reloadRequest = false; @@ -87,7 +90,7 @@ END_EVENT_TABLE() EDA_3D_FRAME::EDA_3D_FRAME( PCB_BASE_FRAME* parent, icon.CopyFromBitmap( KiBitmap( icon_3d_xpm ) ); SetIcon( icon ); - GetSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); // Create the status line @@ -139,84 +142,76 @@ void EDA_3D_FRAME::OnCloseWindow( wxCloseEvent& Event ) } -void EDA_3D_FRAME::GetSettings() +void EDA_3D_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); // Current config used by application - class INFO3D_VISU& prms = g_Parm_3D_Visu; + EDA_BASE_FRAME::LoadSettings( aCfg ); - if( config ) - { - EDA_BASE_FRAME::LoadSettings(); + INFO3D_VISU& prms = g_Parm_3D_Visu; - config->Read( keyBgColor_Red, &g_Parm_3D_Visu.m_BgColor.m_Red, 0.0 ); - config->Read( keyBgColor_Green, &g_Parm_3D_Visu.m_BgColor.m_Green, 0.0 ); - config->Read( keyBgColor_Blue, &g_Parm_3D_Visu.m_BgColor.m_Blue, 0.0 ); + aCfg->Read( keyBgColor_Red, &g_Parm_3D_Visu.m_BgColor.m_Red, 0.0 ); + aCfg->Read( keyBgColor_Green, &g_Parm_3D_Visu.m_BgColor.m_Green, 0.0 ); + aCfg->Read( keyBgColor_Blue, &g_Parm_3D_Visu.m_BgColor.m_Blue, 0.0 ); - bool tmp; - config->Read( keyShowRealisticMode, &tmp, false ); - prms.SetFlag( FL_USE_REALISTIC_MODE, tmp ); + bool tmp; + aCfg->Read( keyShowRealisticMode, &tmp, false ); + prms.SetFlag( FL_USE_REALISTIC_MODE, tmp ); - config->Read( keyShowAxis, &tmp, true ); - prms.SetFlag( FL_AXIS, tmp ); + aCfg->Read( keyShowAxis, &tmp, true ); + prms.SetFlag( FL_AXIS, tmp ); - config->Read( keyShowFootprints, &tmp, true ); - prms.SetFlag( FL_MODULE, tmp ); + aCfg->Read( keyShowFootprints, &tmp, true ); + prms.SetFlag( FL_MODULE, tmp ); - config->Read( keyShowCopperThickness, &tmp, false ); - prms.SetFlag( FL_USE_COPPER_THICKNESS, tmp ); + aCfg->Read( keyShowCopperThickness, &tmp, false ); + prms.SetFlag( FL_USE_COPPER_THICKNESS, tmp ); - config->Read( keyShowZones, &tmp, true ); - prms.SetFlag( FL_ZONE, tmp ); + aCfg->Read( keyShowZones, &tmp, true ); + prms.SetFlag( FL_ZONE, tmp ); - config->Read( keyShowAdhesiveLayers, &tmp, true ); - prms.SetFlag( FL_ADHESIVE, tmp ); + aCfg->Read( keyShowAdhesiveLayers, &tmp, true ); + prms.SetFlag( FL_ADHESIVE, tmp ); - config->Read( keyShowSilkScreenLayers, &tmp, true ); - prms.SetFlag( FL_SILKSCREEN, tmp ); + aCfg->Read( keyShowSilkScreenLayers, &tmp, true ); + prms.SetFlag( FL_SILKSCREEN, tmp ); - config->Read( keyShowSolderMaskLayers, &tmp, true ); - prms.SetFlag( FL_SOLDERMASK, tmp ); + aCfg->Read( keyShowSolderMaskLayers, &tmp, true ); + prms.SetFlag( FL_SOLDERMASK, tmp ); - config->Read( keyShowSolderPasteLayers, &tmp, true ); - prms.SetFlag( FL_SOLDERPASTE, tmp ); + aCfg->Read( keyShowSolderPasteLayers, &tmp, true ); + prms.SetFlag( FL_SOLDERPASTE, tmp ); - config->Read( keyShowCommentsLayer, &tmp, true ); - prms.SetFlag( FL_COMMENTS, tmp ); + aCfg->Read( keyShowCommentsLayer, &tmp, true ); + prms.SetFlag( FL_COMMENTS, tmp ); - config->Read( keyShowEcoLayers, &tmp, true ); - prms.SetFlag( FL_ECO, tmp ); + aCfg->Read( keyShowEcoLayers, &tmp, true ); + prms.SetFlag( FL_ECO, tmp ); - config->Read( keyShowBoardBody, &tmp, true ); - prms.SetFlag( FL_SHOW_BOARD_BODY, tmp ); - } + aCfg->Read( keyShowBoardBody, &tmp, true ); + prms.SetFlag( FL_SHOW_BOARD_BODY, tmp ); } -void EDA_3D_FRAME::SaveSettings() +void EDA_3D_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); // Current config used by application + EDA_BASE_FRAME::SaveSettings( aCfg ); - if( !config ) - return; + INFO3D_VISU& prms = g_Parm_3D_Visu; - EDA_BASE_FRAME::SaveSettings(); - - config->Write( keyBgColor_Red, g_Parm_3D_Visu.m_BgColor.m_Red ); - config->Write( keyBgColor_Green, g_Parm_3D_Visu.m_BgColor.m_Green ); - config->Write( keyBgColor_Blue, g_Parm_3D_Visu.m_BgColor.m_Blue ); - class INFO3D_VISU& prms = g_Parm_3D_Visu; - config->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) ); - config->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) ); - config->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) ); - config->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) ); - config->Write( keyShowZones, prms.GetFlag( FL_ZONE ) ); - config->Write( keyShowAdhesiveLayers, prms.GetFlag( FL_ADHESIVE ) ); - config->Write( keyShowSilkScreenLayers, prms.GetFlag( FL_SILKSCREEN ) ); - config->Write( keyShowSolderMaskLayers, prms.GetFlag( FL_SOLDERMASK ) ); - config->Write( keyShowSolderPasteLayers, prms.GetFlag( FL_SOLDERPASTE ) ); - config->Write( keyShowCommentsLayer, prms.GetFlag( FL_COMMENTS ) ); - config->Write( keyShowEcoLayers, prms.GetFlag( FL_ECO ) ); - config->Write( keyShowBoardBody, prms.GetFlag( FL_SHOW_BOARD_BODY ) ); + aCfg->Write( keyBgColor_Red, g_Parm_3D_Visu.m_BgColor.m_Red ); + aCfg->Write( keyBgColor_Green, g_Parm_3D_Visu.m_BgColor.m_Green ); + aCfg->Write( keyBgColor_Blue, g_Parm_3D_Visu.m_BgColor.m_Blue ); + aCfg->Write( keyShowRealisticMode, prms.GetFlag( FL_USE_REALISTIC_MODE ) ); + aCfg->Write( keyShowAxis, prms.GetFlag( FL_AXIS ) ); + aCfg->Write( keyShowFootprints, prms.GetFlag( FL_MODULE ) ); + aCfg->Write( keyShowCopperThickness, prms.GetFlag( FL_USE_COPPER_THICKNESS ) ); + aCfg->Write( keyShowZones, prms.GetFlag( FL_ZONE ) ); + aCfg->Write( keyShowAdhesiveLayers, prms.GetFlag( FL_ADHESIVE ) ); + aCfg->Write( keyShowSilkScreenLayers, prms.GetFlag( FL_SILKSCREEN ) ); + aCfg->Write( keyShowSolderMaskLayers, prms.GetFlag( FL_SOLDERMASK ) ); + aCfg->Write( keyShowSolderPasteLayers, prms.GetFlag( FL_SOLDERPASTE ) ); + aCfg->Write( keyShowCommentsLayer, prms.GetFlag( FL_COMMENTS ) ); + aCfg->Write( keyShowEcoLayers, prms.GetFlag( FL_ECO ) ); + aCfg->Write( keyShowBoardBody, prms.GetFlag( FL_SHOW_BOARD_BODY ) ); } diff --git a/3d-viewer/3d_read_mesh.cpp b/3d-viewer/3d_read_mesh.cpp index 24046f9e9c..62a725a1ab 100644 --- a/3d-viewer/3d_read_mesh.cpp +++ b/3d-viewer/3d_read_mesh.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include <3d_viewer.h> #include diff --git a/3d-viewer/3d_viewer.h b/3d-viewer/3d_viewer.h index 24d76d6aa7..96036e1194 100644 --- a/3d-viewer/3d_viewer.h +++ b/3d-viewer/3d_viewer.h @@ -30,7 +30,7 @@ #ifndef __3D_VIEWER_H__ #define __3D_VIEWER_H__ -#include // for EDA_BASE_FRAME. +#include #if !wxUSE_GLCANVAS #error Please build wxWidgets with Opengl support (./configure --with-opengl) @@ -50,24 +50,29 @@ #include <3d_struct.h> +#define KISYS3DMOD "KISYS3DMOD" + class EDA_3D_CANVAS; class PCB_BASE_FRAME; -#define KICAD_DEFAULT_3D_DRAWFRAME_STYLE wxDEFAULT_FRAME_STYLE | wxWANTS_CHARS -#define LIB3D_PATH wxT( "packages3d" ) +#define KICAD_DEFAULT_3D_DRAWFRAME_STYLE (wxDEFAULT_FRAME_STYLE | wxWANTS_CHARS) +#define LIB3D_PATH wxT( "packages3d" ) -class EDA_3D_FRAME : public EDA_BASE_FRAME + +class EDA_3D_FRAME : public KIWAY_PLAYER { private: EDA_3D_CANVAS* m_canvas; bool m_reloadRequest; wxString m_defaultFileName; /// Filename to propose for screenshot + /// Tracks whether to use Orthographic or Perspective projection bool m_ortho; public: - EDA_3D_FRAME( PCB_BASE_FRAME* parent, const wxString& title, + EDA_3D_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent, const wxString& aTitle, long style = KICAD_DEFAULT_3D_DRAWFRAME_STYLE ); + ~EDA_3D_FRAME() { m_auimgr.UnInit(); @@ -118,8 +123,9 @@ private: // to the current display options void ReCreateMainToolbar(); void SetToolbars(); - void GetSettings(); - void SaveSettings(); + + void LoadSettings( wxConfigBase* aCfg ); // overload virtual + void SaveSettings( wxConfigBase* aCfg ); // overload virtual // Other functions void OnLeftClick( wxDC* DC, const wxPoint& MousePos ); diff --git a/CMakeLists.txt b/CMakeLists.txt index 012a06fff4..c5461823e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules ) # option( USE_KIWAY_DLLS - "Build the major modules as KIFACE DLLs or DSOs, will soon be the norm." OFF ) + "Build the major modules as KIFACE DLLs or DSOs, will soon be the norm." ON ) # The desire is to migrate designs *away from* case independence, and to create designs which use # literally (case specific) interpreted component names. But for backwards compatibility, @@ -110,6 +110,12 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) OUTPUT_VARIABLE GCC_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) + set( TO_LINKER -XLinker ) + else() + set( TO_LINKER -Wl ) + endif() + # Establish -Wall early, so specialized relaxations of this may come # subsequently on the command line, such as in pcbnew/github/CMakeLists.txt set( CMAKE_C_FLAGS "-Wall ${CMAKE_C_FLAGS}" ) @@ -177,12 +183,6 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PIC_FLAG}" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PIC_FLAG}" ) - if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) - set( TO_LINKER -XLinker ) - else() - set( TO_LINKER -Wl ) - endif() - # Thou shalt not link vaporware and tell us it's a valid DSO: set( CMAKE_SHARED_LINKER_FLAGS "${TO_LINKER},--no-undefined" ) set( CMAKE_MODULE_LINKER_FLAGS "${TO_LINKER},--no-undefined" ) @@ -206,11 +206,11 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) if( NOT CMAKE_CXX_COMPILER ) EXEC_PROGRAM( wx-config ARGS --cc OUTPUT_VARIABLE CMAKE_C_COMPILER ) - endif( NOT CMAKE_CXX_COMPILER ) + endif() if( NOT CMAKE_CXX_COMPILER ) EXEC_PROGRAM( wx-config ARGS --cxx OUTPUT_VARIABLE CMAKE_CXX_COMPILER ) - endif( NOT CMAKE_CXX_COMPILER ) + endif() endif() @@ -326,7 +326,7 @@ include( ExternalProject ) include( CheckFindPackageResult ) # Turn on wxWidgets compatibility mode for some classes -add_definitions(-DWX_COMPATIBILITY) +add_definitions( -DWX_COMPATIBILITY ) ####################### # Find OpenGL library # @@ -334,6 +334,11 @@ add_definitions(-DWX_COMPATIBILITY) find_package( OpenGL QUIET ) check_find_package_result( OPENGL_FOUND "OpenGL" ) +# Dick 5-Feb-2014: +# Marco: This is broken. You cannot use both ExternalProject_Add() add and find_package() +# in the same CMake tree and have them both reference the same package: +# http://stackoverflow.com/questions/6351609/cmake-linking-to-library-downloaded-from-externalproject-add +# https://www.mail-archive.com/cmake@cmake.org/msg47501.html if( KICAD_BUILD_STATIC OR KICAD_BUILD_DYNAMIC ) #set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so;.dylib;.dll") @@ -351,9 +356,16 @@ if( KICAD_BUILD_STATIC OR KICAD_BUILD_DYNAMIC ) # TODO - Library packaging/relocation endif() - add_custom_target( lib-dependencies - DEPENDS boost cairo glew libpng pixman pkgconfig - ) + if( MINGW ) + include( download_bzip2 ) + add_custom_target( lib-dependencies + DEPENDS boost cairo glew libpng pixman pkgconfig bzip2 + ) + else() + add_custom_target( lib-dependencies + DEPENDS boost cairo glew libpng pixman pkgconfig + ) + endif() include( download_libpng ) @@ -385,14 +397,18 @@ endif( KICAD_BUILD_STATIC OR KICAD_BUILD_DYNAMIC) ##################### # Find GLEW library # ##################### -find_package(GLEW) -check_find_package_result(GLEW_FOUND "GLEW") +if( NOT GLEW_FOUND ) + find_package( GLEW ) + check_find_package_result( GLEW_FOUND "GLEW" ) +endif() ###################### # Find Cairo library # ###################### -find_package(Cairo 1.8.1 QUIET) -check_find_package_result(CAIRO_FOUND "Cairo") +if( NOT CAIRO_FOUND ) + find_package( Cairo 1.8.1 QUIET ) + check_find_package_result( CAIRO_FOUND "Cairo" ) +endif() # Download boost and possibly build parts of it ################################################# @@ -428,8 +444,8 @@ else() endif() if( NOT (KICAD_BUILD_STATIC OR KICAD_BUILD_DYNAMIC) ) -check_find_package_result( wxWidgets_FOUND "wxWidgets" ) -endif( NOT (KICAD_BUILD_STATIC OR KICAD_BUILD_DYNAMIC) ) + check_find_package_result( wxWidgets_FOUND "wxWidgets" ) +endif() # Include wxWidgets macros. include( ${wxWidgets_USE_FILE} ) diff --git a/CMakeModules/download_boost.cmake b/CMakeModules/download_boost.cmake index 9230b334e2..e929a2aae5 100644 --- a/CMakeModules/download_boost.cmake +++ b/CMakeModules/download_boost.cmake @@ -59,7 +59,9 @@ set( BOOST_LIBS_BUILT ) #-------------------------------------------------------------------- -find_package( BZip2 REQUIRED ) +if( NOT BZIP2_FOUND ) + find_package( BZip2 REQUIRED ) +endif() string( REGEX REPLACE "\\." "_" BOOST_VERS "${BOOST_RELEASE}" ) set( PREFIX ${DOWNLOAD_DIR}/boost_${BOOST_VERS} ) @@ -99,7 +101,7 @@ else() endif() -if( MINGW ) +if( MINGW AND NOT CMAKE_HOST_UNIX ) # building for MINGW on windows not UNIX if( MSYS ) # The Boost system does not build properly on MSYS using bootstrap.sh. Running # bootstrap.bat with cmd.exe does. It's ugly but it works. At least for Boost @@ -113,14 +115,16 @@ if( MINGW ) set( b2_libs ${b2_libs} --with-${lib} ) endforeach() unset( BOOST_CFLAGS ) + else() string( REGEX REPLACE "\\;" "," libs_csv "${boost_libs_list}" ) #message( STATUS "libs_csv:${libs_csv}" ) set( bootstrap ./bootstrap.sh --with-libraries=${libs_csv} ) # pass to *both* C and C++ compilers - set( BOOST_CFLAGS "cflags=${PIC_FLAG}" ) - set( BOOST_INCLUDE "${BOOST_ROOT}/include" ) + set( BOOST_CFLAGS "cflags=${PIC_FLAG}" ) + set( BOOST_CXXFLAGS "cxxflags=${PIC_FLAG}" ) + set( BOOST_INCLUDE "${BOOST_ROOT}/include" ) unset( b2_libs ) endif() diff --git a/CMakeModules/download_cairo.cmake b/CMakeModules/download_cairo.cmake index 51d136750b..26ab53e3e9 100644 --- a/CMakeModules/download_cairo.cmake +++ b/CMakeModules/download_cairo.cmake @@ -33,7 +33,9 @@ set( CAIRO_ROOT "${PROJECT_SOURCE_DIR}/cairo_root" ) #-------------------------------------------------------------------- -find_package( BZip2 REQUIRED ) +if( NOT BZIP2_FOUND ) + find_package( BZip2 REQUIRED ) +endif() set( PREFIX ${DOWNLOAD_DIR}/cairo ) @@ -42,7 +44,7 @@ if ( KICAD_BUILD_STATIC ) endif( KICAD_BUILD_STATIC ) -if (APPLE) +if (APPLE) set( CAIRO_CFLAGS "CFLAGS=" ) set( CAIRO_LDFLAGS "LDFLAGS=-framework CoreServices -framework Cocoa" ) @@ -94,8 +96,13 @@ ExternalProject_Add( cairo #BINARY_DIR "${PREFIX}" - BUILD_COMMAND $(MAKE) + BUILD_COMMAND $(MAKE) INSTALL_DIR "${CAIRO_ROOT}" INSTALL_COMMAND $(MAKE) install ) + +# match these with whatever FindCairo.cmake sets +set( CAIRO_FOUND true ) +set( CAIRO_INCLUDE_DIR ${PREFIX}/include ) +set( CAIRO_CAIRO_LIBRARIES ${PREFIX}/lib ) diff --git a/CMakeModules/download_glew.cmake b/CMakeModules/download_glew.cmake index 74e28a98f3..1c7d690809 100644 --- a/CMakeModules/download_glew.cmake +++ b/CMakeModules/download_glew.cmake @@ -33,11 +33,13 @@ set( GLEW_ROOT "${PROJECT_SOURCE_DIR}/glew_root" ) #-------------------------------------------------------------------- -find_package( BZip2 REQUIRED ) +if( NOT BZIP2_FOUND ) + find_package( BZip2 REQUIRED ) +endif() set( PREFIX ${DOWNLOAD_DIR}/glew ) -if (APPLE) +if (APPLE) if( CMAKE_OSX_ARCHITECTURES ) set( GLEW_CFLAGS "CFLAGS.EXTRA=-arch ${CMAKE_OSX_ARCHITECTURES} -mmacosx-version-min=10.5" ) set( GLEW_LDFLAGS "LDFLAGS.EXTRA=-arch ${CMAKE_OSX_ARCHITECTURES} -mmacosx-version-min=10.5" ) diff --git a/CMakeModules/download_pixman.cmake b/CMakeModules/download_pixman.cmake index a925d1bf1a..cba41a13ca 100644 --- a/CMakeModules/download_pixman.cmake +++ b/CMakeModules/download_pixman.cmake @@ -33,13 +33,15 @@ set( PIXMAN_ROOT "${PROJECT_SOURCE_DIR}/pixman_root" ) #-------------------------------------------------------------------- -find_package( BZip2 REQUIRED ) +if( NOT BZIP2_FOUND ) + find_package( BZip2 REQUIRED ) +endif() set( PREFIX ${DOWNLOAD_DIR}/pixman ) set(PIXMAN_CPPFLAGS "CFLAGS=") -if (APPLE) +if (APPLE) if( CMAKE_OSX_ARCHITECTURES ) set(PIXMAN_CPPFLAGS "${PIXMAN_CPPFLAGS} -arch ${CMAKE_OSX_ARCHITECTURES} -fno-common -mmacosx-version-min=10.5") else() diff --git a/CMakeModules/download_pkgconfig.cmake b/CMakeModules/download_pkgconfig.cmake index 1960af317a..a0f6c530c1 100644 --- a/CMakeModules/download_pkgconfig.cmake +++ b/CMakeModules/download_pkgconfig.cmake @@ -33,7 +33,9 @@ set( PKGCONFIG_ROOT "${PROJECT_SOURCE_DIR}/pkgconfig_root" ) #-------------------------------------------------------------------- -find_package( BZip2 REQUIRED ) +if( NOT BZIP2_FOUND ) + find_package( BZip2 REQUIRED ) +endif() set( PREFIX ${DOWNLOAD_DIR}/pkgconfig ) diff --git a/CMakeModules/download_wxwidgets.cmake b/CMakeModules/download_wxwidgets.cmake index 693d490df3..ed7ebe879c 100644 --- a/CMakeModules/download_wxwidgets.cmake +++ b/CMakeModules/download_wxwidgets.cmake @@ -33,11 +33,13 @@ set( LIBWX_ROOT "${PROJECT_SOURCE_DIR}/libwx_root" ) #-------------------------------------------------------------------- -find_package( BZip2 REQUIRED ) +if( NOT BZIP2_FOUND ) + find_package( BZip2 REQUIRED ) +endif() set( PREFIX ${DOWNLOAD_DIR}/libwx ) -if (APPLE) +if (APPLE) if( CMAKE_OSX_ARCHITECTURES ) STRING(REGEX REPLACE " -arch " "," LIBWX_ARCHITECTURES ${CMAKE_OSX_ARCHITECTURES}) SET( LIBWX_ARCHITECTURES --enable-universal_binary=${LIBWX_ARCHITECTURES}) @@ -80,7 +82,7 @@ ExternalProject_Add( libwx #SET directories set(wxWidgets_BIN_DIR ${LIBWX_ROOT}/bin) set(wxWidgets_CONFIG_EXECUTABLE ${LIBWX_ROOT}/bin/wx-config) -set(wxWidgets_INCLUDE_DIRS ${LIBWX_ROOT}/include) +set(wxWidgets_INCLUDE_DIRS ${LIBWX_ROOT}/include) set(wxWidgets_LIBRARY_DIRS ${LIBWX_ROOT}/lib) @@ -110,7 +112,7 @@ ExternalProject_Add_Step( libwx bzr_init_libwx ###### ExternalProject_Add_Step( libwx libwx_recursive_message - COMMAND cmake . + COMMAND cmake . COMMENT "*** RERUN CMAKE - wxWidgets built, now reissue a cmake to build Kicad" DEPENDEES install ) diff --git a/Documentation/KIWAY_Build_Symbols_Defined.txt b/Documentation/KIWAY_Build_Symbols_Defined.txt new file mode 100644 index 0000000000..f10dea9b1c --- /dev/null +++ b/Documentation/KIWAY_Build_Symbols_Defined.txt @@ -0,0 +1,29 @@ + +KIWAY Build Symbols, Definitions and Intentions + + +COMPILING_DLL: + + This is a signal to import_export.h, and when present, toggles the + interpretation of the #defines in that file. Its purpose should not be + extended beyond this. + + +USE_KIWAY_DLLS: + + Comes from CMake as a user configuration variable, settable in the Cmake + user interface. It decides if KiCad will be built with the *.kiface program + modules. + + +BUILD_KIWAY_DLL: + + Comes from CMake, but at the 2nd tier, not the top tier. By 2nd tier, + something like pcbnew/CMakeLists.txt, not /CMakeLists.txt is meant. It is + not a user configuration variable. Instead, the 2nd tier CMakeLists.txt file + looks at the top level USE_KIWAY_DLLS and decides how the object files under + the 2nd tier's control will be built. If it decides it wants to march in + lockstep with USE_KIWAY_DLLS, then this local CMakeLists.txt file may pass a + defined BUILD_KIWAY_DLL (singular) on the compiler command line to the + pertinent set of compilation steps under its control. + diff --git a/TODO.txt b/TODO.txt index 0eeec9f0d9..690c07e01c 100644 --- a/TODO.txt +++ b/TODO.txt @@ -62,7 +62,11 @@ PCBNew Dick's Final TODO List: ====================== -*) Get licensing cleaned up. -*) DLL-ization of pcbnew & eeschema - http://www.eevblog.com/forum/open-source-kicad-geda/seriously-irritated-with-the-library-editor!/ - https://blueprints.launchpad.net/kicad/+spec/modular-kicad +*) Get licensing cleaned up. + +*) DLL-ization of pcbnew & eeschema + http://www.eevblog.com/forum/open-source-kicad-geda/seriously-irritated-with-the-library-editor!/ + https://blueprints.launchpad.net/kicad/+spec/modular-kicad + + Issues as a result of minimal testing: + Kicad project manager will crash when requesting help file. diff --git a/bitmap2component/CMakeLists.txt b/bitmap2component/CMakeLists.txt index 2c5c85eed9..0bd0921309 100644 --- a/bitmap2component/CMakeLists.txt +++ b/bitmap2component/CMakeLists.txt @@ -1,5 +1,5 @@ -include_directories(BEFORE ${INC_BEFORE}) +include_directories( BEFORE ${INC_BEFORE} ) include_directories( ../potrace ../polygon/kbool/include @@ -7,48 +7,63 @@ include_directories( ${INC_AFTER} ) -set(BITMAP2COMPONENT_SRCS +set( BITMAP2COMPONENT_SRCS + ../common/single_top.cpp bitmap2component.cpp bitmap2cmp_gui_base bitmap2cmp_gui ) -if(WIN32) - if(MINGW) - # BITMAP2COMPONENT_RESOURCES variable is set by the macro. - mingw_resource_compiler(bitmap2component) - else(MINGW) - set(BITMAP2COMPONENT_RESOURCES bitmap2component.rc) - endif(MINGW) -endif(WIN32) +set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=0" + ) +set_source_files_properties( bitmap2cmp_gui.cpp PROPERTIES + COMPILE_DEFINITIONS "COMPILING_DLL" + ) + +add_executable( bitmap2component WIN32 MACOSX_BUNDLE + ${BITMAP2COMPONENT_SRCS} + ${BITMAP2COMPONENT_RESOURCES} + ) + +target_link_libraries( bitmap2component + common + polygon + bitmaps + ${wxWidgets_LIBRARIES} + potrace + ) + +install( TARGETS bitmap2component + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) -if(APPLE) - set(BITMAP2COMPONENT_RESOURCES bitmap2component.icns) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/bitmap2component.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - set(MACOSX_BUNDLE_ICON_FILE bitmap2component.icns) - set(MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.bitmap2component) -endif(APPLE) +if( false ) # linker map with cross reference + set_target_properties( bitmap2component PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=bitmap2component.map" + ) +endif() - -add_executable(bitmap2component WIN32 MACOSX_BUNDLE - ${BITMAP2COMPONENT_SRCS} - ${BITMAP2COMPONENT_RESOURCES}) +if( MINGW ) + # BITMAP2COMPONENT_RESOURCES variable is set by the macro. + mingw_resource_compiler( bitmap2component ) +else() + set( BITMAP2COMPONENT_RESOURCES bitmap2component.rc ) +endif() -if(APPLE) - set_target_properties(bitmap2component PROPERTIES MACOSX_BUNDLE_INFO_PLIST - ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) -endif(APPLE) - -target_link_libraries( bitmap2component common polygon bitmaps - ${wxWidgets_LIBRARIES} - potrace - ) - -install(TARGETS bitmap2component - DESTINATION ${KICAD_BIN} - COMPONENT binary) +if( APPLE ) + set( BITMAP2COMPONENT_RESOURCES bitmap2component.icns ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/bitmap2component.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set( MACOSX_BUNDLE_ICON_FILE bitmap2component.icns ) + set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.bitmap2component ) + set_target_properties( bitmap2component PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) +endif() diff --git a/bitmap2component/bitmap2cmp_gui.cpp b/bitmap2component/bitmap2cmp_gui.cpp index d83a0fce8c..f43d5c751c 100644 --- a/bitmap2component/bitmap2cmp_gui.cpp +++ b/bitmap2component/bitmap2cmp_gui.cpp @@ -21,8 +21,11 @@ * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + #include -#include +#include + +#include #include #include #include @@ -39,47 +42,53 @@ #include #include #include +#include +#include + +#define KEYWORD_FRAME_POSX wxT( "Bmconverter_Pos_x" ) +#define KEYWORD_FRAME_POSY wxT( "Bmconverter_Pos_y" ) +#define KEYWORD_FRAME_SIZEX wxT( "Bmconverter_Size_x" ) +#define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" ) +#define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" ) +#define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" ) +#define KEYWORD_LAST_FORMAT wxT( "Last_format" ) +#define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" ) +#define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" ) -#define KEYWORD_FRAME_POSX wxT( "Bmconverter_Pos_x" ) -#define KEYWORD_FRAME_POSY wxT( "Bmconverter_Pos_y" ) -#define KEYWORD_FRAME_SIZEX wxT( "Bmconverter_Size_x" ) -#define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" ) -#define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" ) -#define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" ) -#define KEYWORD_LAST_FORMAT wxT( "Last_format" ) -#define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" ) -#define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" ) extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ); -/* Class BM2CMP_FRAME_BASE -This is the main frame for this application -*/ +/** + * Class BM2CMP_FRAME_BASE + * is the main frame for this application + */ class BM2CMP_FRAME : public BM2CMP_FRAME_BASE { private: - wxImage m_Pict_Image; - wxBitmap m_Pict_Bitmap; - wxImage m_Greyscale_Image; - wxBitmap m_Greyscale_Bitmap; - wxImage m_NB_Image; - wxBitmap m_BN_Bitmap; - wxString m_BitmapFileName; - wxString m_ConvertedFileName; - wxSize m_FrameSize; - wxPoint m_FramePos; - wxConfig * m_Config; + wxImage m_Pict_Image; + wxBitmap m_Pict_Bitmap; + wxImage m_Greyscale_Image; + wxBitmap m_Greyscale_Bitmap; + wxImage m_NB_Image; + wxBitmap m_BN_Bitmap; + wxString m_BitmapFileName; + wxString m_ConvertedFileName; + wxSize m_FrameSize; + wxPoint m_FramePos; + wxConfig* m_Config; public: - BM2CMP_FRAME(); + BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~BM2CMP_FRAME(); + // overload KIWAY_PLAYER virtual + bool OpenProjectFiles( const std::vector& aFilenames, int aCtl=0 ); + private: // Event handlers void OnPaint( wxPaintEvent& event ); void OnLoadFile( wxCommandEvent& event ); - bool LoadFile( wxString& aFullFileName ); void OnExport( wxCommandEvent& event ); /** @@ -114,8 +123,11 @@ private: }; -BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) +BM2CMP_FRAME::BM2CMP_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + BM2CMP_FRAME_BASE( aParent ) { + SetKiway( this, aKiway ); + int tmp; m_Config = new wxConfig(); m_Config->Read( KEYWORD_FRAME_POSX, & m_FramePos.x, -1 ); @@ -124,15 +136,16 @@ BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) m_Config->Read( KEYWORD_FRAME_SIZEY, & m_FrameSize.y, -1 ); m_Config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); m_Config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); + if( m_Config->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) ) m_sliderThreshold->SetValue( tmp ); + if( m_Config->Read( KEYWORD_BW_NEGATIVE, &tmp ) ) m_rbOptions->SetSelection( tmp ? 1 : 0 ); m_Config->Read( KEYWORD_LAST_FORMAT, &tmp ); m_radioBoxFormat->SetSelection( tmp ); - // Give an icon wxIcon icon; icon.CopyFromBitmap( KiBitmap( icon_bitmap2component_xpm ) ); @@ -144,14 +157,14 @@ BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) m_buttonExport->Enable( false ); - if ( m_FramePos == wxDefaultPosition ) + if( m_FramePos == wxDefaultPosition ) Centre(); } BM2CMP_FRAME::~BM2CMP_FRAME() { - if( ( m_Config == NULL ) || IsIconized() ) + if( !m_Config || IsIconized() ) return; m_FrameSize = GetSize(); @@ -207,23 +220,24 @@ void BM2CMP_FRAME::OnPaint( wxPaintEvent& event ) */ void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event ) { - wxFileName fn(m_BitmapFileName); - wxString path = fn.GetPath(); + wxFileName fn(m_BitmapFileName); + wxString path = fn.GetPath(); if( path.IsEmpty() || !wxDirExists(path) ) path = wxGetCwd(); - wxFileDialog FileDlg( this, _( "Choose Image" ), path, wxEmptyString, + wxFileDialog fileDlg( this, _( "Choose Image" ), path, wxEmptyString, _( "Image Files " ) + wxImage::GetImageExtWildcard(), wxFD_OPEN ); - int diag = FileDlg.ShowModal(); + + int diag = fileDlg.ShowModal(); if( diag != wxID_OK ) return; - wxString fullFilename = FileDlg.GetPath(); + wxString fullFilename = fileDlg.GetPath(); - if( ! LoadFile( fullFilename ) ) + if( !OpenProjectFiles( std::vector( 1, fullFilename ) ) ) return; m_buttonExport->Enable( true ); @@ -232,13 +246,22 @@ void BM2CMP_FRAME::OnLoadFile( wxCommandEvent& event ) } -bool BM2CMP_FRAME::LoadFile( wxString& aFullFileName ) +bool BM2CMP_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) { - m_BitmapFileName = aFullFileName; + // Prj().MaybeLoadProjectSettings(); + + m_BitmapFileName = aFileSet[0]; if( !m_Pict_Image.LoadFile( m_BitmapFileName ) ) { - wxMessageBox( _( "Couldn't load image from <%s>" ), m_BitmapFileName.c_str() ); + /* LoadFile has its own UI, no need for further failure notification here + wxString msg = wxString::Format( + _( "Could not load image '%s'" ), + GetChars( aFilename ) + ); + + wxMessageBox( msg ); + */ return false; } @@ -249,6 +272,7 @@ bool BM2CMP_FRAME::LoadFile( wxString& aFullFileName ) int nb = m_Pict_Bitmap.GetDepth(); wxString msg; + msg.Printf( wxT( "%d" ), w ); m_SizeXValue->SetLabel(msg); msg.Printf( wxT( "%d" ), h ); @@ -262,12 +286,14 @@ bool BM2CMP_FRAME::LoadFile( wxString& aFullFileName ) m_Greyscale_Image.Destroy(); m_Greyscale_Image = m_Pict_Image.ConvertToGreyscale( ); + if( m_rbOptions->GetSelection() > 0 ) NegateGreyscaleImage( ); + m_Greyscale_Bitmap = wxBitmap( m_Greyscale_Image ); m_NB_Image = m_Greyscale_Image; - Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() ); + Binarize( (double) m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() ); return true; } @@ -297,9 +323,10 @@ void BM2CMP_FRAME::Binarize( double aThreshold ) m_BN_Bitmap = wxBitmap( m_NB_Image ); } + void BM2CMP_FRAME::NegateGreyscaleImage( ) { - unsigned char pix; + unsigned char pix; int h = m_Greyscale_Image.GetHeight(); int w = m_Greyscale_Image.GetWidth(); @@ -321,58 +348,61 @@ void BM2CMP_FRAME::OnOptionsSelection( wxCommandEvent& event ) Refresh(); } + void BM2CMP_FRAME::OnThresholdChange( wxScrollEvent& event ) { Binarize( (double)m_sliderThreshold->GetValue()/m_sliderThreshold->GetMax() ); Refresh(); } + void BM2CMP_FRAME::OnExport( wxCommandEvent& event ) { int sel = m_radioBoxFormat->GetSelection(); switch( sel ) { - case 0: - OnExportEeschema(); - break; + case 0: + OnExportEeschema(); + break; - case 1: - OnExportPcbnew( true ); - break; + case 1: + OnExportPcbnew( true ); + break; - case 2: - OnExportPcbnew( false ); - break; + case 2: + OnExportPcbnew( false ); + break; - case 3: - OnExportPostScript(); - break; + case 3: + OnExportPostScript(); + break; - case 4: - OnExportLogo(); - break; + case 4: + OnExportLogo(); + break; } } + void BM2CMP_FRAME::OnExportLogo() { - wxFileName fn(m_ConvertedFileName); - wxString path = fn.GetPath(); + wxFileName fn(m_ConvertedFileName); + wxString path = fn.GetPath(); if( path.IsEmpty() || !wxDirExists(path) ) path = ::wxGetCwd(); wxString msg = _( "Logo file (*.kicad_wks)|*.kicad_wks" ); - wxFileDialog FileDlg( this, _( "Create a logo file" ), path, wxEmptyString, + wxFileDialog fileDlg( this, _( "Create a logo file" ), path, wxEmptyString, msg, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - int diag = FileDlg.ShowModal(); + int diag = fileDlg.ShowModal(); if( diag != wxID_OK ) return; - m_ConvertedFileName = FileDlg.GetPath(); + m_ConvertedFileName = fileDlg.GetPath(); FILE* outfile; outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) ); @@ -389,24 +419,26 @@ void BM2CMP_FRAME::OnExportLogo() fclose( outfile ); } + void BM2CMP_FRAME::OnExportPostScript() { - wxFileName fn(m_ConvertedFileName); - wxString path = fn.GetPath(); + wxFileName fn( m_ConvertedFileName ); + wxString path = fn.GetPath(); - if( path.IsEmpty() || !wxDirExists(path) ) + if( path.IsEmpty() || !wxDirExists( path ) ) path = ::wxGetCwd(); wxString msg = _( "Postscript file (*.ps)|*.ps" ); - wxFileDialog FileDlg( this, _( "Create a Postscript file" ), path, wxEmptyString, + wxFileDialog fileDlg( this, _( "Create a Postscript file" ), path, wxEmptyString, msg, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - int diag = FileDlg.ShowModal(); + + int diag = fileDlg.ShowModal(); if( diag != wxID_OK ) return; - m_ConvertedFileName = FileDlg.GetPath(); + m_ConvertedFileName = fileDlg.GetPath(); FILE* outfile; outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) ); @@ -423,27 +455,29 @@ void BM2CMP_FRAME::OnExportPostScript() fclose( outfile ); } + void BM2CMP_FRAME::OnExportEeschema() { - wxFileName fn(m_ConvertedFileName); - wxString path = fn.GetPath(); + wxFileName fn( m_ConvertedFileName ); + wxString path = fn.GetPath(); if( path.IsEmpty() || !wxDirExists(path) ) path = ::wxGetCwd(); wxString msg = _( "Schematic lib file (*.lib)|*.lib" ); - wxFileDialog FileDlg( this, _( "Create a lib file for Eeschema" ), path, wxEmptyString, + + wxFileDialog fileDlg( this, _( "Create a lib file for Eeschema" ), path, wxEmptyString, msg, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - int diag = FileDlg.ShowModal(); + + int diag = fileDlg.ShowModal(); if( diag != wxID_OK ) return; - m_ConvertedFileName = FileDlg.GetPath(); + m_ConvertedFileName = fileDlg.GetPath(); - FILE* outfile; - outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) ); + FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) ); if( outfile == NULL ) { @@ -460,29 +494,29 @@ void BM2CMP_FRAME::OnExportEeschema() void BM2CMP_FRAME::OnExportPcbnew( bool aLegacyFormat ) { - wxFileName fn(m_ConvertedFileName); - wxString path = fn.GetPath(); + wxFileName fn( m_ConvertedFileName ); + wxString path = fn.GetPath(); - if( path.IsEmpty() || !wxDirExists(path) ) + if( path.IsEmpty() || !wxDirExists( path ) ) path = ::wxGetCwd(); wxString msg = aLegacyFormat ? _( "Footprint file (*.emp)|*.emp" ) : _( "Footprint file (*.kicad_mod)|*.kicad_mod" ); - wxFileDialog FileDlg( this, _( "Create a footprint file for PcbNew" ), + + wxFileDialog fileDlg( this, _( "Create a footprint file for PcbNew" ), path, wxEmptyString, msg, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - int diag = FileDlg.ShowModal(); + + int diag = fileDlg.ShowModal(); if( diag != wxID_OK ) return; - m_ConvertedFileName = FileDlg.GetPath(); + m_ConvertedFileName = fileDlg.GetPath(); - - FILE* outfile; - outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) ); + FILE* outfile = wxFopen( m_ConvertedFileName, wxT( "w" ) ); if( outfile == NULL ) { @@ -496,6 +530,7 @@ void BM2CMP_FRAME::OnExportPcbnew( bool aLegacyFormat ) fclose( outfile ); } + void BM2CMP_FRAME::ExportFile( FILE* aOutfile, int aFormat ) { // Create a potrace bitmap @@ -525,29 +560,82 @@ void BM2CMP_FRAME::ExportFile( FILE* aOutfile, int aFormat ) } -// EDA_APP -IMPLEMENT_APP( EDA_APP ) +//---------------------------------------------------------------------- -///----------------------------------------------------------------------------- -// EDA_APP -// main program -//----------------------------------------------------------------------------- +namespace BMP2CMP { -bool EDA_APP::OnInit() +static struct IFACE : public KIFACE_I { - wxInitAllImageHandlers(); + bool OnKifaceStart( PGM_BASE* aProgram ); - InitEDA_Appl( wxT( "BMP2CMP" ) ); + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) + { + switch( aClassId ) + { - wxFrame* frame = new BM2CMP_FRAME(); - SetTopWindow( frame ); - frame->Show( true ); + default: + { + KIWAY_PLAYER* frame = new BM2CMP_FRAME( aKiway, aParent ); + return frame; + } + } + } - return true; + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) + { + return NULL; + } + + IFACE( const char* aDSOname, KIWAY::FACE_T aType ) : + KIFACE_I( aDSOname, aType ) + {} + +} kiface( "BMP2CMP", KIWAY::FACE_BMP2CMP ); + +} // namespace BMP2CMP + +using namespace BMP2CMP; + +static PGM_BASE* process; + +KIFACE_I& Kiface() +{ + return kiface; } -void EDA_APP::MacOpenFile( const wxString& aFileName ) +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram ) { + process = (PGM_BASE*) aProgram; + return &kiface; } + + +#if defined(BUILD_KIWAY_DLLS) +PGM_BASE& Pgm() +{ + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} +#endif + + +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) +{ + return start_common(); +} + diff --git a/bitmap2component/bitmap2cmp_gui_base.cpp b/bitmap2component/bitmap2cmp_gui_base.cpp index 92315a9545..ee7f225306 100644 --- a/bitmap2component/bitmap2cmp_gui_base.cpp +++ b/bitmap2component/bitmap2cmp_gui_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 5 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -9,7 +9,7 @@ /////////////////////////////////////////////////////////////////////////// -BM2CMP_FRAME_BASE::BM2CMP_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) +BM2CMP_FRAME_BASE::BM2CMP_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : KIWAY_PLAYER( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); diff --git a/bitmap2component/bitmap2cmp_gui_base.fbp b/bitmap2component/bitmap2cmp_gui_base.fbp index d848aa0d8c..2944581ac6 100644 --- a/bitmap2component/bitmap2cmp_gui_base.fbp +++ b/bitmap2component/bitmap2cmp_gui_base.fbp @@ -20,8 +20,10 @@ . 1 + 1 1 1 + UI 0 0 @@ -44,7 +46,7 @@ 527,470 wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER - + KIWAY_PLAYER; kiway_player.h Bitmap to Component Converter diff --git a/bitmap2component/bitmap2cmp_gui_base.h b/bitmap2component/bitmap2cmp_gui_base.h index 301a63398b..4ed079ce86 100644 --- a/bitmap2component/bitmap2cmp_gui_base.h +++ b/bitmap2component/bitmap2cmp_gui_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 5 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,6 +11,9 @@ #include #include #include +class KIWAY_PLAYER; + +#include "kiway_player.h" #include #include #include @@ -37,7 +40,7 @@ /////////////////////////////////////////////////////////////////////////////// /// Class BM2CMP_FRAME_BASE /////////////////////////////////////////////////////////////////////////////// -class BM2CMP_FRAME_BASE : public wxFrame +class BM2CMP_FRAME_BASE : public KIWAY_PLAYER { private: diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e69e9ecae7..8a79b34a16 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -62,6 +62,48 @@ if( WIN32 AND MSYS ) add_definitions( -DGLEW_STATIC ) endif() + +# A shared library subsetted from common which restricts what can go into +# a single_top link image. By not linking to common, we control what does +# statically go into single_top link images. My current thinking is that only +# wxWidgets should be a shared link from single top, everything else should be +# statically bound into it. Otherwise you will have DSO loading problems. After it +# sets the LIB PATHS however, we want the *.kiface modules to use shared linking. +add_library( singletop STATIC EXCLUDE_FROM_ALL + confirm.cpp + eda_doc.cpp + kiway.cpp + kiway_holder.cpp + ) + + +# A shared library used by multiple *.kiface files and one or two program +# launchers. Object files can migrate into here over time, but only if they are +# surely needed and certainly used from more than one place without recompilation. +# Functions and data all need to use the #include and be declared +# as APIEXPORT +set( LIB_KICAD_SRCS + colors.cpp + dlist.cpp + string.cpp + ) + +if( future ) +add_library( lib_kicad SHARED + ) +target_link_libraries( lib_kicad + ${wxWidgets_LIBRARIES} + ) +set_target_properties( lib_kicad PROPERTIES + OUTPUT_NAME ki + ) +install( TARGETS lib_kicad + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) +endif() + + set( COMMON_ABOUT_DLG_SRCS dialog_about/AboutDialog_main.cpp dialog_about/dialog_about.cpp @@ -89,11 +131,13 @@ set( COMMON_PAGE_LAYOUT_SRCS ) set( COMMON_SRCS + ${LIB_KICAD_SRCS} ${COMMON_ABOUT_DLG_SRCS} ${COMMON_PAGE_LAYOUT_SRCS} base_struct.cpp basicframe.cpp bezier_curves.cpp + bin_mod.cpp bitmap.cpp block_commande.cpp build_version.cpp @@ -103,6 +147,7 @@ set( COMMON_SRCS class_marker_base.cpp class_plotter.cpp class_undoredo_container.cpp + colors.cpp common.cpp common_plot_functions.cpp common_plotHPGL_functions.cpp @@ -111,13 +156,13 @@ set( COMMON_SRCS common_plotGERBER_functions.cpp common_plotDXF_functions.cpp common_plotSVG_functions.cpp + config_params.cpp confirm.cpp copy_to_clipboard.cpp dialog_shim.cpp displlst.cpp - dlist.cpp - drawframe.cpp - drawpanel.cpp + draw_frame.cpp + draw_panel.cpp drawtxt.cpp dsnlexer.cpp eda_dde.cpp @@ -130,16 +175,19 @@ set( COMMON_SRCS hotkeys_basic.cpp hotkey_grid_table.cpp html_messagebox.cpp + kiface_i.cpp kiway.cpp + kiway_holder.cpp msgpanel.cpp netlist_keywords.cpp newstroke_font.cpp - projet_config.cpp + project.cpp ptree.cpp reporter.cpp richio.cpp + search_stack.cpp selcolor.cpp - string.cpp + systemdirsappend.cpp trigo.cpp utf8.cpp wildcards_and_files_ext.cpp @@ -149,9 +197,11 @@ set( COMMON_SRCS zoom.cpp ) -# We will not want edaappl.cpp linked into the KIFACE, only into the KIWAY. if( TRUE OR NOT USE_KIWAY_DLLS ) - list( APPEND COMMON_SRCS edaappl.cpp ) +#if( NOT USE_KIWAY_DLLS ) + # We DO NOT want pgm_base.cpp linked into the KIFACE, only into the KIWAY. + # Check the map files to verify eda_pgm.o not being linked in. + list( APPEND COMMON_SRCS pgm_base.cpp ) endif() if( NOT HAVE_STRTOKR ) @@ -180,10 +230,9 @@ set( COMMON_SRCS geometry/shape_collisions.cpp geometry/shape_index.cpp ) - - add_library( common STATIC ${COMMON_SRCS} ) + set( PCB_COMMON_SRCS base_screen.cpp eda_text.cpp diff --git a/common/base_units.cpp b/common/base_units.cpp index 38a0279786..5b79ab5746 100644 --- a/common/base_units.cpp +++ b/common/base_units.cpp @@ -197,7 +197,7 @@ void StripTrailingZeros( wxString& aStringValue, unsigned aTrailingZeroAllowed ) * otherwise the actual value is rounded when read from dialog and converted * in internal units, and therefore modified. */ -wxString ReturnStringFromValue( EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol ) +wxString StringFromValue( EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol ) { double value_to_print = To_User_Unit( aUnit, aValue ); @@ -257,7 +257,7 @@ wxString ReturnStringFromValue( EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymb void PutValueInLocalUnits( wxTextCtrl& aTextCtr, int aValue ) { - wxString msg = ReturnStringFromValue( g_UserUnit, aValue ); + wxString msg = StringFromValue( g_UserUnit, aValue ); aTextCtr.SetValue( msg ); } @@ -286,7 +286,7 @@ double From_User_Unit( EDA_UNITS_T aUnit, double aValue ) } -int ReturnValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue ) +int ValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue ) { double value; double dtmp = 0; @@ -348,21 +348,21 @@ int ReturnValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue ) } -int ReturnValueFromString( const wxString& aTextValue ) +int ValueFromString( const wxString& aTextValue ) { int value; - value = ReturnValueFromString( g_UserUnit, aTextValue); + value = ValueFromString( g_UserUnit, aTextValue); return value; } -int ReturnValueFromTextCtrl( const wxTextCtrl& aTextCtr ) +int ValueFromTextCtrl( const wxTextCtrl& aTextCtr ) { int value; wxString msg = aTextCtr.GetValue(); - value = ReturnValueFromString( g_UserUnit, msg ); + value = ValueFromString( g_UserUnit, msg ); return value; } diff --git a/common/basicframe.cpp b/common/basicframe.cpp index d1616dd722..3efb4af478 100644 --- a/common/basicframe.cpp +++ b/common/basicframe.cpp @@ -36,7 +36,8 @@ #include #include -#include +#include +#include #include #include #include @@ -61,11 +62,9 @@ static const wxChar entryPerspective[] = wxT( "Perspective" ); -EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, - ID_DRAWFRAME_TYPE aFrameType, - const wxString& aTitle, - const wxPoint& aPos, const wxSize& aSize, - long aStyle, const wxString & aFrameName ) : +EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, + const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, + long aStyle, const wxString& aFrameName ) : wxFrame( aParent, wxID_ANY, aTitle, aPos, aSize, aStyle, aFrameName ) { wxSize minsize; @@ -108,7 +107,7 @@ EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event ) { - SaveSettings(); // virtual, wxFrame specific + SaveSettings( config() ); // virtual, wxFrame specific event.Skip(); // we did not "handle" the event, only eavesdropped on it. } @@ -116,9 +115,6 @@ void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event ) EDA_BASE_FRAME::~EDA_BASE_FRAME() { - if( wxGetApp().GetHtmlHelpController() ) - wxGetApp().SetHtmlHelpController( NULL ); - delete m_autoSaveTimer; // This is needed for OSX: avoids further OnDraw processing after this @@ -174,54 +170,45 @@ void EDA_BASE_FRAME::SetLanguage( wxCommandEvent& event ) { int id = event.GetId(); - wxGetApp().SetLanguageIdentifier( id ); - wxGetApp().SetLanguage(); + Pgm().SetLanguageIdentifier( id ); + Pgm().SetLanguage(); ReCreateMenuBar(); GetMenuBar()->Refresh(); } -void EDA_BASE_FRAME::LoadSettings() +void EDA_BASE_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxString text; - int Ypos_min; - wxConfig* config; - - config = wxGetApp().GetSettings(); - int maximized = 0; - if( config ) + wxString text = m_FrameName + wxT( "Pos_x" ); + aCfg->Read( text, &m_FramePos.x ); + + text = m_FrameName + wxT( "Pos_y" ); + aCfg->Read( text, &m_FramePos.y ); + + text = m_FrameName + wxT( "Size_x" ); + aCfg->Read( text, &m_FrameSize.x, 600 ); + + text = m_FrameName + wxT( "Size_y" ); + aCfg->Read( text, &m_FrameSize.y, 400 ); + + text = m_FrameName + wxT( "Maximized" ); + aCfg->Read( text, &maximized, 0 ); + + if( m_hasAutoSave ) { - text = m_FrameName + wxT( "Pos_x" ); - config->Read( text, &m_FramePos.x ); - - text = m_FrameName + wxT( "Pos_y" ); - config->Read( text, &m_FramePos.y ); - - text = m_FrameName + wxT( "Size_x" ); - config->Read( text, &m_FrameSize.x, 600 ); - - text = m_FrameName + wxT( "Size_y" ); - config->Read( text, &m_FrameSize.y, 400 ); - - text = m_FrameName + wxT( "Maximized" ); - config->Read( text, &maximized, 0 ); - - if( m_hasAutoSave ) - { - text = m_FrameName + entryAutoSaveInterval; - config->Read( text, &m_autoSaveInterval, DEFAULT_AUTO_SAVE_INTERVAL ); - } + text = m_FrameName + entryAutoSaveInterval; + aCfg->Read( text, &m_autoSaveInterval, DEFAULT_AUTO_SAVE_INTERVAL ); } // Ensure Window title bar is visible #if defined( __WXMAC__ ) // for macOSX, the window must be below system (macOSX) toolbar -// Ypos_min = GetMBarHeight(); seems no more exist in new API (subject to change) - Ypos_min = 20; + // Ypos_min = GetMBarHeight(); seems no more exist in new API (subject to change) + int Ypos_min = 20; #else - Ypos_min = 0; + int Ypos_min = 0; #endif if( m_FramePos.y < Ypos_min ) m_FramePos.y = Ypos_min; @@ -229,44 +216,39 @@ void EDA_BASE_FRAME::LoadSettings() if( maximized ) Maximize(); - // Once this is fully implemented, wxAuiManager will be used to maintain the persistance of - // the main frame and all it's managed windows and all of the legacy frame persistence - // position code can be removed. - if( config ) - config->Read( m_FrameName + entryPerspective, &m_perspective ); + aCfg->Read( m_FrameName + entryPerspective, &m_perspective ); } -void EDA_BASE_FRAME::SaveSettings() +void EDA_BASE_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxString text; - wxConfig* config = wxGetApp().GetSettings(); + wxString text; - if( !config || IsIconized() ) + if( IsIconized() ) return; m_FrameSize = GetSize(); m_FramePos = GetPosition(); text = m_FrameName + wxT( "Pos_x" ); - config->Write( text, (long) m_FramePos.x ); + aCfg->Write( text, (long) m_FramePos.x ); text = m_FrameName + wxT( "Pos_y" ); - config->Write( text, (long) m_FramePos.y ); + aCfg->Write( text, (long) m_FramePos.y ); text = m_FrameName + wxT( "Size_x" ); - config->Write( text, (long) m_FrameSize.x ); + aCfg->Write( text, (long) m_FrameSize.x ); text = m_FrameName + wxT( "Size_y" ); - config->Write( text, (long) m_FrameSize.y ); + aCfg->Write( text, (long) m_FrameSize.y ); text = m_FrameName + wxT( "Maximized" ); - config->Write( text, IsMaximized() ); + aCfg->Write( text, IsMaximized() ); if( m_hasAutoSave ) { text = m_FrameName + entryAutoSaveInterval; - config->Write( text, m_autoSaveInterval ); + aCfg->Write( text, m_autoSaveInterval ); } // Once this is fully implemented, wxAuiManager will be used to maintain @@ -276,8 +258,16 @@ void EDA_BASE_FRAME::SaveSettings() // printf( "perspective(%s): %s\n", // TO_UTF8( m_FrameName + entryPerspective ), TO_UTF8( perspective ) ); + aCfg->Write( m_FrameName + entryPerspective, perspective ); +} - config->Write( m_FrameName + entryPerspective, perspective ); + +wxConfigBase* EDA_BASE_FRAME::config() +{ + // KICAD_MANAGER_FRAME overrides this + wxConfigBase* ret = Kiface().KifaceSettings(); + wxASSERT( ret ); + return ret; } @@ -288,12 +278,12 @@ void EDA_BASE_FRAME::PrintMsg( const wxString& text ) void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, - wxFileHistory * aFileHistory ) + wxFileHistory* aFileHistory ) { wxFileHistory* fileHistory = aFileHistory; - if( fileHistory == NULL ) - fileHistory = & wxGetApp().GetFileHistory(); + if( !fileHistory ) + fileHistory = &Kiface().GetFileHistory(); fileHistory->AddFileToHistory( FullFileName ); } @@ -302,33 +292,36 @@ void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, wxString EDA_BASE_FRAME::GetFileFromHistory( int cmdId, const wxString& type, wxFileHistory* aFileHistory ) { - wxString fn, msg; - size_t i; wxFileHistory* fileHistory = aFileHistory; - if( fileHistory == NULL ) - fileHistory = & wxGetApp().GetFileHistory(); + if( !fileHistory ) + fileHistory = &Kiface().GetFileHistory(); int baseId = fileHistory->GetBaseId(); - wxASSERT( cmdId >= baseId && cmdId < baseId + ( int )fileHistory->GetCount() ); + wxASSERT( cmdId >= baseId && cmdId < baseId + (int) fileHistory->GetCount() ); - i = ( size_t )( cmdId - baseId ); + unsigned i = cmdId - baseId; if( i < fileHistory->GetCount() ) { - fn = fileHistory->GetHistoryFile( i ); + wxString fn = fileHistory->GetHistoryFile( i ); - if( !wxFileName::FileExists( fn ) ) + if( wxFileName::FileExists( fn ) ) + return fn; + else { - msg.Printf( wxT( "file <%s> was not found." ), GetChars( fn ) ); + wxString msg = wxString::Format( + wxT( "file '%s' was not found." ), + GetChars( fn ) ); + wxMessageBox( msg ); + fileHistory->RemoveFileFromHistory( i ); - fn = wxEmptyString; } } - return fn; + return wxEmptyString; } @@ -339,28 +332,28 @@ void EDA_BASE_FRAME::GetKicadHelp( wxCommandEvent& event ) /* We have to get document for beginners, * or the the full specific doc * if event id is wxID_INDEX, we want the document for beginners. - * else the specific doc file (its name is in wxGetApp().GetHelpFileName()) + * else the specific doc file (its name is in Kiface().GetHelpFileName()) * The document for beginners is the same for all KiCad utilities */ if( event.GetId() == wxID_INDEX ) { - // Temporary change the help filename - wxString tmp = wxGetApp().GetHelpFileName(); + // Temporarily change the help filename + wxString tmp = Kiface().GetHelpFileName(); // Search for "getting_started_in_kicad.pdf" or "Getting_Started_in_KiCad.pdf" - wxGetApp().SetHelpFileName( wxT( "getting_started_in_kicad.pdf" ) ); - wxString helpFile = wxGetApp().GetHelpFile(); + Kiface().SetHelpFileName( wxT( "getting_started_in_kicad.pdf" ) ); + wxString helpFile = Kiface().GetHelpFile(); if( !helpFile ) { // Try to find "Getting_Started_in_KiCad.pdf" - wxGetApp().SetHelpFileName( wxT( "Getting_Started_in_KiCad.pdf" ) ); - helpFile = wxGetApp().GetHelpFile(); + Kiface().SetHelpFileName( wxT( "Getting_Started_in_KiCad.pdf" ) ); + helpFile = Kiface().GetHelpFile(); } if( !helpFile ) { msg.Printf( _( "Help file %s could not be found." ), - GetChars( wxGetApp().GetHelpFileName() ) ); + GetChars( Kiface().GetHelpFileName() ) ); wxMessageBox( msg ); } else @@ -368,36 +361,36 @@ void EDA_BASE_FRAME::GetKicadHelp( wxCommandEvent& event ) GetAssociatedDocument( this, helpFile ); } - wxGetApp().SetHelpFileName( tmp ); + Kiface().SetHelpFileName( tmp ); return; } #if defined ONLINE_HELP_FILES_FORMAT_IS_HTML - if( wxGetApp().GetHtmlHelpController() == NULL ) + if( Kiface().GetHtmlHelpController() == NULL ) { - wxGetApp().InitOnLineHelp(); + Kiface().InitOnLineHelp(); } - if( wxGetApp().GetHtmlHelpController() ) + if( Kiface().GetHtmlHelpController() ) { - wxGetApp().GetHtmlHelpController()->DisplayContents(); - wxGetApp().GetHtmlHelpController()->Display( wxGetApp().GetHelpFileName() ); + Kiface().GetHtmlHelpController()->DisplayContents(); + Kiface().GetHtmlHelpController()->Display( Kiface().GetHelpFileName() ); } else { - msg.Printf( _( "Help file %s could not be found." ), GetChars( wxGetApp().GetHelpFileName() ) ); + msg.Printf( _( "Help file %s could not be found." ), GetChars( Kiface().GetHelpFileName() ) ); wxMessageBox( msg ); } #elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF - wxString helpFile = wxGetApp().GetHelpFile(); + wxString helpFile = Kiface().GetHelpFile(); if( !helpFile ) { msg.Printf( _( "Help file %s could not be found." ), - GetChars( wxGetApp().GetHelpFileName() ) ); + GetChars( Kiface().GetHelpFileName() ) ); wxMessageBox( msg ); } else @@ -413,8 +406,8 @@ void EDA_BASE_FRAME::GetKicadHelp( wxCommandEvent& event ) void EDA_BASE_FRAME::OnSelectPreferredEditor( wxCommandEvent& event ) { - wxFileName fn = wxGetApp().GetEditorName(); - wxString wildcard( wxT( "*" ) ); + wxFileName fn = Pgm().GetEditorName(); + wxString wildcard( wxT( "*" ) ); #ifdef __WINDOWS__ wildcard += wxT( ".exe" ); @@ -430,18 +423,16 @@ void EDA_BASE_FRAME::OnSelectPreferredEditor( wxCommandEvent& event ) if( dlg.ShowModal() == wxID_CANCEL ) return; - wxASSERT( wxGetApp().GetCommonSettings() ); + wxString editor = dlg.GetPath(); - wxConfig* cfg = wxGetApp().GetCommonSettings(); - wxGetApp().SetEditorName( dlg.GetPath() ); - cfg->Write( wxT( "Editor" ), wxGetApp().GetEditorName() ); + Pgm().SetEditorName( editor ); } void EDA_BASE_FRAME::GetKicadAbout( wxCommandEvent& event ) { bool ShowAboutDialog(wxWindow * parent); - ShowAboutDialog(this); + ShowAboutDialog( this ); } @@ -535,7 +526,7 @@ void EDA_BASE_FRAME::CopyVersionInfoToClipboard( wxCommandEvent& event ) wxString tmp; wxPlatformInfo info; - tmp = wxT( "Application: " ) + wxGetApp().GetTitle() + wxT( "\n" ); + tmp = wxT( "Application: " ) + Pgm().App().GetAppName() + wxT( "\n" ); tmp << wxT( "Version: " ) << GetBuildVersion() #ifdef DEBUG << wxT( " Debug" ) @@ -666,14 +657,14 @@ void EDA_BASE_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName, if( !autoSaveFileName.FileExists() ) return; - wxString msg; + wxString msg = wxString::Format( _( + "Well this is potentially embarrassing! It appears that the last time " + "you were editing the file '%s' it was not saved properly. Do you wish to restore the last " + "edits you made?" ), + GetChars( aFileName.GetFullName() ) + ); - msg.Printf( _( "Well this is potentially embarrassing! It appears that the last time \ -you were editing the file <%s> it was not saved properly. Do you wish to restore the last \ -edits you made?" ), - GetChars( aFileName.GetFullName() ) ); - - int response = wxMessageBox( msg, wxGetApp().GetAppName(), wxYES_NO | wxICON_QUESTION, this ); + int response = wxMessageBox( msg, Pgm().App().GetAppName(), wxYES_NO | wxICON_QUESTION, this ); // Make a backup of the current file, delete the file, and rename the auto save file to // the file name. @@ -703,7 +694,7 @@ edits you made?" ), if( !wxRenameFile( autoSaveFileName.GetFullPath(), aFileName.GetFullPath() ) ) { wxMessageBox( _( "The auto save file could not be renamed to the board file name." ), - wxGetApp().GetAppName(), wxOK | wxICON_EXCLAMATION, this ); + Pgm().App().GetAppName(), wxOK | wxICON_EXCLAMATION, this ); } } else @@ -716,29 +707,21 @@ edits you made?" ), } } -/** - * Function SetModalMode - * Disable or enable all other windows, to emulate a dialog behavior - * Useful when the frame is used to show and selec items - * (see FOOTPRINT_VIEWER_FRAME and LIB_VIEW_FRAME) - * - * @param aModal = true to disable all other opened windows (i.e. - * this windows is in dialog mode - * = false to enable other windows - * This function is analog to MakeModal( aModal ), deprecated since wxWidgets 2.9.4 - */ + void EDA_BASE_FRAME::SetModalMode( bool aModal ) { // Disable all other windows #if wxCHECK_VERSION(2, 9, 4) - if ( IsTopLevel() ) + if( IsTopLevel() ) { wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - while (node) + + while( node ) { - wxWindow *win = node->GetData(); - if (win != this) - win->Enable(!aModal); + wxWindow* win = node->GetData(); + + if( win != this ) + win->Enable( !aModal ); node = node->GetNext(); } diff --git a/common/bin_mod.cpp b/common/bin_mod.cpp new file mode 100644 index 0000000000..fec950e415 --- /dev/null +++ b/common/bin_mod.cpp @@ -0,0 +1,52 @@ + + +#include +#include +#include + + +BIN_MOD::BIN_MOD( const char* aName ) : + m_name( aName ), + m_config( 0 ) +{ +} + + +void BIN_MOD::Init() +{ + // do an OS specific wxConfig instantiation, using the bin_mod (EXE/DLL/DSO) name. + m_config = new wxConfig( wxString::FromUTF8( m_name ) ); + + m_history.Load( *m_config ); + + // Prepare On Line Help. Use only lower case for help file names, in order to + // avoid problems with upper/lower case file names under windows and unix. +#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML + m_help_file = wxString::FromUTF8( m_name ) + wxT( ".html" ); +#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF + m_help_file = wxString::FromUTF8( m_name ) + wxT( ".pdf" ); +#else + #error Help files format not defined +#endif +} + + +void BIN_MOD::End() +{ + if( m_config ) + { + m_history.Save( *m_config ); + + // Deleting a wxConfigBase writes its contents to disk if changed. + // Might be NULL if called twice, in which case nothing happens. + delete m_config; + m_config = 0; + } +} + + +BIN_MOD::~BIN_MOD() +{ + End(); +} + diff --git a/common/block_commande.cpp b/common/block_commande.cpp index 19a7a0ccfa..dfc27995b3 100644 --- a/common/block_commande.cpp +++ b/common/block_commande.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/common/colors.cpp b/common/colors.cpp new file mode 100644 index 0000000000..ca12867b6e --- /dev/null +++ b/common/colors.cpp @@ -0,0 +1,156 @@ + +#include + + +/** + * The predefined colors used in KiCad. + * Please: if you change a value, remember these values are carefully chosen + * to have good results in Pcbnew, that uses the ORed value of basic colors + * when displaying superimposed objects + * This list must have exactly NBCOLORS items + */ +const StructColors g_ColorRefs[NBCOLORS] = +{ + { 0, 0, 0, BLACK, wxT( "Black" ), DARKDARKGRAY }, + { 72, 72, 72, DARKDARKGRAY, wxT( "Gray 1" ), DARKGRAY }, + { 132, 132, 132, DARKGRAY, wxT( "Gray 2" ), LIGHTGRAY }, + { 194, 194, 194, LIGHTGRAY, wxT( "Gray 3" ), WHITE }, + { 255, 255, 255, WHITE, wxT( "White" ), WHITE }, + { 194, 255, 255, LIGHTYELLOW, wxT( "L.Yellow" ), WHITE }, + { 72, 0, 0, DARKBLUE, wxT( "Blue 1" ), BLUE }, + { 0, 72, 0, DARKGREEN, wxT( "Green 1" ), GREEN }, + { 72, 72, 0, DARKCYAN, wxT( "Cyan 1" ), CYAN }, + { 0, 0, 72, DARKRED, wxT( "Red 1" ), RED }, + { 72, 0, 72, DARKMAGENTA, wxT( "Magenta 1" ), MAGENTA }, + { 0, 72, 72, DARKBROWN, wxT( "Brown 1" ), BROWN }, + { 132, 0, 0, BLUE, wxT( "Blue 2" ), LIGHTBLUE }, + { 0, 132, 0, GREEN, wxT( "Green 2" ), LIGHTGREEN }, + { 132, 132, 0, CYAN, wxT( "Cyan 2" ), LIGHTCYAN }, + { 0, 0, 132, RED, wxT( "Red 2" ), LIGHTRED }, + { 132, 0, 132, MAGENTA, wxT( "Magenta 2" ), LIGHTMAGENTA }, + { 0, 132, 132, BROWN, wxT( "Brown 2" ), YELLOW }, + { 194, 0, 0, LIGHTBLUE, wxT( "Blue 3" ), PUREBLUE, }, + { 0, 194, 0, LIGHTGREEN, wxT( "Green 3" ), PUREGREEN }, + { 194, 194, 0, LIGHTCYAN, wxT( "Cyan 3" ), PURECYAN }, + { 0, 0, 194, LIGHTRED, wxT( "Red 3" ), PURERED }, + { 194, 0, 194, LIGHTMAGENTA, wxT( "Magenta 3" ), PUREMAGENTA }, + { 0, 194, 194, YELLOW, wxT( "Yellow 3" ), PUREYELLOW }, + { 255, 0, 0, PUREBLUE, wxT( "Blue 4" ), WHITE }, + { 0, 255, 0, PUREGREEN, wxT( "Green 4" ), WHITE }, + { 255, 255, 0, PURECYAN, wxT( "Cyan 4" ), WHITE }, + { 0, 0, 255, PURERED, wxT( "Red 4" ), WHITE }, + { 255, 0, 255, PUREMAGENTA, wxT( "Magenta 4" ), WHITE }, + { 0, 255, 255, PUREYELLOW, wxT( "Yellow 4" ), WHITE }, +}; + + +EDA_COLOR_T ColorByName( const wxString& aName ) +{ + // look for a match in the palette itself + for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) ) + { + if( 0 == aName.CmpNoCase( g_ColorRefs[trying].m_Name ) ) + return trying; + } + + // Not found, no idea... + return UNSPECIFIED_COLOR; +} + + +bool ColorIsLight( EDA_COLOR_T aColor ) +{ + const StructColors &c = g_ColorRefs[ColorGetBase( aColor )]; + int r = c.m_Red; + int g = c.m_Green; + int b = c.m_Blue; + return ((r * r) + (g * g) + (b * b)) > (128 * 128 * 3); +} + + +EDA_COLOR_T ColorFindNearest( const wxColour &aColor ) +{ + return ColorFindNearest( aColor.Red(), aColor.Green(), aColor.Blue() ); +} + + +EDA_COLOR_T ColorFindNearest( int aR, int aG, int aB ) +{ + EDA_COLOR_T candidate = BLACK; + + /* Find the 'nearest' color in the palette. This is fun. There is + a gazilion of metrics for the color space and no one of the + useful one is in the RGB color space. Who cares, this is a CAD, + not a photosomething... + + I hereby declare that the distance is the sum of the square of the + component difference. Think about the RGB color cube. Now get the + euclidean distance, but without the square root... for ordering + purposes it's the same, obviously. Also each component can't be + less of the target one, since I found this currently work better... + */ + int nearest_distance = 255 * 255 * 3 + 1; // Can't beat this + + for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) ) + { + const StructColors &c = g_ColorRefs[trying]; + int distance = (aR - c.m_Red) * (aR - c.m_Red) + + (aG - c.m_Green) * (aG - c.m_Green) + + (aB - c.m_Blue) * (aB - c.m_Blue); + if( distance < nearest_distance && c.m_Red >= aR && + c.m_Green >= aG && c.m_Blue >= aB ) + { + nearest_distance = distance; + candidate = trying; + } + } + + return candidate; +} + + +EDA_COLOR_T ColorMix( EDA_COLOR_T aColor1, EDA_COLOR_T aColor2 ) +{ + /* Memoization storage. This could be potentially called for each + * color merge so a cache is useful (there are few colours anyway) */ + static EDA_COLOR_T mix_cache[NBCOLORS][NBCOLORS]; + + // TODO how is alpha used? it's a mac only thing, I have no idea + aColor1 = ColorGetBase( aColor1 ); + aColor2 = ColorGetBase( aColor2 ); + + // First easy thing: a black gives always the other colour + if( aColor1 == BLACK ) + return aColor2; + if( aColor2 == BLACK) + return aColor1; + + /* Now we are sure that black can't occur, so the rule is: + * BLACK means not computed yet. If we're lucky we already have + * an answer */ + EDA_COLOR_T candidate = mix_cache[aColor1][aColor2]; + if( candidate != BLACK ) + return candidate; + + // Blend the two colors (i.e. OR the RGB values) + const StructColors &c1 = g_ColorRefs[aColor1]; + const StructColors &c2 = g_ColorRefs[aColor2]; + + // Ask the palette for the nearest color to the mix + wxColour mixed( c1.m_Red | c2.m_Red, + c1.m_Green | c2.m_Green, + c1.m_Blue | c2.m_Blue ); + candidate = ColorFindNearest( mixed ); + + /* Here, BLACK is *not* a good answer, since it would recompute the next time. + * Even theorically its not possible (with the current rules), but + * maybe the metric will change in the future */ + if( candidate == BLACK) + candidate = DARKDARKGRAY; + + // Store the result in the cache. The operation is commutative, too + mix_cache[aColor1][aColor2] = candidate; + mix_cache[aColor2][aColor1] = candidate; + return candidate; +} + diff --git a/common/common.cpp b/common/common.cpp index 46d2670fb7..f52e6469b9 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -65,48 +65,6 @@ EDA_UNITS_T g_UserUnit; EDA_COLOR_T g_GhostColor; -/** - * The predefined colors used in KiCad. - * Please: if you change a value, remember these values are carefully chosen - * to have good results in Pcbnew, that uses the ORed value of basic colors - * when displaying superimposed objects - * This list must have exactly NBCOLORS items - */ -const StructColors g_ColorRefs[NBCOLORS] = -{ - { 0, 0, 0, BLACK, wxT( "Black" ), DARKDARKGRAY }, - { 72, 72, 72, DARKDARKGRAY, wxT( "Gray 1" ), DARKGRAY }, - { 132, 132, 132, DARKGRAY, wxT( "Gray 2" ), LIGHTGRAY }, - { 194, 194, 194, LIGHTGRAY, wxT( "Gray 3" ), WHITE }, - { 255, 255, 255, WHITE, wxT( "White" ), WHITE }, - { 194, 255, 255, LIGHTYELLOW, wxT( "L.Yellow" ), WHITE }, - { 72, 0, 0, DARKBLUE, wxT( "Blue 1" ), BLUE }, - { 0, 72, 0, DARKGREEN, wxT( "Green 1" ), GREEN }, - { 72, 72, 0, DARKCYAN, wxT( "Cyan 1" ), CYAN }, - { 0, 0, 72, DARKRED, wxT( "Red 1" ), RED }, - { 72, 0, 72, DARKMAGENTA, wxT( "Magenta 1" ), MAGENTA }, - { 0, 72, 72, DARKBROWN, wxT( "Brown 1" ), BROWN }, - { 132, 0, 0, BLUE, wxT( "Blue 2" ), LIGHTBLUE }, - { 0, 132, 0, GREEN, wxT( "Green 2" ), LIGHTGREEN }, - { 132, 132, 0, CYAN, wxT( "Cyan 2" ), LIGHTCYAN }, - { 0, 0, 132, RED, wxT( "Red 2" ), LIGHTRED }, - { 132, 0, 132, MAGENTA, wxT( "Magenta 2" ), LIGHTMAGENTA }, - { 0, 132, 132, BROWN, wxT( "Brown 2" ), YELLOW }, - { 194, 0, 0, LIGHTBLUE, wxT( "Blue 3" ), PUREBLUE, }, - { 0, 194, 0, LIGHTGREEN, wxT( "Green 3" ), PUREGREEN }, - { 194, 194, 0, LIGHTCYAN, wxT( "Cyan 3" ), PURECYAN }, - { 0, 0, 194, LIGHTRED, wxT( "Red 3" ), PURERED }, - { 194, 0, 194, LIGHTMAGENTA, wxT( "Magenta 3" ), PUREMAGENTA }, - { 0, 194, 194, YELLOW, wxT( "Yellow 3" ), PUREYELLOW }, - { 255, 0, 0, PUREBLUE, wxT( "Blue 4" ), WHITE }, - { 0, 255, 0, PUREGREEN, wxT( "Green 4" ), WHITE }, - { 255, 255, 0, PURECYAN, wxT( "Cyan 4" ), WHITE }, - { 0, 0, 255, PURERED, wxT( "Red 4" ), WHITE }, - { 255, 0, 255, PUREMAGENTA, wxT( "Magenta 4" ), WHITE }, - { 0, 255, 255, PUREYELLOW, wxT( "Yellow 4" ), WHITE }, -}; - - /** * Function to use local notation or C standard notation for floating point numbers * some countries use 1,5 and others (and C) 1.5 diff --git a/common/common_plotPDF_functions.cpp b/common/common_plotPDF_functions.cpp index 8349c5ff45..ec9cef66d3 100644 --- a/common/common_plotPDF_functions.cpp +++ b/common/common_plotPDF_functions.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include diff --git a/common/common_plotPS_functions.cpp b/common/common_plotPS_functions.cpp index cad37ae694..9e1644485b 100644 --- a/common/common_plotPS_functions.cpp +++ b/common/common_plotPS_functions.cpp @@ -211,34 +211,34 @@ void PSLIKE_PLOTTER::fputsPostscriptString(FILE *fout, const wxString& txt) putc( '(', fout ); for( unsigned i = 0; i < txt.length(); i++ ) { - // Lazyness made me use stdio buffering yet another time... - wchar_t ch = txt[i]; - if( ch < 256 ) - { - switch (ch) - { - // The ~ shouldn't reach the outside - case '~': - break; - // These characters must be escaped - case '(': - case ')': - case '\\': - putc( '\\', fout ); + // Lazyness made me use stdio buffering yet another time... + wchar_t ch = txt[i]; + if( ch < 256 ) + { + switch (ch) + { + // The ~ shouldn't reach the outside + case '~': + break; + // These characters must be escaped + case '(': + case ')': + case '\\': + putc( '\\', fout ); - // FALLTHRU - default: - putc( ch, fout ); - break; - } - } + // FALLTHRU + default: + putc( ch, fout ); + break; + } + } } putc( ')', fout ); } /** - * Sister function for the ReturnGraphicTextWidth in drawtxt.cpp + * Sister function for the GraphicTextWidth in drawtxt.cpp * Does the same processing (i.e. calculates a text string width) but * using postscript metrics for the Helvetica font (optionally used for * PS and PDF plotting @@ -303,7 +303,7 @@ void PSLIKE_PLOTTER::postscriptOverlinePositions( const wxString& aText, int aXS } void PS_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil, - double aScale, bool aMirror ) + double aScale, bool aMirror ) { wxASSERT( !outputFile ); m_plotMirror = aMirror; @@ -354,31 +354,31 @@ void PSLIKE_PLOTTER::computeTextParameters( const wxPoint& aPos, switch( aH_justify ) { case GR_TEXT_HJUSTIFY_CENTER: - dx = -tw / 2; - break; + dx = -tw / 2; + break; case GR_TEXT_HJUSTIFY_RIGHT: - dx = -tw; - break; + dx = -tw; + break; case GR_TEXT_HJUSTIFY_LEFT: - dx = 0; - break; + dx = 0; + break; } switch( aV_justify ) { case GR_TEXT_VJUSTIFY_CENTER: - dy = th / 2; - break; + dy = th / 2; + break; case GR_TEXT_VJUSTIFY_TOP: dy = th; - break; + break; case GR_TEXT_VJUSTIFY_BOTTOM: - dy = 0; - break; + dy = 0; + break; } RotatePoint( &dx, &dy, aOrient ); @@ -620,7 +620,7 @@ void PS_PLOTTER::PenTo( const wxPoint& pos, char plume ) } if( penState != plume || pos != penLastpos ) { - DPOINT pos_dev = userToDeviceCoordinates( pos ); + DPOINT pos_dev = userToDeviceCoordinates( pos ); fprintf( outputFile, "%g %g %sto\n", pos_dev.x, pos_dev.y, ( plume=='D' ) ? "line" : "move" ); @@ -650,39 +650,39 @@ bool PS_PLOTTER::StartPlot() static const char* PSMacro[] = { - "%%BeginProlog\n" - "/line { newpath moveto lineto stroke } bind def\n", - "/cir0 { newpath 0 360 arc stroke } bind def\n", - "/cir1 { newpath 0 360 arc gsave fill grestore stroke } bind def\n", - "/cir2 { newpath 0 360 arc gsave fill grestore stroke } bind def\n", - "/arc0 { newpath arc stroke } bind def\n", - "/arc1 { newpath 4 index 4 index moveto arc closepath gsave fill\n", - " grestore stroke } bind def\n", - "/arc2 { newpath 4 index 4 index moveto arc closepath gsave fill\n", - " grestore stroke } bind def\n", - "/poly0 { stroke } bind def\n", - "/poly1 { closepath gsave fill grestore stroke } bind def\n", - "/poly2 { closepath gsave fill grestore stroke } bind def\n", - "/rect0 { rectstroke } bind def\n", - "/rect1 { rectfill } bind def\n", - "/rect2 { rectfill } bind def\n", - "/linemode0 { 0 setlinecap 0 setlinejoin 0 setlinewidth } bind def\n", - "/linemode1 { 1 setlinecap 1 setlinejoin } bind def\n", - "/dashedline { [200] 100 setdash } bind def\n", - "/solidline { [] 0 setdash } bind def\n", + "%%BeginProlog\n" + "/line { newpath moveto lineto stroke } bind def\n", + "/cir0 { newpath 0 360 arc stroke } bind def\n", + "/cir1 { newpath 0 360 arc gsave fill grestore stroke } bind def\n", + "/cir2 { newpath 0 360 arc gsave fill grestore stroke } bind def\n", + "/arc0 { newpath arc stroke } bind def\n", + "/arc1 { newpath 4 index 4 index moveto arc closepath gsave fill\n", + " grestore stroke } bind def\n", + "/arc2 { newpath 4 index 4 index moveto arc closepath gsave fill\n", + " grestore stroke } bind def\n", + "/poly0 { stroke } bind def\n", + "/poly1 { closepath gsave fill grestore stroke } bind def\n", + "/poly2 { closepath gsave fill grestore stroke } bind def\n", + "/rect0 { rectstroke } bind def\n", + "/rect1 { rectfill } bind def\n", + "/rect2 { rectfill } bind def\n", + "/linemode0 { 0 setlinecap 0 setlinejoin 0 setlinewidth } bind def\n", + "/linemode1 { 1 setlinecap 1 setlinejoin } bind def\n", + "/dashedline { [200] 100 setdash } bind def\n", + "/solidline { [] 0 setdash } bind def\n", - // This is for 'hidden' text (search anchors for PDF) + // This is for 'hidden' text (search anchors for PDF) "/phantomshow { moveto\n", " /KicadFont findfont 0.000001 scalefont setfont\n", - " show } bind def\n", + " show } bind def\n", // This is for regular postscript text "/textshow { gsave\n", " findfont exch scalefont setfont concat 1 scale 0 0 moveto show\n", " } bind def\n", - // Utility for getting Latin1 encoded fonts - "/reencodefont {\n", + // Utility for getting Latin1 encoded fonts + "/reencodefont {\n", " findfont dup length dict begin\n", " { 1 index /FID ne\n", " { def }\n", @@ -692,13 +692,13 @@ bool PS_PLOTTER::StartPlot() " currentdict\n", " end } bind def\n" - // Remap AdobeStandard fonts to Latin1 - "/KicadFont /Helvetica reencodefont definefont pop\n", - "/KicadFont-Bold /Helvetica-Bold reencodefont definefont pop\n", - "/KicadFont-Oblique /Helvetica-Oblique reencodefont definefont pop\n", - "/KicadFont-BoldOblique /Helvetica-BoldOblique reencodefont definefont pop\n", - "%%EndProlog\n", - NULL + // Remap AdobeStandard fonts to Latin1 + "/KicadFont /Helvetica reencodefont definefont pop\n", + "/KicadFont-Bold /Helvetica-Bold reencodefont definefont pop\n", + "/KicadFont-Oblique /Helvetica-Oblique reencodefont definefont pop\n", + "/KicadFont-BoldOblique /Helvetica-BoldOblique reencodefont definefont pop\n", + "%%EndProlog\n", + NULL }; time_t time1970 = time( NULL ); @@ -726,8 +726,8 @@ bool PS_PLOTTER::StartPlot() psPaperSize.Set( pageInfo.GetHeightMils(), pageInfo.GetWidthMils() ); fprintf( outputFile, "%%%%BoundingBox: 0 0 %d %d\n", - (int) ceil( psPaperSize.x * BIGPTsPERMIL ), - (int) ceil( psPaperSize.y * BIGPTsPERMIL ) ); + (int) ceil( psPaperSize.x * BIGPTsPERMIL ), + (int) ceil( psPaperSize.y * BIGPTsPERMIL ) ); // Specify the size of the sheet and the name associated with that size. // (If the "User size" option has been selected for the sheet size, @@ -775,9 +775,9 @@ bool PS_PLOTTER::StartPlot() // within the Document Structuring Convention. fputs( "%%Page: 1 1\n" "%%BeginPageSetup\n" - "gsave\n" - "0.0072 0.0072 scale\n" // Configure postscript for decimils coordinates - "linemode1\n", outputFile ); + "gsave\n" + "0.0072 0.0072 scale\n" // Configure postscript for decimils coordinates + "linemode1\n", outputFile ); // Rototranslate the coordinate to achieve the landscape layout @@ -803,7 +803,7 @@ bool PS_PLOTTER::EndPlot() wxASSERT( outputFile ); fputs( "showpage\n" "grestore\n" - "%%EOF\n", outputFile ); + "%%EOF\n", outputFile ); fclose( outputFile ); outputFile = NULL; @@ -813,15 +813,15 @@ bool PS_PLOTTER::EndPlot() void PS_PLOTTER::Text( const wxPoint& aPos, - enum EDA_COLOR_T aColor, - const wxString& aText, - double aOrient, - const wxSize& aSize, - enum EDA_TEXT_HJUSTIFY_T aH_justify, - enum EDA_TEXT_VJUSTIFY_T aV_justify, - int aWidth, - bool aItalic, - bool aBold ) + enum EDA_COLOR_T aColor, + const wxString& aText, + double aOrient, + const wxSize& aSize, + enum EDA_TEXT_HJUSTIFY_T aH_justify, + enum EDA_TEXT_VJUSTIFY_T aV_justify, + int aWidth, + bool aItalic, + bool aBold ) { SetCurrentLineWidth( aWidth ); SetColor( aColor ); @@ -874,7 +874,7 @@ void PS_PLOTTER::Text( const wxPoint& aPos, if( m_textMode == PLOTTEXTMODE_PHANTOM ) { fputsPostscriptString( outputFile, aText ); - DPOINT pos_dev = userToDeviceCoordinates( aPos ); + DPOINT pos_dev = userToDeviceCoordinates( aPos ); fprintf( outputFile, " %g %g phantomshow\n", pos_dev.x, pos_dev.y ); } diff --git a/common/projet_config.cpp b/common/config_params.cpp similarity index 62% rename from common/projet_config.cpp rename to common/config_params.cpp index 2d50a29b5f..6f7fabcbbc 100644 --- a/common/projet_config.cpp +++ b/common/config_params.cpp @@ -1,15 +1,36 @@ -/*********************/ -/* projet_config.cpp */ -/*********************/ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ #include #include -#include +#include #include #include #include #include -#include +#include #include #include @@ -19,8 +40,89 @@ #include -#define CONFIG_VERSION 1 -#define FORCE_LOCAL_CONFIG true +void wxConfigSaveParams( wxConfigBase* aCfg, + const PARAM_CFG_ARRAY& aList, const wxString& aGroup ) +{ + wxASSERT( aCfg ); + + BOOST_FOREACH( const PARAM_CFG_BASE& param, aList ) + { + if( param.m_Group ) + aCfg->SetPath( param.m_Group ); + else + aCfg->SetPath( aGroup ); + + if( param.m_Setup ) + continue; + + if( param.m_Type == PARAM_COMMAND_ERASE ) // Erase all data + { + if( param.m_Ident ) + aCfg->DeleteGroup( param.m_Ident ); + } + else + { + param.SaveParam( aCfg ); + } + } +} + + +void wxConfigLoadParams( wxConfigBase* aCfg, + const PARAM_CFG_ARRAY& aList, const wxString& aGroup ) +{ + wxASSERT( aCfg ); + + BOOST_FOREACH( const PARAM_CFG_BASE& param, aList ) + { + if( param.m_Group ) + aCfg->SetPath( param.m_Group ); + else + aCfg->SetPath( aGroup ); + + if( param.m_Setup ) + continue; + + param.ReadParam( aCfg ); + } +} + + +void wxConfigSaveSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList ) +{ + wxASSERT( aCfg ); + + BOOST_FOREACH( const PARAM_CFG_BASE& param, aList ) + { + if( !param.m_Setup ) + continue; + + if( param.m_Type == PARAM_COMMAND_ERASE ) // Erase all data + { + if( param.m_Ident ) + aCfg->DeleteGroup( param.m_Ident ); + } + else + { + param.SaveParam( aCfg ); + } + } +} + + +void wxConfigLoadSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList ) +{ + wxASSERT( aCfg ); + + BOOST_FOREACH( const PARAM_CFG_BASE& param, aList ) + { + if( !param.m_Setup ) + continue; + + param.ReadParam( aCfg ); + } +} + void ConfigBaseWriteDouble( wxConfigBase* aConfig, const wxString& aKey, double aValue ) @@ -35,220 +137,6 @@ void ConfigBaseWriteDouble( wxConfigBase* aConfig, const wxString& aKey, double } -bool EDA_APP::ReCreatePrjConfig( const wxString& fileName, - const wxString& GroupName, - bool ForceUseLocalConfig ) -{ - wxFileName fn = fileName; - - // Free old config file. - if( m_projectSettings ) - { - delete m_projectSettings; - m_projectSettings = NULL; - } - - /* Force the file extension. - * This allows the user to enter a filename without extension - * or use an existing name to create the project file - */ - if( fn.GetExt() != ProjectFileExtension ) - { - fn.SetExt( ProjectFileExtension ); - } - - /* Update the library search path list if a new project file is loaded. */ - if( m_projectFileName != fn ) - { - RemoveLibraryPath( m_projectFileName.GetPath() ); - InsertLibraryPath( fn.GetPath(), 0 ); - m_projectFileName = fn; - } - - // Init local config filename - if( ForceUseLocalConfig || fn.FileExists() ) - { - m_CurrentOptionFile = fn.GetFullPath(); - m_projectSettings = new wxFileConfig( wxEmptyString, wxEmptyString, - m_CurrentOptionFile, wxEmptyString ); - m_projectSettings->DontCreateOnDemand(); - - if( ForceUseLocalConfig ) - return true; - - /* Check the application version against the version saved in the - * project file. - * - * TODO: Push the version test up the stack so that when one of the - * KiCad application version changes, the other applications - * settings do not get updated. Practically, this can go away. - * It isn't used anywhere as far as I know (WLS). - */ - int version = -1; - int def_version = 0; - - m_projectSettings->SetPath( GroupName ); - version = m_projectSettings->Read( wxT( "version" ), def_version ); - m_projectSettings->SetPath( wxCONFIG_PATH_SEPARATOR ); - - if( version > 0 ) - { - return true; - } - else - { - delete m_projectSettings; // Version incorrect - } - } - - wxString defaultFileName; - defaultFileName = m_libSearchPaths.FindValidPath( wxT( "kicad.pro" ) ); - - if( defaultFileName.IsEmpty() ) - { - wxLogDebug( wxT( "Template file not found." ) ); - fn = wxFileName( GetTraits()->GetStandardPaths().GetDocumentsDir(), - wxT( "kicad" ), ProjectFileExtension ); - } - else - { - fn = defaultFileName; - } - - // Create new project file using the default name. - m_CurrentOptionFile = fn.GetFullPath(); - m_projectSettings = new wxFileConfig( wxEmptyString, wxEmptyString, - wxEmptyString, fn.GetFullPath() ); - m_projectSettings->DontCreateOnDemand(); - - return false; -} - - -void EDA_APP::WriteProjectConfig( const wxString& fileName, - const wxString& GroupName, - const PARAM_CFG_ARRAY& params ) -{ - ReCreatePrjConfig( fileName, GroupName, FORCE_LOCAL_CONFIG ); - - /* Write date ( surtout pour eviter bug de wxFileConfig - * qui se trompe de rubrique si declaration [xx] en premiere ligne - * (en fait si groupe vide) */ - m_projectSettings->SetPath( wxCONFIG_PATH_SEPARATOR ); - - m_projectSettings->Write( wxT( "update" ), DateAndTime() ); - m_projectSettings->Write( wxT( "last_client" ), GetAppName() ); - - /* Save parameters */ - m_projectSettings->DeleteGroup( GroupName ); // Erase all data - m_projectSettings->Flush(); - - m_projectSettings->SetPath( GroupName ); - m_projectSettings->Write( wxT( "version" ), CONFIG_VERSION ); - m_projectSettings->SetPath( wxCONFIG_PATH_SEPARATOR ); - - BOOST_FOREACH( const PARAM_CFG_BASE& param, params ) - { - if( param.m_Group ) - m_projectSettings->SetPath( param.m_Group ); - else - m_projectSettings->SetPath( GroupName ); - - if( param.m_Setup ) - continue; - - if ( param.m_Type == PARAM_COMMAND_ERASE ) // Erase all data - { - if( param.m_Ident ) - m_projectSettings->DeleteGroup( param.m_Ident ); - } - else - { - param.SaveParam( m_projectSettings ); - } - } - - m_projectSettings->SetPath( UNIX_STRING_DIR_SEP ); - - delete m_projectSettings; - m_projectSettings = NULL; -} - -void EDA_APP::SaveCurrentSetupValues( const PARAM_CFG_ARRAY& List ) -{ - if( m_settings == NULL ) - return; - - unsigned count = List.size(); - for( unsigned i=0; iDeleteGroup( param.m_Ident ); - } - else - { - param.SaveParam( m_settings ); - } - } -} - -bool EDA_APP::ReadProjectConfig( const wxString& local_config_filename, - const wxString& GroupName, - const PARAM_CFG_ARRAY& params, - bool Load_Only_if_New ) -{ - ReCreatePrjConfig( local_config_filename, GroupName, false ); - - m_projectSettings->SetPath( wxCONFIG_PATH_SEPARATOR ); - wxString timestamp = m_projectSettings->Read( wxT( "update" ) ); - - if( Load_Only_if_New && ( !timestamp.IsEmpty() ) - && (timestamp == m_CurrentOptionFileDateAndTime) ) - { - return false; - } - - m_CurrentOptionFileDateAndTime = timestamp; - - BOOST_FOREACH( const PARAM_CFG_BASE& param, params ) - { - if( param.m_Group ) - m_projectSettings->SetPath( param.m_Group ); - else - m_projectSettings->SetPath( GroupName ); - - if( param.m_Setup ) - continue; - - param.ReadParam( m_projectSettings ); - } - - delete m_projectSettings; - m_projectSettings = NULL; - - return true; -} - - -void EDA_APP::ReadCurrentSetupValues( const PARAM_CFG_ARRAY& List ) -{ - BOOST_FOREACH( const PARAM_CFG_BASE& param, List ) - { - if( param.m_Setup == false ) - continue; - - param.ReadParam( m_settings ); - } -} - - PARAM_CFG_BASE::PARAM_CFG_BASE( const wxChar* ident, const paramcfg_id type, const wxChar* group ) { @@ -286,7 +174,7 @@ PARAM_CFG_INT::PARAM_CFG_INT( bool Insetup, const wxChar* ident, int* ptparam, void PARAM_CFG_INT::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; int itmp = aConfig->Read( m_Ident, m_Default ); @@ -300,7 +188,7 @@ void PARAM_CFG_INT::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_INT::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; aConfig->Write( m_Ident, *m_Pt_param ); @@ -330,7 +218,7 @@ PARAM_CFG_INT_WITH_SCALE::PARAM_CFG_INT_WITH_SCALE( bool Insetup, void PARAM_CFG_INT_WITH_SCALE::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; double dtmp = (double) m_Default * m_BIU_to_cfgunit; @@ -347,7 +235,7 @@ void PARAM_CFG_INT_WITH_SCALE::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_INT_WITH_SCALE::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; // We cannot use aConfig->Write for a double, because @@ -383,8 +271,9 @@ PARAM_CFG_SETCOLOR::PARAM_CFG_SETCOLOR( bool Insetup, void PARAM_CFG_SETCOLOR::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; + EDA_COLOR_T itmp = ColorByName( aConfig->Read( m_Ident, wxT("NONE") ) ); if( itmp == UNSPECIFIED_COLOR ) @@ -395,7 +284,7 @@ void PARAM_CFG_SETCOLOR::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_SETCOLOR::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; aConfig->Write( m_Ident, ColorGetName( *m_Pt_param ) ); @@ -433,7 +322,7 @@ PARAM_CFG_DOUBLE::PARAM_CFG_DOUBLE( bool Insetup, void PARAM_CFG_DOUBLE::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; double dtmp = m_Default; @@ -448,7 +337,7 @@ void PARAM_CFG_DOUBLE::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_DOUBLE::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; // We cannot use aConfig->Write for a double, because @@ -483,7 +372,7 @@ PARAM_CFG_BOOL::PARAM_CFG_BOOL( bool Insetup, void PARAM_CFG_BOOL::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; int itmp = aConfig->Read( m_Ident, (int) m_Default ); @@ -494,7 +383,7 @@ void PARAM_CFG_BOOL::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_BOOL::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; aConfig->Write( m_Ident, *m_Pt_param ); @@ -524,22 +413,22 @@ PARAM_CFG_WXSTRING::PARAM_CFG_WXSTRING( bool Insetup, const wxChar* ident, void PARAM_CFG_WXSTRING::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; + *m_Pt_param = aConfig->Read( m_Ident, m_default ); } void PARAM_CFG_WXSTRING::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; aConfig->Write( m_Ident, *m_Pt_param ); } - PARAM_CFG_FILENAME::PARAM_CFG_FILENAME( const wxChar* ident, wxString* ptparam, const wxChar* group ) : @@ -551,7 +440,7 @@ PARAM_CFG_FILENAME::PARAM_CFG_FILENAME( const wxChar* ident, void PARAM_CFG_FILENAME::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; wxString prm = aConfig->Read( m_Ident ); @@ -567,7 +456,7 @@ void PARAM_CFG_FILENAME::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_FILENAME::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; wxString prm = *m_Pt_param; @@ -588,7 +477,7 @@ PARAM_CFG_LIBNAME_LIST::PARAM_CFG_LIBNAME_LIST( const wxChar* ident, void PARAM_CFG_LIBNAME_LIST::ReadParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; int indexlib = 1; // We start indexlib to 1 because first @@ -617,15 +506,15 @@ void PARAM_CFG_LIBNAME_LIST::ReadParam( wxConfigBase* aConfig ) const void PARAM_CFG_LIBNAME_LIST::SaveParam( wxConfigBase* aConfig ) const { - if( m_Pt_param == NULL || aConfig == NULL ) + if( !m_Pt_param || !aConfig ) return; + wxArrayString* libname_list = m_Pt_param; - unsigned indexlib = 0; wxString configkey; wxString libname; - for( ; indexlib < libname_list->GetCount(); indexlib++ ) + for( unsigned indexlib = 0; indexlib < libname_list->GetCount(); indexlib++ ) { configkey = m_Ident; diff --git a/common/copy_to_clipboard.cpp b/common/copy_to_clipboard.cpp index 4f3130b7f7..5e710d81a7 100644 --- a/common/copy_to_clipboard.cpp +++ b/common/copy_to_clipboard.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include static bool DrawPageOnClipboard( EDA_DRAW_FRAME* aFrame ); diff --git a/common/dialog_about/AboutDialog_main.cpp b/common/dialog_about/AboutDialog_main.cpp index d66561fe5d..e32b0a4dd5 100644 --- a/common/dialog_about/AboutDialog_main.cpp +++ b/common/dialog_about/AboutDialog_main.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include @@ -41,7 +41,7 @@ static wxString HtmlNewline( const unsigned int amount = 1 ); static void InitKiCadAboutNew( AboutAppInfo& info ) { // Set application specific icon - const wxTopLevelWindow * const tlw = wxDynamicCast(::wxGetApp().GetTopWindow(), wxTopLevelWindow); + const wxTopLevelWindow* const tlw = wxDynamicCast( Pgm().App().GetTopWindow(), wxTopLevelWindow); if( tlw ) info.SetIcon( tlw->GetIcon() ); @@ -56,10 +56,10 @@ static void InitKiCadAboutNew( AboutAppInfo& info ) } /* Set title */ - info.SetAppName( wxT( ".: " ) + wxGetApp().GetTitle() + wxT( " :." ) ); + info.SetAppName( wxT( ".: " ) + Pgm().App().GetAppName() + wxT( " :." ) ); /* Copyright information */ - info.SetCopyright( wxT( "(C) 1992-2013 KiCad Developers Team" ) ); + info.SetCopyright( wxT( "(C) 1992-2014 KiCad Developers Team" ) ); /* KiCad build version */ wxString version; diff --git a/common/dialog_shim.cpp b/common/dialog_shim.cpp index 1d50a08908..354444c4ff 100644 --- a/common/dialog_shim.cpp +++ b/common/dialog_shim.cpp @@ -24,12 +24,22 @@ */ #include - +#include DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : - wxDialog( aParent, id, title, pos, size, style, name ) + wxDialog( aParent, id, title, pos, size, style, name ), + KIWAY_HOLDER( 0 ) { + // pray that aParent is either a KIWAY_PLAYER or DIALOG_SHIM derivation. + KIWAY_HOLDER* h = dynamic_cast( aParent ); + + wxASSERT_MSG( h, + wxT( "DIALOG_SHIM's parent not derived from KIWAY_PLAYER nor DIALOG_SHIM" ) ); + + if( h ) + SetKiway( this, &h->Kiway() ); + #if DLGSHIM_USE_SETFOCUS Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_SHIM::onInit ) ); #endif diff --git a/common/dialogs/dialog_get_component.cpp b/common/dialogs/dialog_get_component.cpp index 0fddd7f992..c0516bb5ba 100644 --- a/common/dialogs/dialog_get_component.cpp +++ b/common/dialogs/dialog_get_component.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include diff --git a/common/dialogs/dialog_hotkeys_editor.cpp b/common/dialogs/dialog_hotkeys_editor.cpp index a1457febca..bb3b85f523 100644 --- a/common/dialogs/dialog_hotkeys_editor.cpp +++ b/common/dialogs/dialog_hotkeys_editor.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include @@ -202,7 +202,7 @@ void HOTKEYS_EDITOR_DIALOG::OnRightClickOnCell( wxGridEvent& event ) wxString keyname = wxGetSingleChoice( _( "Special keys only. For others keys, use keyboard" ), _( "Select a key" ), C_COUNT, choices, this ); - int key = ReturnKeyCodeFromKeyName( keyname ); + int key = KeyCodeFromKeyName( keyname ); if( key == 0 ) return; @@ -251,7 +251,7 @@ void HOTKEYS_EDITOR_DIALOG::OnKeyPressed( wxKeyEvent& event ) #endif // See if this key code is handled in hotkeys names list bool exists; - ReturnKeyNameFromKeyCode( key, &exists ); + KeyNameFromKeyCode( key, &exists ); if( !exists ) // not handled, see hotkeys_basic.cpp { diff --git a/common/dialogs/dialog_page_settings.cpp b/common/dialogs/dialog_page_settings.cpp index bbd6cd967f..a56261f048 100644 --- a/common/dialogs/dialog_page_settings.cpp +++ b/common/dialogs/dialog_page_settings.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/common/displlst.cpp b/common/displlst.cpp index 1717f2a0f8..e78a72eac8 100644 --- a/common/displlst.cpp +++ b/common/displlst.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/common/drawframe.cpp b/common/draw_frame.cpp similarity index 96% rename from common/drawframe.cpp rename to common/draw_frame.cpp index 5820bed89b..13fc21d68a 100644 --- a/common/drawframe.cpp +++ b/common/draw_frame.cpp @@ -28,7 +28,8 @@ */ #include -#include +#include +#include #include #include #include @@ -38,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -88,12 +89,12 @@ BEGIN_EVENT_TABLE( EDA_DRAW_FRAME, EDA_BASE_FRAME ) END_EVENT_TABLE() -EDA_DRAW_FRAME::EDA_DRAW_FRAME( wxWindow* aParent, +EDA_DRAW_FRAME::EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, long aStyle, const wxString & aFrameName ) : - EDA_BASE_FRAME( aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ) + KIWAY_PLAYER( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ) { m_drawToolBar = NULL; m_optionsToolBar = NULL; @@ -531,7 +532,7 @@ wxPoint EDA_DRAW_FRAME::GetGridPosition( const wxPoint& aPosition ) const } -int EDA_DRAW_FRAME::ReturnBlockCommand( int key ) +int EDA_DRAW_FRAME::BlockCommand( int key ) { return 0; } @@ -582,25 +583,21 @@ void EDA_DRAW_FRAME::UpdateStatusBar() } -void EDA_DRAW_FRAME::LoadSettings() +void EDA_DRAW_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); + EDA_BASE_FRAME::LoadSettings( aCfg ); - wxConfig* cfg = wxGetApp().GetSettings(); + aCfg->Read( m_FrameName + CursorShapeEntryKeyword, &m_cursorShape, ( long )0 ); - EDA_BASE_FRAME::LoadSettings(); - cfg->Read( m_FrameName + CursorShapeEntryKeyword, &m_cursorShape, ( long )0 ); bool btmp; - - if ( cfg->Read( m_FrameName + ShowGridEntryKeyword, &btmp ) ) + if( aCfg->Read( m_FrameName + ShowGridEntryKeyword, &btmp ) ) SetGridVisibility( btmp ); int itmp; - - if( cfg->Read( m_FrameName + GridColorEntryKeyword, &itmp ) ) + if( aCfg->Read( m_FrameName + GridColorEntryKeyword, &itmp ) ) SetGridColor( ColorFromInt( itmp ) ); - cfg->Read( m_FrameName + LastGridSizeIdKeyword, &m_LastGridSizeId, 0L ); + aCfg->Read( m_FrameName + LastGridSizeIdKeyword, &m_LastGridSizeId, 0L ); // m_LastGridSizeId is an offset, expected to be >= 0 if( m_LastGridSizeId < 0 ) @@ -608,17 +605,14 @@ void EDA_DRAW_FRAME::LoadSettings() } -void EDA_DRAW_FRAME::SaveSettings() +void EDA_DRAW_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); + EDA_BASE_FRAME::SaveSettings( aCfg ); - wxConfig* cfg = wxGetApp().GetSettings(); - - EDA_BASE_FRAME::SaveSettings(); - cfg->Write( m_FrameName + CursorShapeEntryKeyword, m_cursorShape ); - cfg->Write( m_FrameName + ShowGridEntryKeyword, IsGridVisible() ); - cfg->Write( m_FrameName + GridColorEntryKeyword, ( long ) GetGridColor() ); - cfg->Write( m_FrameName + LastGridSizeIdKeyword, ( long ) m_LastGridSizeId ); + aCfg->Write( m_FrameName + CursorShapeEntryKeyword, m_cursorShape ); + aCfg->Write( m_FrameName + ShowGridEntryKeyword, IsGridVisible() ); + aCfg->Write( m_FrameName + GridColorEntryKeyword, ( long ) GetGridColor() ); + aCfg->Write( m_FrameName + LastGridSizeIdKeyword, ( long ) m_LastGridSizeId ); } @@ -682,7 +676,7 @@ bool EDA_DRAW_FRAME::HandleBlockBegin( wxDC* aDC, int aKey, const wxPoint& aPosi if( ( Block->GetCommand() != BLOCK_IDLE ) || ( Block->GetState() != STATE_NO_BLOCK ) ) return false; - Block->SetCommand( (BLOCK_COMMAND_T) ReturnBlockCommand( aKey ) ); + Block->SetCommand( (BLOCK_COMMAND_T) BlockCommand( aKey ) ); if( Block->GetCommand() == 0 ) return false; diff --git a/common/drawpanel.cpp b/common/draw_panel.cpp similarity index 97% rename from common/drawpanel.cpp rename to common/draw_panel.cpp index a055fb83b8..1e3adb750b 100644 --- a/common/drawpanel.cpp +++ b/common/draw_panel.cpp @@ -28,7 +28,8 @@ */ #include -#include +#include +#include #include #include #include @@ -36,7 +37,7 @@ #include #include #include -#include +#include #include @@ -45,16 +46,17 @@ static const int CURSOR_SIZE = 12; ///< Cursor size in pixels #define CLIP_BOX_PADDING 2 // keys to store options in config: -#define ENBL_ZOOM_NO_CENTER_KEY wxT( "ZoomNoCenter" ) -#define ENBL_MIDDLE_BUTT_PAN_KEY wxT( "MiddleButtonPAN" ) -#define MIDDLE_BUTT_PAN_LIMITED_KEY wxT( "MiddleBtnPANLimited" ) -#define ENBL_AUTO_PAN_KEY wxT( "AutoPAN" ) +#define ENBL_ZOOM_NO_CENTER_KEY wxT( "ZoomNoCenter" ) +#define ENBL_MIDDLE_BUTT_PAN_KEY wxT( "MiddleButtonPAN" ) +#define MIDDLE_BUTT_PAN_LIMITED_KEY wxT( "MiddleBtnPANLimited" ) +#define ENBL_AUTO_PAN_KEY wxT( "AutoPAN" ) -/* Definitions for enabling and disabling debugging features in drawpanel.cpp. - * Please don't forget to turn these off before making any commits to Launchpad. - */ + +// Definitions for enabling and disabling debugging features in drawpanel.cpp. +// Please don't forget to turn these off before making any commits to Launchpad. #define DEBUG_SHOW_CLIP_RECT 0 // Set to 1 to draw clipping rectangle. + /** * Trace mask used to enable or disable the trace output of coordinates during drawing * functions. The coordinate dumping can be turned on by setting the WXTRACE environment @@ -122,12 +124,14 @@ EDA_DRAW_PANEL::EDA_DRAW_PANEL( EDA_DRAW_FRAME* parent, int id, m_mouseCaptureCallback = NULL; m_endMouseCaptureCallback = NULL; - if( wxGetApp().GetSettings() ) + wxConfigBase* cfg = Kiface().KifaceSettings(); + + if( cfg ) { - wxGetApp().GetSettings()->Read( ENBL_MIDDLE_BUTT_PAN_KEY, &m_enableMiddleButtonPan, false ); - wxGetApp().GetSettings()->Read( ENBL_ZOOM_NO_CENTER_KEY, &m_enableZoomNoCenter, false ); - wxGetApp().GetSettings()->Read( MIDDLE_BUTT_PAN_LIMITED_KEY, &m_panScrollbarLimits, false ); - wxGetApp().GetSettings()->Read( ENBL_AUTO_PAN_KEY, &m_enableAutoPan, true ); + cfg->Read( ENBL_MIDDLE_BUTT_PAN_KEY, &m_enableMiddleButtonPan, false ); + cfg->Read( ENBL_ZOOM_NO_CENTER_KEY, &m_enableZoomNoCenter, false ); + cfg->Read( MIDDLE_BUTT_PAN_LIMITED_KEY, &m_panScrollbarLimits, false ); + cfg->Read( ENBL_AUTO_PAN_KEY, &m_enableAutoPan, true ); } m_requestAutoPan = false; @@ -149,10 +153,15 @@ EDA_DRAW_PANEL::EDA_DRAW_PANEL( EDA_DRAW_FRAME* parent, int id, EDA_DRAW_PANEL::~EDA_DRAW_PANEL() { - wxGetApp().GetSettings()->Write( ENBL_MIDDLE_BUTT_PAN_KEY, m_enableMiddleButtonPan ); - wxGetApp().GetSettings()->Write( ENBL_ZOOM_NO_CENTER_KEY, m_enableZoomNoCenter ); - wxGetApp().GetSettings()->Write( MIDDLE_BUTT_PAN_LIMITED_KEY, m_panScrollbarLimits ); - wxGetApp().GetSettings()->Write( ENBL_AUTO_PAN_KEY, m_enableAutoPan ); + wxConfigBase* cfg = Kiface().KifaceSettings(); + + if( cfg ) + { + cfg->Write( ENBL_MIDDLE_BUTT_PAN_KEY, m_enableMiddleButtonPan ); + cfg->Write( ENBL_ZOOM_NO_CENTER_KEY, m_enableZoomNoCenter ); + cfg->Write( MIDDLE_BUTT_PAN_LIMITED_KEY, m_panScrollbarLimits ); + cfg->Write( ENBL_AUTO_PAN_KEY, m_enableAutoPan ); + } } diff --git a/common/drawtxt.cpp b/common/drawtxt.cpp index 29286be5b4..33c79529b0 100644 --- a/common/drawtxt.cpp +++ b/common/drawtxt.cpp @@ -161,7 +161,7 @@ static const char* GetHersheyShapeDescription( int AsciiCode ) } -int ReturnGraphicTextWidth( const wxString& aText, int aXSize, bool aItalic, bool aWidth ) +int GraphicTextWidth( const wxString& aText, int aXSize, bool aItalic, bool aWidth ) { int tally = 0; int char_count = aText.length(); @@ -315,7 +315,7 @@ void DrawGraphicText( EDA_RECT* aClipBox, current_char_pos = aPos; - dx = ReturnGraphicTextWidth( aText, size_h, aItalic, aWidth ); + dx = GraphicTextWidth( aText, size_h, aItalic, aWidth ); dy = size_v; /* Do not draw the text if out of draw area! */ diff --git a/common/eda_dde.cpp b/common/eda_dde.cpp index 8fd540433f..b00cc11cad 100644 --- a/common/eda_dde.cpp +++ b/common/eda_dde.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/common/eda_doc.cpp b/common/eda_doc.cpp index 495359cf06..11374c9dff 100644 --- a/common/eda_doc.cpp +++ b/common/eda_doc.cpp @@ -3,7 +3,7 @@ */ #include -#include +#include #include #include #include @@ -14,19 +14,20 @@ #include -void EDA_APP::ReadPdfBrowserInfos() +void PGM_BASE::ReadPdfBrowserInfos() { - wxASSERT( m_commonSettings != NULL ); + wxASSERT( m_common_settings ); - m_PdfBrowser = m_commonSettings->Read( wxT( "PdfBrowserName" ), wxEmptyString ); + wxString browser = m_common_settings->Read( wxT( "PdfBrowserName" ), wxEmptyString ); + SetPdfBrowserName( browser ); } -void EDA_APP::WritePdfBrowserInfos() +void PGM_BASE::WritePdfBrowserInfos() { - wxASSERT( m_commonSettings != NULL ); + wxASSERT( m_common_settings ); - m_commonSettings->Write( wxT( "PdfBrowserName" ), m_PdfBrowser ); + m_common_settings->Write( wxT( "PdfBrowserName" ), GetPdfBrowserName() ); } @@ -122,7 +123,7 @@ bool GetAssociatedDocument( wxFrame* aFrame, if( !wxFileExists( fullfilename ) ) { - msg.Printf( _( "Doc File <%s> not found" ), GetChars( aDocName ) ); + msg.Printf( _( "Doc File '%s' not found" ), GetChars( aDocName ) ); DisplayError( aFrame, msg ); return false; } diff --git a/common/eda_text.cpp b/common/eda_text.cpp index 35983951af..97da020d55 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -94,7 +94,7 @@ EDA_TEXT::~EDA_TEXT() int EDA_TEXT::LenSize( const wxString& aLine ) const { - return ReturnGraphicTextWidth( aLine, m_Size.x, m_Italic, m_Bold ); + return GraphicTextWidth( aLine, m_Size.x, m_Italic, m_Bold ); } /** diff --git a/common/edaappl.cpp b/common/edaappl.cpp deleted file mode 100644 index a512c0dc84..0000000000 --- a/common/edaappl.cpp +++ /dev/null @@ -1,1197 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com - * Copyright (C) 2008-2011 Wayne Stambaugh - * Copyright (C) 1992-2011 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 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file edaappl.cpp - * - * @brief For the main application: init functions, and language selection - * (locale handling) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static const wxChar* CommonConfigPath = wxT( "kicad_common" ); - - -// some key strings used to store parameters in config -static const wxChar backgroundColorKey[] = wxT( "BackgroundColor" ); -static const wxChar showPageLimitsKey[] = wxT( "ShowPageLimits" ); -static const wxChar workingDirKey[] = wxT( "WorkingDir" ); -static const wxChar languageCfgKey[] = wxT( "LanguageID" ); -static const wxChar kicadFpLibPath[] = wxT( "KicadFootprintLibraryPath" ); - - -/** - * A small class to handle the list of existing translations. - * The locale translation is automatic. - * The selection of languages is mainly for maintainer's convenience - * To add a support to a new translation: - * create a new icon (flag of the country) (see Lang_Fr.xpm as an example) - * add a new item to s_Languages[]. - */ -struct LANGUAGE_DESCR -{ - /// wxWidgets locale identifier (See wxWidgets doc) - int m_WX_Lang_Identifier; - - /// KiCad identifier used in menu selection (See id.h) - int m_KI_Lang_Identifier; - - /// The menu language icons - BITMAP_DEF m_Lang_Icon; - - /// Labels used in menus - wxString m_Lang_Label; - - /// Set to true if the m_Lang_Label must not be translated - bool m_DoNotTranslate; -}; - - -/** - * Variable s_Languages - * Note: because this list is not created on the fly, wxTranslation - * must be called when a language name must be displayed after translation. - * Do not change this behavior, because m_Lang_Label is also used as key in config - */ -static LANGUAGE_DESCR s_Languages[] = -{ - // Default language - { - wxLANGUAGE_DEFAULT, - ID_LANGUAGE_DEFAULT, - lang_def_xpm, - _( "Default" ) - }, - - // English language - { - wxLANGUAGE_ENGLISH, - ID_LANGUAGE_ENGLISH, - lang_en_xpm, - wxT( "English" ), - true - }, - - // French language - { - wxLANGUAGE_FRENCH, - ID_LANGUAGE_FRENCH, - lang_fr_xpm, - _( "French" ) - }, - - // Finnish language - { - wxLANGUAGE_FINNISH, - ID_LANGUAGE_FINNISH, - lang_fi_xpm, - _( "Finnish" ) - }, - - // Spanish language - { - wxLANGUAGE_SPANISH, - ID_LANGUAGE_SPANISH, - lang_es_xpm, - _( "Spanish" ) - }, - - // Portuguese language - { - wxLANGUAGE_PORTUGUESE, - ID_LANGUAGE_PORTUGUESE, - lang_pt_xpm, - _( "Portuguese" ) - }, - - // Italian language - { - wxLANGUAGE_ITALIAN, - ID_LANGUAGE_ITALIAN, - lang_it_xpm, - _( "Italian" ) - }, - - // German language - { - wxLANGUAGE_GERMAN, - ID_LANGUAGE_GERMAN, - lang_de_xpm, - _( "German" ) - }, - - // Greek language - { - wxLANGUAGE_GREEK, - ID_LANGUAGE_GREEK, - lang_gr_xpm, - _( "Greek" ) - }, - - // Slovenian language - { - wxLANGUAGE_SLOVENIAN, - ID_LANGUAGE_SLOVENIAN, - lang_sl_xpm, - _( "Slovenian" ) - }, - - // Hungarian language - { - wxLANGUAGE_HUNGARIAN, - ID_LANGUAGE_HUNGARIAN, - lang_hu_xpm, - _( "Hungarian" ) - }, - - // Polish language - { - wxLANGUAGE_POLISH, - ID_LANGUAGE_POLISH, - lang_pl_xpm, - _( "Polish" ) - }, - - // Czech language - { - wxLANGUAGE_CZECH, - ID_LANGUAGE_CZECH, - lang_cs_xpm, - _( "Czech" ) - }, - - // Russian language - { - wxLANGUAGE_RUSSIAN, - ID_LANGUAGE_RUSSIAN, - lang_ru_xpm, - _( "Russian" ) - }, - - // Korean language - { - wxLANGUAGE_KOREAN, - ID_LANGUAGE_KOREAN, - lang_ko_xpm, - _( "Korean" ) - }, - - // Chinese simplified - { - wxLANGUAGE_CHINESE_SIMPLIFIED, - ID_LANGUAGE_CHINESE_SIMPLIFIED, - lang_chinese_xpm, - _( "Chinese simplified" ) - }, - - // Catalan language - { - wxLANGUAGE_CATALAN, - ID_LANGUAGE_CATALAN, - lang_catalan_xpm, - _( "Catalan" ) - }, - - // Dutch language - { - wxLANGUAGE_DUTCH, - ID_LANGUAGE_DUTCH, - lang_nl_xpm, - _( "Dutch" ) - }, - - // Japanese language - { - wxLANGUAGE_JAPANESE, - ID_LANGUAGE_JAPANESE, - lang_jp_xpm, - _( "Japanese" ) - }, - - // Bulgarian language - { - wxLANGUAGE_BULGARIAN, - ID_LANGUAGE_BULGARIAN, - lang_bg_xpm, - _( "Bulgarian" ) - } -}; - - -EDA_APP::EDA_APP() -{ - m_Checker = NULL; - m_oneInstancePerFileChecker = NULL; - m_HtmlCtrl = NULL; - m_settings = NULL; - setLanguageId( wxLANGUAGE_DEFAULT ); - m_Locale = NULL; - m_projectSettings = NULL; - m_commonSettings = NULL; -} - - -EDA_APP::~EDA_APP() -{ - SaveSettings(); - - // delete user datas - delete m_projectSettings; - delete m_commonSettings; - delete m_settings; - delete m_Checker; - delete m_oneInstancePerFileChecker; - delete m_Locale; -} - - -void EDA_APP::InitEDA_Appl( const wxString& aName, EDA_APP_T aId ) -{ - m_Id = aId; - m_Checker = new wxSingleInstanceChecker( aName.Lower() + wxT( "-" ) + wxGetUserId() ); - - // Init KiCad environment - // the environment variable KICAD (if exists) gives the kicad path: - // something like set KICAD=d:\kicad - bool isDefined = wxGetEnv( wxT( "KICAD" ), &m_KicadEnv ); - - if( isDefined ) // ensure m_KicadEnv ends by "/" - { - m_KicadEnv.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); - - if( !m_KicadEnv.IsEmpty() && m_KicadEnv.Last() != '/' ) - m_KicadEnv += UNIX_STRING_DIR_SEP; - } - - // Prepare On Line Help. Use only lower case for help file names, in order to - // avoid problems with upper/lower case file names under windows and unix. -#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML - m_HelpFileName = aName.Lower() + wxT( ".html" ); -#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF - m_HelpFileName = aName.Lower() + wxT( ".pdf" ); -#else - #error Help files format not defined -#endif - - // Init parameters for configuration - SetVendorName( wxT( "KiCad" ) ); - SetAppName( aName.Lower() ); - SetTitle( aName ); - - m_settings = new wxConfig(); - - wxASSERT( m_settings != NULL ); - - m_commonSettings = new wxConfig( CommonConfigPath ); - wxASSERT( m_commonSettings != NULL ); - - // Install some image handlers, mainly for help - wxImage::AddHandler( new wxPNGHandler ); - wxImage::AddHandler( new wxGIFHandler ); - wxImage::AddHandler( new wxJPEGHandler ); - wxFileSystem::AddHandler( new wxZipFSHandler ); - - // Analyze the command line & init binary path - SetBinDir(); - SetDefaultSearchPaths(); - SetLanguagePath(); - ReadPdfBrowserInfos(); - - // Internationalization: loading the kicad suitable Dictionary - wxString languageSel; - m_commonSettings->Read( languageCfgKey, &languageSel); - - setLanguageId( wxLANGUAGE_DEFAULT ); - - // Search for the current selection - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - if( s_Languages[ii].m_Lang_Label == languageSel ) - { - setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); - break; - } - } - - bool succes = SetLanguage( true ); - - if( !succes ) - { - } - - // Set locale option for separator used in float numbers - SetLocaleTo_Default(); -} - - -void EDA_APP::SetHtmlHelpController( wxHtmlHelpController* aController ) -{ - delete m_HtmlCtrl; - - m_HtmlCtrl = aController; -} - - -void EDA_APP::InitOnLineHelp() -{ - wxString fullfilename = FindKicadHelpPath(); - -#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML - m_HelpFileName = fullfilename + wxT( ".html" ); - fullfilename += wxT( "kicad.hhp" ); - - if( wxFileExists( fullfilename ) ) - { - m_HtmlCtrl = new wxHtmlHelpController( wxHF_TOOLBAR | wxHF_CONTENTS | - wxHF_PRINT | wxHF_OPEN_FILES - /*| wxHF_SEARCH */ ); - m_HtmlCtrl->UseConfig( m_commonSettings ); - m_HtmlCtrl->SetTitleFormat( wxT( "KiCad Help" ) ); - m_HtmlCtrl->AddBook( fullfilename ); - } - -#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF - m_HtmlCtrl = NULL; - -#else - #error Help files format not defined -#endif -} - - -bool EDA_APP::SetBinDir() -{ -// Apple MacOSx -#ifdef __APPLE__ - - // Derive path from location of the app bundle - CFBundleRef mainBundle = CFBundleGetMainBundle(); - - if( mainBundle == NULL ) - return false; - - CFURLRef urlref = CFBundleCopyBundleURL( mainBundle ); - - if( urlref == NULL ) - return false; - - CFStringRef str = CFURLCopyFileSystemPath( urlref, kCFURLPOSIXPathStyle ); - - if( str == NULL ) - return false; - - char* native_str = NULL; - int len = CFStringGetMaximumSizeForEncoding( CFStringGetLength( str ), - kCFStringEncodingUTF8 ) + 1; - native_str = new char[len]; - - CFStringGetCString( str, native_str, len, kCFStringEncodingUTF8 ); - m_BinDir = FROM_UTF8( native_str ); - delete[] native_str; - -#elif defined(__UNIX__) // Linux and non-Apple Unix - m_BinDir = wxStandardPaths::Get().GetExecutablePath(); - -#else - m_BinDir = argv[0]; -#endif - - // Use unix notation for paths. I am not sure this is a good idea, - // but it simplifies compatibility between Windows and Unices. - // However it is a potential problem in path handling under Windows. - m_BinDir.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); - - // Remove file name form command line: - while( m_BinDir.Last() != '/' && !m_BinDir.IsEmpty() ) - m_BinDir.RemoveLast(); - - return true; -} - - -void EDA_APP::SetDefaultSearchPaths() -{ - wxString path = m_BinDir; - wxPathList tmp; - - m_searchPaths.Clear(); - -#ifdef __WINDOWS__ - - /* m_BinDir path is in unix notation. - * But wxFileName expect (to work fine) native notation - * specifically when using a path including a server, like - * \\myserver\local_path . - */ - path.Replace( UNIX_STRING_DIR_SEP, WIN_STRING_DIR_SEP ); - -#endif - wxFileName fn( path, wxEmptyString ); - - /* User environment variable path is the first search path. Chances are - * if the user is savvy enough to set an environment variable they know - * what they are doing. */ - if( ::wxGetEnv( wxT( "KICAD" ), NULL ) ) - tmp.AddEnvList( wxT( "KICAD" ) ); - - // Add the user's home path. - tmp.Add( GetTraits()->GetStandardPaths().GetUserDataDir() ); - - // Standard application data path if it is different from the binary path. - if( fn.GetPath() != GetTraits()->GetStandardPaths().GetDataDir() ) - { - tmp.Add( GetTraits()->GetStandardPaths().GetDataDir() ); - } - - // Up one level relative to binary path with "share" appended for Windows. - fn.RemoveLastDir(); - tmp.Add( fn.GetPath() ); - - /* The normal OS program file install paths allow for binary to be - * installed in a different path from the library files. This is - * useful for development purposes so the library and documentation - * files do not need to be installed separately. If someone can - * figure out a way to implement this without #ifdef, please do. - */ -#ifdef __WXMSW__ - tmp.AddEnvList( wxT( "PROGRAMFILES" ) ); -#elif __WXMAC__ - tmp.Add( wxString( wxGetenv( wxT( "HOME" ) ) ) + wxT( "/Library/Application Support" ) ); - tmp.Add( wxT( "/Library/Application Support" ) ); -#else - tmp.AddEnvList( wxT( "PATH" ) ); -#endif - - // This is the equivalent of CMAKE_INSTALL_PREFIX. Useful when installed by `make install`. - tmp.Add( wxT( DEFAULT_INSTALL_PATH ) ); - - // Add kicad, kicad/share, share, and share/kicad to each possible base path. - for( unsigned i = 0; i < tmp.GetCount(); i++ ) - { - fn = wxFileName( tmp[i], wxEmptyString ); - - if( fn.GetPath().AfterLast( fn.GetPathSeparator() ) == wxT( "bin" ) ) - fn.RemoveLastDir(); - - m_searchPaths.Add( fn.GetPath() ); - fn.AppendDir( wxT( "kicad" ) ); - m_searchPaths.Add( fn.GetPath() ); - fn.AppendDir( wxT( "share" ) ); - m_searchPaths.Add( fn.GetPath() ); - fn.RemoveLastDir(); - fn.RemoveLastDir(); - fn.AppendDir( wxT( "share" ) ); - m_searchPaths.Add( fn.GetPath() ); - fn.AppendDir( wxT( "kicad" ) ); - m_searchPaths.Add( fn.GetPath() ); - } - - // Remove all non-existent paths from the list. - for( unsigned i = 0; i < m_searchPaths.GetCount(); i++ ) - { - if( !wxFileName::IsDirReadable( m_searchPaths[i] ) ) - { - m_searchPaths.RemoveAt( i ); - i -= 1; - } - else - { - fn.Clear(); - fn.SetPath( m_searchPaths[i] ); - - /* Add schematic library file path to search path list. - * we must add /library and /library/doc - */ - if( m_Id == APP_EESCHEMA_T ) - { - fn.AppendDir( wxT( "library" ) ); - - if( fn.IsDirReadable() ) - { - m_libSearchPaths.Add( fn.GetPath() ); - } - - // Add schematic doc file path (library/doc)to search path list. - fn.AppendDir( wxT( "doc" ) ); - - if( fn.IsDirReadable() ) - { - m_libSearchPaths.Add( fn.GetPath() ); - } - - fn.RemoveLastDir(); - fn.RemoveLastDir(); // point to - } - - // Add PCB library file path to search path list. - if( m_Id == APP_PCBNEW_T || m_Id == APP_CVPCB_T ) - { - fn.AppendDir( wxT( "modules" ) ); - - if( fn.IsDirReadable() ) - { - m_libSearchPaths.Add( fn.GetPath() ); - } - - // Add 3D module library file path to search path list. - fn.AppendDir( wxT( "packages3d" ) ); - - if( fn.IsDirReadable() ) - { - m_libSearchPaths.Add( fn.GetPath() ); - } - - fn.RemoveLastDir(); - fn.RemoveLastDir(); // point to - } - - // Add KiCad template file path to search path list. - fn.AppendDir( wxT( "template" ) ); - - if( fn.IsDirReadable() ) - { - m_libSearchPaths.Add( fn.GetPath() ); - } - - fn.RemoveLastDir(); - } - } - -#if 0 && defined( DEBUG ) - wxLogDebug( wxT( "Library search paths:" ) ); - - for( unsigned i = 0; i < m_libSearchPaths.GetCount(); i++ ) - wxLogDebug( wxT( " %s" ), GetChars( m_libSearchPaths[i] ) ); -#endif -} - - -void EDA_APP::GetSettings( bool aReopenLastUsedDirectory ) -{ - wxASSERT( m_settings != NULL && m_commonSettings != NULL ); - - m_HelpSize.x = 500; - m_HelpSize.y = 400; - - wxString languageSel; - - m_commonSettings->Read( languageCfgKey, &languageSel ); - setLanguageId( wxLANGUAGE_DEFAULT ); - - // Search for the current selection - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - if( s_Languages[ii].m_Lang_Label == languageSel ) - { - setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); - break; - } - } - - m_EditorName = m_commonSettings->Read( wxT( "Editor" ) ); - - m_fileHistory.Load( *m_settings ); - - m_settings->Read( showPageLimitsKey, &g_ShowPageLimits ); - - if( aReopenLastUsedDirectory ) - { - wxString dir; - - if( m_settings->Read( workingDirKey, &dir ) && wxDirExists( dir ) ) - { - wxSetWorkingDirectory( dir ); - } - } - - // FIXME OSX Mountain Lion (10.8) - // Seems that Read doesn't found anything and ColorFromInt Asserts - I'm unable to reproduce - // on 10.7 - // In general terms I think is better have a failsafe default than an uninit variable - int draw_bg_color = (int)BLACK; // Default for all apps but Eeschema - - if( m_Id == APP_EESCHEMA_T ) - draw_bg_color = (int)WHITE; // Default for Eeschema - - m_settings->Read( backgroundColorKey, &draw_bg_color ); - g_DrawBgColor = ColorFromInt( draw_bg_color ); - - // Load per-user search paths from settings file - - wxString upath; - int i = 1; - - while( 1 ) - { - upath = m_commonSettings->Read( - wxString::Format( wxT( "LibraryPath%d" ), i ), wxT( "" ) ); - - if( upath.IsSameAs( wxT( "" ) ) ) - break; - - m_libSearchPaths.Add( upath ); - i++; - } -} - - -void EDA_APP::SaveSettings() -{ - wxASSERT( m_settings != NULL ); - - m_settings->Write( showPageLimitsKey, g_ShowPageLimits ); - m_settings->Write( workingDirKey, wxGetCwd() ); - m_settings->Write( backgroundColorKey, (long) g_DrawBgColor ); - - // Save the file history list - m_fileHistory.Save( *m_settings ); -} - - -bool EDA_APP::SetLanguage( bool first_time ) -{ - bool retv = true; - - // dictionary file name without extend (full name is kicad.mo) - wxString DictionaryName( wxT( "kicad" ) ); - - delete m_Locale; - m_Locale = new wxLocale; - -#if wxCHECK_VERSION( 2, 9, 0 ) - if( !m_Locale->Init( m_LanguageId ) ) -#else - if( !m_Locale->Init( m_LanguageId, wxLOCALE_CONV_ENCODING ) ) -#endif - { - wxLogDebug( wxT( "This language is not supported by the system." ) ); - - setLanguageId( wxLANGUAGE_DEFAULT ); - delete m_Locale; - - m_Locale = new wxLocale; - m_Locale->Init(); - retv = false; - } - else if( !first_time ) - { - wxLogDebug( wxT( "Search for dictionary %s.mo in %s" ), - GetChars( DictionaryName ), GetChars( m_Locale->GetName() ) ); - } - - if( !first_time ) - { - wxString languageSel; - - // Search for the current selection - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - if( s_Languages[ii].m_WX_Lang_Identifier == m_LanguageId ) - { - languageSel = s_Languages[ii].m_Lang_Label; - break; - } - } - - m_commonSettings->Write( languageCfgKey, languageSel ); - } - - // Test if floating point notation is working (bug in cross compilation, using wine) - // Make a conversion double <=> string - double dtst = 0.5; - wxString msg; - - extern bool g_DisableFloatingPointLocalNotation; // See common.cpp - - g_DisableFloatingPointLocalNotation = false; - - msg << dtst; - double result; - msg.ToDouble( &result ); - - if( result != dtst ) // string to double encode/decode does not work! Bug detected - { - // Disable floating point localization: - g_DisableFloatingPointLocalNotation = true; - SetLocaleTo_C_standard( ); - } - - if( !m_Locale->IsLoaded( DictionaryName ) ) - m_Locale->AddCatalog( DictionaryName ); - - if( !retv ) - return retv; - - return m_Locale->IsOk(); -} - - -void EDA_APP::SetLanguageIdentifier( int menu_id ) -{ - wxLogDebug( wxT( "Select language ID %d from %zd possible languages." ), - menu_id, DIM( s_Languages ) ); - - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - if( menu_id == s_Languages[ii].m_KI_Lang_Identifier ) - { - setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); - break; - } - } -} - - -void EDA_APP::SetLanguagePath() -{ - // Add defined search paths to locale paths - if( !m_searchPaths.IsEmpty() ) - { - for( unsigned i = 0; i < m_searchPaths.GetCount(); i++ ) - { - wxFileName fn( m_searchPaths[i], wxEmptyString ); - - // Append path for Windows and unix KiCad pack install - fn.AppendDir( wxT( "share" ) ); - fn.AppendDir( wxT( "internat" ) ); - - if( fn.DirExists() ) - { - wxLogDebug( wxT( "Adding locale lookup path: " ) + fn.GetPath() ); - wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() ); - } - - // Append path for unix standard install - fn.RemoveLastDir(); - - // Append path for unix standard install - fn.AppendDir( wxT( "kicad" ) ); - fn.AppendDir( wxT( "internat" ) ); - - if( fn.DirExists() ) - { - wxLogDebug( wxT( "Adding locale lookup path: " ) + fn.GetPath() ); - wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() ); - } - } - } -} - - -void EDA_APP::AddMenuLanguageList( wxMenu* MasterMenu ) -{ - wxMenu* menu = NULL; - wxMenuItem* item; - - item = MasterMenu->FindItem( ID_LANGUAGE_CHOICE ); - - if( item ) // This menu exists, do nothing - return; - - menu = new wxMenu; - - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - wxString label; - - if( s_Languages[ii].m_DoNotTranslate ) - label = s_Languages[ii].m_Lang_Label; - else - label = wxGetTranslation( s_Languages[ii].m_Lang_Label ); - - AddMenuItem( menu, s_Languages[ii].m_KI_Lang_Identifier, - label, KiBitmap(s_Languages[ii].m_Lang_Icon ), - wxITEM_CHECK ); - } - - AddMenuItem( MasterMenu, menu, - ID_LANGUAGE_CHOICE, - _( "Language" ), - _( "Select application language (only for testing!)" ), - KiBitmap( language_xpm ) ); - - // Set Check mark on current selected language - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - if( m_LanguageId == s_Languages[ii].m_WX_Lang_Identifier ) - menu->Check( s_Languages[ii].m_KI_Lang_Identifier, true ); - else - menu->Check( s_Languages[ii].m_KI_Lang_Identifier, false ); - } -} - - -wxString EDA_APP::FindFileInSearchPaths( - const wxString& filename, const wxArrayString* subdirs ) -{ - size_t i, j; - wxFileName fn; - wxPathList paths; - - for( i = 0; i < m_searchPaths.GetCount(); i++ ) - { - fn = wxFileName( m_searchPaths[i], wxEmptyString ); - if( subdirs ) - { - for( j = 0; j < subdirs->GetCount(); j++ ) - fn.AppendDir( subdirs->Item( j ) ); - } - - if( fn.DirExists() ) - { - paths.Add( fn.GetPath() ); - } - } - - return paths.FindValidPath( filename ); -} - - -wxString EDA_APP::GetHelpFile() -{ - wxString fn; - wxArrayString subdirs, altsubdirs; - - /* FIXME: This is not the ideal way to handle this. Unfortunately, the - * CMake install paths seem to be a moving target so this crude - * hack solve the problem of install path differences between - * Windows and non-Windows platforms. */ - - // Partially fixed, but must be enhanced - - // Create subdir tree for "standard" linux distributions, when KiCad comes - // from a distribution files are in /usr/share/doc/kicad/help and binaries - // in /usr/bin or /usr/local/bin - subdirs.Add( wxT( "share" ) ); - subdirs.Add( _T( "doc" ) ); - subdirs.Add( wxT( "kicad" ) ); - subdirs.Add( _T( "help" ) ); - - // Create subdir tree for linux and Windows KiCad pack. - // Note the pack form under linux is also useful if a user wants to - // install KiCad to a server because there is only one path to mount - // or export (something like /usr/local/kicad). - // files are in /kicad/doc/help - // (often /usr/local/kicad/kicad/doc/help) - // /kicad/ is retrieved from m_BinDir - altsubdirs.Add( _T( "doc" ) ); - altsubdirs.Add( _T( "help" ) ); - - /* Search for a help file. - * we *must* find a help file. - * so help is searched in directories in this order: - * help/ like help/en_GB - * help/ like help/en - * help/en - */ - - // Step 1 : Try to find help file in help/ - subdirs.Add( m_Locale->GetCanonicalName() ); - altsubdirs.Add( m_Locale->GetCanonicalName() ); - - fn = FindFileInSearchPaths( m_HelpFileName, &altsubdirs ); - - if( !fn ) - fn = FindFileInSearchPaths( m_HelpFileName, &subdirs ); - - // Step 2 : if not found Try to find help file in help/ - if( !fn ) - { - subdirs.RemoveAt( subdirs.GetCount() - 1 ); - altsubdirs.RemoveAt( altsubdirs.GetCount() - 1 ); - - // wxLocale::GetName() does not return always the short name - subdirs.Add( m_Locale->GetName().BeforeLast( '_' ) ); - altsubdirs.Add( m_Locale->GetName().BeforeLast( '_' ) ); - - fn = FindFileInSearchPaths( m_HelpFileName, &altsubdirs ); - - if( !fn ) - fn = FindFileInSearchPaths( m_HelpFileName, &subdirs ); - } - - // Step 3 : if not found Try to find help file in help/en - if( !fn ) - { - subdirs.RemoveAt( subdirs.GetCount() - 1 ); - altsubdirs.RemoveAt( altsubdirs.GetCount() - 1 ); - subdirs.Add( _T( "en" ) ); - altsubdirs.Add( _T( "en" ) ); - - fn = FindFileInSearchPaths( m_HelpFileName, &altsubdirs ); - - if( !fn ) - fn = FindFileInSearchPaths( m_HelpFileName, &subdirs ); - } - - return fn; -} - - -wxString EDA_APP::ReturnLastVisitedLibraryPath( const wxString& aSubPathToSearch ) -{ - if( !m_LastVisitedLibPath.IsEmpty() ) - return m_LastVisitedLibPath; - - wxString path; - - /* Initialize default path to the main default lib path - * this is the second path in list (the first is the project path) - */ - unsigned pcount = m_libSearchPaths.GetCount(); - - if( pcount ) - { - unsigned ipath = 0; - - if( m_libSearchPaths[0] == wxGetCwd() ) - ipath = 1; - - // First choice of path: - if( ipath < pcount ) - path = m_libSearchPaths[ipath]; - - // Search a sub path matching aSubPathToSearch - if( !aSubPathToSearch.IsEmpty() ) - { - for( ; ipath < pcount; ipath++ ) - { - if( m_libSearchPaths[ipath].Contains( aSubPathToSearch ) ) - { - path = m_libSearchPaths[ipath]; - break; - } - } - } - } - - if( path.IsEmpty() ) - path = wxGetCwd(); - - return path; -} - - -void EDA_APP::SaveLastVisitedLibraryPath( const wxString& aPath ) -{ - m_LastVisitedLibPath = aPath; -} - - -wxString EDA_APP::ReturnFilenameWithRelativePathInLibPath( const wxString& aFullFilename ) -{ - /* If the library path is already in the library search paths - * list, just add the library name to the list. Otherwise, add - * the library name with the full or relative path. - * the relative path, when possible is preferable, - * because it preserve use of default libraries paths, when the path is a sub path of - * these default paths - * Note we accept only sub paths, - * not relative paths starting by ../ that are not subpaths and are outside kicad libs paths - */ - wxFileName fn = aFullFilename; - wxString filename = aFullFilename; - unsigned pathlen = fn.GetPath().Len(); /* path len, used to find the better (shortest) - * subpath within defaults paths */ - - for( unsigned kk = 0; kk < m_libSearchPaths.GetCount(); kk++ ) - { - fn = aFullFilename; - - // Search for the shortest subpath within m_libSearchPaths: - if( fn.MakeRelativeTo( m_libSearchPaths[kk] ) ) - { - if( fn.GetPathWithSep().StartsWith( wxT("..") ) ) // Path outside kicad libs paths - continue; - - if( pathlen > fn.GetPath().Len() ) // A better (shortest) subpath is found - { - filename = fn.GetPathWithSep() + fn.GetFullName(); - pathlen = fn.GetPath().Len(); - } - } - } - - return filename; -} - - -wxString EDA_APP::FindLibraryPath( const wxString& aFileName ) -{ - if( wxFileName::FileExists( aFileName ) ) - return aFileName; - else - return m_libSearchPaths.FindValidPath( aFileName ); -} - - -void EDA_APP::RemoveLibraryPath( const wxString& aPaths ) -{ - wxStringTokenizer Token( aPaths, wxT( ";\n\r" ) ); - - while( Token.HasMoreTokens() ) - { - wxString path = Token.GetNextToken(); - - if( m_libSearchPaths.Index( path, wxFileName::IsCaseSensitive() ) != wxNOT_FOUND ) - { - m_libSearchPaths.Remove( path ); - } - } -} - - -void EDA_APP::InsertLibraryPath( const wxString& aPaths, size_t aIndex ) -{ - wxStringTokenizer Token( aPaths, wxT( ";\n\r" ) ); - - while( Token.HasMoreTokens() ) - { - wxString path = Token.GetNextToken(); - - if( wxFileName::DirExists( path ) - && m_libSearchPaths.Index( path, wxFileName::IsCaseSensitive() ) == wxNOT_FOUND ) - { - if( aIndex >= m_libSearchPaths.GetCount() ) - { - m_libSearchPaths.Add( path ); - } - else - { - m_libSearchPaths.Insert( path, aIndex ); - } - - aIndex++; - } - } -} - - -bool EDA_APP::LockFile( const wxString& fileName ) -{ - // first make absolute and normalize, to avoid that different lock files - // for the same file can be created - wxFileName fn = fileName; - - fn.MakeAbsolute(); - - // semaphore to protect the edition of the file by more than one instance - if( m_oneInstancePerFileChecker != NULL ) - { - // it means that we had an open file and we are opening a different one - delete m_oneInstancePerFileChecker; - } - - wxString lockFileName = fn.GetFullPath() + wxT( ".lock" ); - - lockFileName.Replace( wxT( "/" ), wxT( "_" ) ); - - // We can have filenames coming from Windows, so also convert Windows separator - lockFileName.Replace( wxT( "\\" ), wxT( "_" ) ); - - m_oneInstancePerFileChecker = new wxSingleInstanceChecker( lockFileName ); - - if( m_oneInstancePerFileChecker && - m_oneInstancePerFileChecker->IsAnotherRunning() ) - { - return false; - } - - return true; -} - - -bool EDA_APP::SetFootprintLibTablePath() -{ - wxString path; - wxString kisysmod( wxT( KISYSMOD ) ); - - // Set the KISYSMOD environment variable for the current process if it is not already - // defined in the user's environment. This is required to expand the global footprint - // library table paths. - if( wxGetEnv( kisysmod, &path ) && wxFileName::DirExists( path ) ) - return true; - - // Set the KISYSMOD environment variable to the path defined in the user's configuration - // if it is defined and the path exists. - if( m_commonSettings->Read( kicadFpLibPath, &path ) && wxFileName::DirExists( path ) ) - { - wxSetEnv( kisysmod, path ); - return true; - } - - // Attempt to determine where the footprint libraries were installed using the legacy - // library search paths. - if( !GetLibraryPathList().IsEmpty() ) - { - unsigned modFileCount = 0; - wxString bestPath; - wxArrayString tmp; - - for( unsigned i = 0; i < GetLibraryPathList().GetCount(); i++ ) - { - unsigned cnt = wxDir::GetAllFiles( GetLibraryPathList()[i], &tmp, wxT( "*.mod" ), - wxDIR_FILES ); - - if( cnt > modFileCount ) - { - modFileCount = cnt; - bestPath = GetLibraryPathList()[i]; - } - } - - if( modFileCount != 0 ) - { - wxSetEnv( kisysmod, bestPath ); - return true; - } - } - - return false; -} - diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp index 99d9cd4a9b..99dde1c4bd 100644 --- a/common/footprint_info.cpp +++ b/common/footprint_info.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 3df80ec6d1..880109c048 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -30,7 +30,9 @@ #include -#include +//#include +#include +#include #include #include #include @@ -52,11 +54,11 @@ static const wxString traceFpLibTable( wxT( "KicadFpLibTable" ) ); /// The footprint library table name used when no project file is passed to Pcbnew or CvPcb. /// This is used temporarily to store the project specific library table until the project -/// file being edited is save. It is then moved to the file fp-lib-table in the folder where +/// file being edited is saved. It is then moved to the file fp-lib-table in the folder where /// the project file is saved. -static wxString defaultProjectFileName( wxT( "prj-fp-lib-table" ) ); +static const wxChar templateProjectFileName[] = wxT( "prj-fp-lib-table" ); -static wxString defaultFileName( wxT( "fp-lib-table" ) ); +static const wxChar global_tbl_name[] = wxT( "fp-lib-table" ); void FP_LIB_TABLE::ROW::SetType( const wxString& aType ) @@ -409,7 +411,7 @@ void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const void FP_LIB_TABLE::Save( const wxFileName& aPath ) const throw( IO_ERROR ) { - wxFileName fn = GetProjectFileName( aPath ); + wxFileName fn = GetProjectTableFileName( aPath.GetFullPath() ); wxLogTrace( traceFpLibTable, wxT( "Saving footprint libary table <%s>." ), GetChars( fn.GetFullPath() ) ); @@ -680,33 +682,8 @@ bool FP_LIB_TABLE::IsEmpty( bool aIncludeFallback ) } -bool FP_LIB_TABLE::MissingLegacyLibs( const wxArrayString& aLibNames, wxString* aErrorMsg ) -{ - bool retv = false; - - for( unsigned i = 0; i < aLibNames.GetCount(); i++ ) - { - wxFileName fn = wxFileName( wxEmptyString, aLibNames[i], LegacyFootprintLibPathExtension ); - wxString legacyLibPath = wxGetApp().FindLibraryPath( fn ); - - if( legacyLibPath.IsEmpty() ) - continue; - - if( FindRowByURI( legacyLibPath ) == 0 ) - { - retv = true; - - if( aErrorMsg ) - *aErrorMsg += wxT( "\"" ) + legacyLibPath + wxT( "\"\n" ); - } - } - - return retv; -} - - -bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aLibNames, - REPORTER* aReporter ) throw( IO_ERROR ) +bool FP_LIB_TABLE::ConvertFromLegacy( SEARCH_STACK& aSStack, NETLIST& aNetList, + const wxArrayString& aLibNames, REPORTER* aReporter ) throw( IO_ERROR ) { wxString msg; FPID lastFPID; @@ -720,7 +697,6 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL aNetList.SortByFPID(); wxString libPath; - wxFileName fn; PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); @@ -738,9 +714,9 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL for( unsigned ii = 0; ii < aLibNames.GetCount(); ii++ ) { - fn = wxFileName( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension ); + wxFileName fn( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension ); - libPath = wxGetApp().FindLibraryPath( fn ); + libPath = aSStack.FindValidPath( fn ); if( !libPath ) { @@ -766,7 +742,7 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL } } - if( module == NULL ) + if( !module ) { if( aReporter ) { @@ -780,6 +756,7 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL // Clear the footprint assignment since the old library lookup method is no // longer valid. FPID emptyFPID; + component->SetFPID( emptyFPID ); retv = false; continue; @@ -800,7 +777,9 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL if( wxFileName::GetPathSeparator() == wxChar( '\\' ) && uri.Find( wxChar( '/' ) ) >= 0 ) + { uri.Replace( wxT( "/"), wxT( "\\" ) ); + } if( uri == libPath ) { @@ -815,7 +794,7 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL { if( aReporter ) { - msg.Printf( _( "Component `%s` footprint '%s' legacy library path <%s > " + msg.Printf( _( "Component '%s' footprint '%s' legacy library path '%s' " "was not found in the footprint library table.\n" ), GetChars( component->GetReference() ), GetChars( component->GetFPID().Format() ) ); @@ -834,7 +813,7 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL { if( aReporter ) { - msg.Printf( _( "Component `%s` FPID '%s' is not valid.\n" ), + msg.Printf( _( "Component '%s' FPID '%s' is not valid.\n" ), GetChars( component->GetReference() ), GetChars( newFPID.Format() ) ); aReporter->Report( msg ); @@ -855,55 +834,34 @@ bool FP_LIB_TABLE::ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aL } -void FP_LIB_TABLE::SetProjectPathEnvVariable( const wxFileName& aPath ) -{ - wxString path; - - if( !aPath.IsOk() || !aPath.DirExists() ) - path = wxEmptyString; - else - path = aPath.GetPath(); - - wxLogTrace( traceFpLibTable, wxT( "Setting env %s to '%s'." ), - GetChars( ProjectPathEnvVariableName() ), GetChars( path ) ); - wxSetEnv( ProjectPathEnvVariableName(), path ); -} - - -const wxString FP_LIB_TABLE::ProjectPathEnvVariableName() -{ - return wxT( "KIPRJMOD" ); -} - - const wxString FP_LIB_TABLE::GlobalPathEnvVariableName() { - return wxT( KISYSMOD ); + return wxT( "KISYSMOD" ); } -wxString FP_LIB_TABLE::GetProjectFileName( const wxFileName& aPath ) +wxString FP_LIB_TABLE::GetProjectTableFileName( const wxString& aProjectFullName ) { - wxFileName fn = aPath; + wxFileName fn = aProjectFullName; + wxString path = fn.GetPath(); // Set $KICAD_PRJ_PATH to user's configuration path if aPath is not set or does not exist. - if( !aPath.IsOk() || !aPath.DirExists() ) + + if( !fn.IsOk() || !wxFileName::IsDirReadable( path ) ) { fn.AssignDir( wxStandardPaths::Get().GetUserConfigDir() ); #if defined( __WINDOWS__ ) fn.AppendDir( wxT( "kicad" ) ); #endif - - fn.SetName( defaultProjectFileName ); + fn.SetName( templateProjectFileName ); } else { - fn.AssignDir( aPath.GetPath() ); - fn.SetName( defaultFileName ); + fn.SetName( global_tbl_name ); } - wxLogTrace( traceFpLibTable, wxT( "Project specific footprint library table file '%s'." ), + wxLogTrace( traceFpLibTable, wxT( "Project footprint lib table file '%s'." ), GetChars( fn.GetFullPath() ) ); return fn.GetFullPath(); @@ -912,8 +870,8 @@ wxString FP_LIB_TABLE::GetProjectFileName( const wxFileName& aPath ) bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR ) { - bool tableExists = true; - wxFileName fn = GetGlobalTableFileName(); + bool tableExists = true; + wxFileName fn = GetGlobalTableFileName(); if( !fn.FileExists() ) { @@ -925,21 +883,22 @@ bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARS GetChars( fn.GetPath() ) ) ); } - // Attempt to copy the default global file table from the KiCad template folder to - // the users home configuration path. - wxString fileName = wxGetApp().FindLibraryPath( defaultFileName ); + // Attempt to copy the default global file table from the KiCad + // template folder to the user's home configuration path. + wxString fileName = Kiface().KifaceSearch().FindValidPath( global_tbl_name ); // The fallback is to create an empty global footprint table for the user to populate. if( fileName.IsEmpty() || !::wxCopyFile( fileName, fn.GetFullPath(), false ) ) { - FP_LIB_TABLE emptyTable; - FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); + FP_LIB_TABLE emptyTable; + FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); + emptyTable.Format( &sf, 0 ); } } - FILE_LINE_READER reader( fn.GetFullPath() ); - FP_LIB_TABLE_LEXER lexer( &reader ); + FILE_LINE_READER reader( fn.GetFullPath() ); + FP_LIB_TABLE_LEXER lexer( &reader ); aTable.Parse( &lexer ); return tableExists; @@ -965,9 +924,9 @@ wxString FP_LIB_TABLE::GetGlobalTableFileName() } -const wxString& FP_LIB_TABLE::GetFileName() +const wxString FP_LIB_TABLE::GetFileName() { - return defaultFileName; + return global_tbl_name; } @@ -979,8 +938,9 @@ void FP_LIB_TABLE::Load( const wxFileName& aFileName, FP_LIB_TABLE* aFallBackTab // Empty footprint library tables are valid. if( aFileName.IsOk() && aFileName.FileExists() ) { - FILE_LINE_READER reader( aFileName.GetFullPath() ); - FP_LIB_TABLE_LEXER lexer( &reader ); + FILE_LINE_READER reader( aFileName.GetFullPath() ); + FP_LIB_TABLE_LEXER lexer( &reader ); + Parse( &lexer ); } } diff --git a/common/gestfich.cpp b/common/gestfich.cpp index 900b5b10a9..a66b396c7f 100644 --- a/common/gestfich.cpp +++ b/common/gestfich.cpp @@ -30,7 +30,7 @@ // For compilers that support precompilation, includes "wx.h". #include -#include +#include #include #include @@ -299,14 +299,14 @@ wxString FindKicadHelpPath() bool PathFound = false; /* find kicad/help/ */ - tmp = wxGetApp().GetExecutablePath(); + tmp = Pgm().GetExecutablePath(); if( tmp.Last() == '/' ) tmp.RemoveLast(); FullPath = tmp.BeforeLast( '/' ); // cd .. FullPath += wxT( "/doc/help/" ); - LocaleString = wxGetApp().GetLocale()->GetCanonicalName(); + LocaleString = Pgm().GetLocale()->GetCanonicalName(); wxString path_tmp = FullPath; #ifdef __WINDOWS__ @@ -319,9 +319,9 @@ wxString FindKicadHelpPath() } /* find kicad/help/ from environment variable KICAD */ - if( !PathFound && wxGetApp().IsKicadEnvVariableDefined() ) + if( !PathFound && Pgm().IsKicadEnvVariableDefined() ) { - FullPath = wxGetApp().GetKicadEnvVariable() + wxT( "/doc/help/" ); + FullPath = Pgm().GetKicadEnvVariable() + wxT( "/doc/help/" ); if( wxDirExists( FullPath ) ) PathFound = true; @@ -379,7 +379,7 @@ wxString FindKicadFile( const wxString& shortname ) /* Test the presence of the file in the directory shortname of * the KiCad binary path. */ - FullFileName = wxGetApp().GetExecutablePath() + shortname; + FullFileName = Pgm().GetExecutablePath() + shortname; if( wxFileExists( FullFileName ) ) return FullFileName; @@ -387,9 +387,9 @@ wxString FindKicadFile( const wxString& shortname ) /* Test the presence of the file in the directory shortname * defined by the environment variable KiCad. */ - if( wxGetApp().IsKicadEnvVariableDefined() ) + if( Pgm().IsKicadEnvVariableDefined() ) { - FullFileName = wxGetApp().GetKicadEnvVariable() + shortname; + FullFileName = Pgm().GetKicadEnvVariable() + shortname; if( wxFileExists( FullFileName ) ) return FullFileName; @@ -426,7 +426,7 @@ int ExecuteFile( wxWindow* frame, const wxString& ExecFile, const wxString& para #ifdef __WXMAC__ if( wxFileExists( FullFileName ) || wxDir::Exists( FullFileName ) ) { - return ProcessExecute( wxGetApp().GetExecutablePath() + wxT( "/" ) + return ProcessExecute( Pgm().GetExecutablePath() + wxT( "/" ) + ExecFile + wxT( " " ) + param, wxEXEC_ASYNC, callback ); } @@ -450,26 +450,26 @@ int ExecuteFile( wxWindow* frame, const wxString& ExecFile, const wxString& para } -wxString ReturnKicadDatasPath() +wxString KicadDatasPath() { bool PathFound = false; wxString data_path; - if( wxGetApp().IsKicadEnvVariableDefined() ) // Path defined by the KICAD environment variable. + if( Pgm().IsKicadEnvVariableDefined() ) // Path defined by the KICAD environment variable. { - data_path = wxGetApp().GetKicadEnvVariable(); + data_path = Pgm().GetKicadEnvVariable(); PathFound = true; } else // Path of executables. { - wxString tmp = wxGetApp().GetExecutablePath(); + wxString tmp = Pgm().GetExecutablePath(); #ifdef __WINDOWS__ tmp.MakeLower(); #endif if( tmp.Contains( wxT( "kicad" ) ) ) { #ifdef __WINDOWS__ - tmp = wxGetApp().GetExecutablePath(); + tmp = Pgm().GetExecutablePath(); #endif if( tmp.Last() == '/' ) tmp.RemoveLast(); @@ -527,47 +527,6 @@ wxString ReturnKicadDatasPath() } -wxString& EDA_APP::GetEditorName() -{ - wxString editorname = m_EditorName; - - // We get the preferred editor name from environment variable first. - if( editorname.IsEmpty() ) - { - // If there is no EDITOR variable set, try the desktop default - if(!wxGetEnv( wxT( "EDITOR" ), &editorname )) - { -#ifdef __WXMAC__ - editorname = "/usr/bin/open"; -#elif __WXX11__ - editorname = "/usr/bin/xdg-open"; -#endif - } - } - if( editorname.IsEmpty() ) // We must get a preferred editor name - { - DisplayInfoMessage( NULL, - _( "No default editor found, you must choose it" ) ); - wxString mask( wxT( "*" ) ); - -#ifdef __WINDOWS__ - mask += wxT( ".exe" ); -#endif - editorname = EDA_FileSelector( _( "Preferred Editor:" ), wxEmptyString, - wxEmptyString, wxEmptyString, mask, - NULL, wxFD_OPEN, true ); - } - - if( !editorname.IsEmpty() ) - { - m_EditorName = editorname; - m_commonSettings->Write( wxT( "Editor" ), m_EditorName ); - } - - return m_EditorName; -} - - bool OpenPDF( const wxString& file ) { wxString command; @@ -575,12 +534,12 @@ bool OpenPDF( const wxString& file ) wxString type; bool success = false; - wxGetApp().ReadPdfBrowserInfos(); + Pgm().ReadPdfBrowserInfos(); - if( !wxGetApp().UseSystemPdfBrowser() ) // Run the preferred PDF Browser + if( !Pgm().UseSystemPdfBrowser() ) // Run the preferred PDF Browser { AddDelimiterString( filename ); - command = wxGetApp().GetPdfBrowserFileName() + wxT( " " ) + filename; + command = Pgm().GetPdfBrowserName() + wxT( " " ) + filename; } else { diff --git a/common/gr_basic.cpp b/common/gr_basic.cpp index 22a58b338a..1baa202443 100644 --- a/common/gr_basic.cpp +++ b/common/gr_basic.cpp @@ -1405,113 +1405,6 @@ void GRBezier( EDA_RECT* ClipBox, } -EDA_COLOR_T ColorMix( EDA_COLOR_T aColor1, EDA_COLOR_T aColor2 ) -{ - /* Memoization storage. This could be potentially called for each - * color merge so a cache is useful (there are few colours anyway) */ - static EDA_COLOR_T mix_cache[NBCOLORS][NBCOLORS]; - - // TODO how is alpha used? it's a mac only thing, I have no idea - aColor1 = ColorGetBase( aColor1 ); - aColor2 = ColorGetBase( aColor2 ); - - // First easy thing: a black gives always the other colour - if( aColor1 == BLACK ) - return aColor2; - if( aColor2 == BLACK) - return aColor1; - - /* Now we are sure that black can't occur, so the rule is: - * BLACK means not computed yet. If we're lucky we already have - * an answer */ - EDA_COLOR_T candidate = mix_cache[aColor1][aColor2]; - if( candidate != BLACK ) - return candidate; - - // Blend the two colors (i.e. OR the RGB values) - const StructColors &c1 = g_ColorRefs[aColor1]; - const StructColors &c2 = g_ColorRefs[aColor2]; - - // Ask the palette for the nearest color to the mix - wxColour mixed( c1.m_Red | c2.m_Red, - c1.m_Green | c2.m_Green, - c1.m_Blue | c2.m_Blue ); - candidate = ColorFindNearest( mixed ); - - /* Here, BLACK is *not* a good answer, since it would recompute the next time. - * Even theorically its not possible (with the current rules), but - * maybe the metric will change in the future */ - if( candidate == BLACK) - candidate = DARKDARKGRAY; - - // Store the result in the cache. The operation is commutative, too - mix_cache[aColor1][aColor2] = candidate; - mix_cache[aColor2][aColor1] = candidate; - return candidate; -} - - -EDA_COLOR_T ColorByName( const wxString& aName ) -{ - // look for a match in the palette itself - for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) ) - { - if( 0 == aName.CmpNoCase( g_ColorRefs[trying].m_Name ) ) - return trying; - } - - // Not found, no idea... - return UNSPECIFIED_COLOR; -} - -bool ColorIsLight( EDA_COLOR_T aColor ) -{ - const StructColors &c = g_ColorRefs[ColorGetBase( aColor )]; - int r = c.m_Red; - int g = c.m_Green; - int b = c.m_Blue; - return ((r * r) + (g * g) + (b * b)) > (128 * 128 * 3); -} - -EDA_COLOR_T ColorFindNearest( const wxColour &aColor ) -{ - return ColorFindNearest( aColor.Red(), aColor.Green(), aColor.Blue() ); -} - -EDA_COLOR_T ColorFindNearest( int aR, int aG, int aB ) -{ - EDA_COLOR_T candidate = BLACK; - - /* Find the 'nearest' color in the palette. This is fun. There is - a gazilion of metrics for the color space and no one of the - useful one is in the RGB color space. Who cares, this is a CAD, - not a photosomething... - - I hereby declare that the distance is the sum of the square of the - component difference. Think about the RGB color cube. Now get the - euclidean distance, but without the square root... for ordering - purposes it's the same, obviously. Also each component can't be - less of the target one, since I found this currently work better... - */ - int nearest_distance = 255 * 255 * 3 + 1; // Can't beat this - - for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) ) - { - const StructColors &c = g_ColorRefs[trying]; - int distance = (aR - c.m_Red) * (aR - c.m_Red) + - (aG - c.m_Green) * (aG - c.m_Green) + - (aB - c.m_Blue) * (aB - c.m_Blue); - if( distance < nearest_distance && c.m_Red >= aR && - c.m_Green >= aG && c.m_Blue >= aB ) - { - nearest_distance = distance; - candidate = trying; - } - } - - return candidate; -} - void GRDrawAnchor( EDA_RECT *aClipBox, wxDC *aDC, int x, int y, int aSize, EDA_COLOR_T aColor ) { diff --git a/common/hotkey_grid_table.cpp b/common/hotkey_grid_table.cpp index ee884f26cf..ecb75182aa 100644 --- a/common/hotkey_grid_table.cpp +++ b/common/hotkey_grid_table.cpp @@ -78,7 +78,7 @@ wxString HOTKEY_EDITOR_GRID_TABLE::GetValue( int row, int col ) } else { - return ReturnKeyNameFromKeyCode( hotkey_descr->m_KeyCode ); + return KeyNameFromKeyCode( hotkey_descr->m_KeyCode ); } } } diff --git a/common/hotkeys_basic.cpp b/common/hotkeys_basic.cpp index 0881c0f96d..968bcb47ca 100644 --- a/common/hotkeys_basic.cpp +++ b/common/hotkeys_basic.cpp @@ -29,7 +29,7 @@ */ #include -#include +#include #include #include #include @@ -61,9 +61,11 @@ wxString g_ModuleEditSectionTag( wxT( "[footprinteditor]" ) ); EDA_HOTKEY::EDA_HOTKEY( const wxChar* infomsg, int idcommand, int keycode, int idmenuevent ) { m_KeyCode = keycode; // Key code (ascii value for ascii keys + // or wxWidgets code for function key m_InfoMsg = infomsg; // info message. m_Idcommand = idcommand; // internal id for the corresponding + // command (see hotkey_id_commnand list) m_IdMenuEvent = idmenuevent; // id to call the corresponding event // (if any) (see id.h) @@ -137,13 +139,13 @@ static struct hotkey_name_descr s_Hotkey_Name_List[] = { wxT( "" ), 0 } }; -#define MODIFIER_CTRL wxT( "Ctrl+" ) -#define MODIFIER_ALT wxT( "Alt+" ) +#define MODIFIER_CTRL wxT( "Ctrl+" ) +#define MODIFIER_ALT wxT( "Alt+" ) #define MODIFIER_SHIFT wxT( "Shift+" ) /** - * Function ReturnKeyNameFromKeyCode + * Function KeyNameFromKeyCode * return the key name from the key code * Only some wxWidgets key values are handled for function key ( see * s_Hotkey_Name_List[] ) @@ -151,7 +153,7 @@ static struct hotkey_name_descr s_Hotkey_Name_List[] = * @param aIsFound = a pointer to a bool to return true if found, or false. an be NULL default) * @return the key name in a wxString */ -wxString ReturnKeyNameFromKeyCode( int aKeycode, bool* aIsFound ) +wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound ) { wxString keyname, modifier, fullkeyname; int ii; @@ -237,7 +239,7 @@ wxString AddHotkeyName( const wxString& aText, EDA_HOTKEY** aList, wxString keyname; if( aList ) - keyname = ReturnKeyNameFromCommandId( aList, aCommandId ); + keyname = KeyNameFromCommandId( aList, aCommandId ); if( !keyname.IsEmpty() ) { @@ -278,14 +280,14 @@ wxString AddHotkeyName( const wxString& aText, { wxString msg = aText; wxString keyname; - EDA_HOTKEY** List; + EDA_HOTKEY** list; if( aDescList ) { for( ; aDescList->m_HK_InfoList != NULL; aDescList++ ) { - List = aDescList->m_HK_InfoList; - keyname = ReturnKeyNameFromCommandId( List, aCommandId ); + list = aDescList->m_HK_InfoList; + keyname = KeyNameFromCommandId( list, aCommandId ); if( !keyname.IsEmpty() ) { @@ -313,13 +315,13 @@ wxString AddHotkeyName( const wxString& aText, /** - * Function ReturnKeyNameFromCommandId + * Function KeyNameFromCommandId * return the key name from the Command id value ( m_Idcommand member value) * @param aList = pointer to a EDA_HOTKEY list of commands * @param aCommandId = Command Id value * @return the key name in a wxString */ -wxString ReturnKeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ) +wxString KeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ) { wxString keyname; @@ -329,7 +331,7 @@ wxString ReturnKeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ) if( hk_decr->m_Idcommand == aCommandId ) { - keyname = ReturnKeyNameFromKeyCode( hk_decr->m_KeyCode ); + keyname = KeyNameFromKeyCode( hk_decr->m_KeyCode ); break; } } @@ -339,14 +341,14 @@ wxString ReturnKeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ) /** - * Function ReturnKeyCodeFromKeyName + * Function KeyCodeFromKeyName * return the key code from its key name * Only some wxWidgets key values are handled for function key * @param keyname = wxString key name to find in s_Hotkey_Name_List[], * like F2 or space or an usual (ascii) char. * @return the key code */ -int ReturnKeyCodeFromKeyName( const wxString& keyname ) +int KeyCodeFromKeyName( const wxString& keyname ) { int ii, keycode = 0; @@ -406,7 +408,7 @@ int ReturnKeyCodeFromKeyName( const wxString& keyname ) void DisplayHotkeyList( EDA_DRAW_FRAME* aFrame, struct EDA_HOTKEY_CONFIG* aDescList ) { wxString keyname; - EDA_HOTKEY** List; + EDA_HOTKEY** list; wxString msg = wxT( "" ); @@ -416,15 +418,16 @@ void DisplayHotkeyList( EDA_DRAW_FRAME* aFrame, struct EDA_HOTKEY_CONFIG* aDescL for( ; aDescList->m_HK_InfoList != NULL; aDescList++ ) { - List = aDescList->m_HK_InfoList; + list = aDescList->m_HK_InfoList; - for( ; *List != NULL; List++ ) + for( ; *list != NULL; list++ ) { - EDA_HOTKEY* hk_decr = *List; + EDA_HOTKEY* hk_decr = *list; if( !hk_decr->m_InfoMsg.Contains( wxT( "Macros" ) ) ) { - keyname = ReturnKeyNameFromKeyCode( hk_decr->m_KeyCode ); + keyname = KeyNameFromKeyCode( hk_decr->m_KeyCode ); + // Some chars should be modified, using html encoding, to be // displayed by DisplayHtmlInfoMessage() keyname.Replace( wxT("<"), wxT("<") ); @@ -480,8 +483,8 @@ int EDA_BASE_FRAME::WriteHotkeyConfig( struct EDA_HOTKEY_CONFIG* aDescList, msg = wxT( "$hotkey list\n" ); - /* Print the current hotkey list */ - EDA_HOTKEY** List; + // Print the current hotkey list + EDA_HOTKEY** list; for( ; aDescList->m_HK_InfoList != NULL; aDescList++ ) { @@ -495,13 +498,13 @@ int EDA_BASE_FRAME::WriteHotkeyConfig( struct EDA_HOTKEY_CONFIG* aDescList, msg += *aDescList->m_SectionTag; msg += wxT( "\n" ); - List = aDescList->m_HK_InfoList; + list = aDescList->m_HK_InfoList; - for( ; *List != NULL; List++ ) + for( ; *list != NULL; list++ ) { - EDA_HOTKEY* hk_decr = *List; + EDA_HOTKEY* hk_decr = *list; msg += wxT( "shortcut " ); - keyname = ReturnKeyNameFromKeyCode( hk_decr->m_KeyCode ); + keyname = KeyNameFromKeyCode( hk_decr->m_KeyCode ); AddDelimiterString( keyname ); infokey = hk_decr->m_InfoMsg; AddDelimiterString( infokey ); @@ -548,21 +551,21 @@ int EDA_BASE_FRAME::ReadHotkeyConfigFile( const wxString& aFilename, { wxFile cfgfile( aFilename ); - /* get length */ + // get length cfgfile.SeekEnd(); wxFileOffset size = cfgfile.Tell(); cfgfile.Seek( 0 ); - /* read data */ + // read data char* buffer = new char[size]; cfgfile.Read( buffer, size ); wxString data( buffer, wxConvUTF8 ); - /* parse */ + // parse ParseHotkeyConfig( data, aDescList ); - /* cleanup */ + // cleanup delete[] buffer; cfgfile.Close(); return 1; @@ -603,7 +606,7 @@ int EDA_BASE_FRAME::ReadHotkeyConfig( struct EDA_HOTKEY_CONFIG* aDescList ) void ParseHotkeyConfig( const wxString& data, struct EDA_HOTKEY_CONFIG* aDescList ) { - /* Read the config */ + // Read the config wxStringTokenizer tokenizer( data, L"\r\n", wxTOKEN_STRTOK ); EDA_HOTKEY** CurrentHotkeyList = 0; @@ -643,23 +646,23 @@ void ParseHotkeyConfig( const wxString& data, if( CurrentHotkeyList == NULL ) continue; - /* Get the key name */ + // Get the key name lineTokenizer.SetString( lineTokenizer.GetString(), L"\"\r\n\t ", wxTOKEN_STRTOK ); wxString keyname = lineTokenizer.GetNextToken(); wxString remainder = lineTokenizer.GetString(); - /* Get the command name */ + // Get the command name wxString fctname = remainder.AfterFirst( '\"' ).BeforeFirst( '\"' ); - /* search the hotkey in current hotkey list */ - for( EDA_HOTKEY** List = CurrentHotkeyList; *List != NULL; List++ ) + // search the hotkey in current hotkey list + for( EDA_HOTKEY** list = CurrentHotkeyList; *list != NULL; list++ ) { - EDA_HOTKEY* hk_decr = *List; + EDA_HOTKEY* hk_decr = *list; if( hk_decr->m_InfoMsg == fctname ) { - int code = ReturnKeyCodeFromKeyName( keyname ); + int code = KeyCodeFromKeyName( keyname ); if( code ) hk_decr->m_KeyCode = code; @@ -681,7 +684,7 @@ void EDA_BASE_FRAME::ImportHotkeyConfigFromFile( struct EDA_HOTKEY_CONFIG* aDesc wxString ext = DEFAULT_HOTKEY_FILENAME_EXT; wxString mask = wxT( "*." ) + ext; wxString path = wxGetCwd(); - wxString filename = wxGetApp().GetAppName() + wxT( "." ) + ext; + wxString filename = Kiface().Name() + wxT( '.' ) + ext; filename = EDA_FileSelector( _( "Read Hotkey Configuration File:" ), path, @@ -709,7 +712,7 @@ void EDA_BASE_FRAME::ExportHotkeyConfigToFile( struct EDA_HOTKEY_CONFIG* aDescLi wxString ext = DEFAULT_HOTKEY_FILENAME_EXT; wxString mask = wxT( "*." ) + ext; wxString path = wxGetCwd(); - wxString filename = wxGetApp().GetAppName() + wxT( "." ) + ext; + wxString filename = Kiface().Name() + wxT( "." ) + ext; filename = EDA_FileSelector( _( "Write Hotkey Configuration File:" ), path, @@ -736,14 +739,14 @@ void AddHotkeyConfigMenu( wxMenu* aMenu ) wxMenu* HotkeySubmenu = new wxMenu(); - /* List existing hotkey menu*/ + // List existing hotkey menu AddMenuItem( HotkeySubmenu, ID_PREFERENCES_HOTKEY_SHOW_CURRENT_LIST, _( "&List Current Keys" ), _( "Displays the current hotkeys list and corresponding commands" ), KiBitmap( info_xpm ) ); - /* Call hotkeys editor*/ + // Call hotkeys editor AddMenuItem( HotkeySubmenu, ID_PREFERENCES_HOTKEY_SHOW_EDITOR, _( "&Edit Hotkeys" ), _( "Call the hotkeys editor" ), @@ -751,19 +754,19 @@ void AddHotkeyConfigMenu( wxMenu* aMenu ) HotkeySubmenu->AppendSeparator(); - /* create hotkey file to export current hotkeys config */ + // create hotkey file to export current hotkeys config AddMenuItem( HotkeySubmenu, ID_PREFERENCES_HOTKEY_EXPORT_CONFIG, _( "E&xport Hotkeys" ), _( "Create a hotkey configuration file to export the current hotkeys" ), KiBitmap( save_setup_xpm ) ); - /* Reload hotkey file */ + // Reload hotkey file AddMenuItem( HotkeySubmenu, ID_PREFERENCES_HOTKEY_IMPORT_CONFIG, _( "&Import Hotkeys" ), _( "Load an existing hotkey configuration file" ), KiBitmap( reload_xpm ) ); - /* Append HotkeySubmenu to menu */ + // Append HotkeySubmenu to menu AddMenuItem( aMenu, HotkeySubmenu, ID_PREFERENCES_HOTKEY_SUBMENU, _( "&Hotkeys" ), _( "Hotkeys configuration and preferences" ), diff --git a/common/kiface_i.cpp b/common/kiface_i.cpp new file mode 100644 index 0000000000..164195b231 --- /dev/null +++ b/common/kiface_i.cpp @@ -0,0 +1,206 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 1992-2014 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include // FROM_UTF8() +#include +#include + +#include +#include + +#include +#include + + +static const wxChar showPageLimitsKey[] = wxT( "ShowPageLimits" ); +static const wxChar backgroundColorKey[] = wxT( "BackgroundColor" ); + + +/// Initialize aDst SEARCH_STACK with KIFACE (DSO) specific settings. +/// A non-member function so it an be moved easily, plus it's nobody's business. +static void setSearchPaths( SEARCH_STACK* aDst, KIWAY::FACE_T aId ) +{ + SEARCH_STACK bases; + + SystemDirsAppend( &bases ); + aDst->Clear(); + + for( unsigned i = 0; i < bases.GetCount(); ++i ) + { + wxFileName fn( bases[i], wxEmptyString ); + + // Add schematic library file path to search path list. + // we must add /library and /library/doc + if( aId == KIWAY::FACE_SCH ) + { + fn.AppendDir( wxT( "library" ) ); + aDst->AddPaths( fn.GetPath() ); + + // Add schematic doc file path (library/doc)to search path list. + fn.AppendDir( wxT( "doc" ) ); + aDst->AddPaths( fn.GetPath() ); + + fn.RemoveLastDir(); + fn.RemoveLastDir(); // "../../" up twice, removing library/doc/ + } + + // Add PCB library file path to search path list. + if( aId == KIWAY::FACE_PCB || aId == KIWAY::FACE_CVPCB ) + { + fn.AppendDir( wxT( "modules" ) ); + aDst->AddPaths( fn.GetPath() ); + + // Add 3D module library file path to search path list. + fn.AppendDir( wxT( "packages3d" ) ); + aDst->AddPaths( fn.GetPath() ); + + fn.RemoveLastDir(); + fn.RemoveLastDir(); // "../../" up twice, remove modules/packages3d + } + + // Add KiCad template file path to search path list. + fn.AppendDir( wxT( "template" ) ); + aDst->AddPaths( fn.GetPath() ); + } + +#if 1 && defined(DEBUG) + aDst->Show( "kiway" ); +#endif +} + + +bool KIFACE_I::start_common() +{ + m_bm.Init(); + + m_bm.m_config->Read( showPageLimitsKey, &g_ShowPageLimits ); + + // FIXME OSX Mountain Lion (10.8) + // Seems that Read doesn't found anything and ColorFromInt + // Asserts - I'm unable to reproduce on 10.7 + + int draw_bg_color = BLACK; // Default for all apps but Eeschema + + if( m_id == KIWAY::FACE_SCH ) + draw_bg_color = WHITE; // Default for Eeschema + + m_bm.m_config->Read( backgroundColorKey, &draw_bg_color ); + + g_DrawBgColor = ColorFromInt( draw_bg_color ); + + setSearchPaths( &m_bm.m_search, m_id ); + + return true; +} + + +void KIFACE_I::end_common() +{ + m_bm.End(); +} + + +wxString KIFACE_I::GetHelpFile() +{ + wxString fn; + wxArrayString subdirs; + wxArrayString altsubdirs; + + // FIXME: This is not the ideal way to handle this. Unfortunately, the + // CMake install paths seem to be a moving target so this crude + // hack solves the problem of install path differences between + // Windows and non-Windows platforms. + + // Partially fixed, but must be enhanced + + // Create subdir tree for "standard" linux distributions, when KiCad comes + // from a distribution files are in /usr/share/doc/kicad/help and binaries + // in /usr/bin or /usr/local/bin + subdirs.Add( wxT( "share" ) ); + subdirs.Add( wxT( "doc" ) ); + subdirs.Add( wxT( "kicad" ) ); + subdirs.Add( wxT( "help" ) ); + + // Create subdir tree for linux and Windows KiCad pack. + // Note the pack form under linux is also useful if a user wants to + // install KiCad to a server because there is only one path to mount + // or export (something like /usr/local/kicad). + // files are in /kicad/doc/help + // (often /usr/local/kicad/kicad/doc/help) + // /kicad/ is retrieved from m_BinDir + altsubdirs.Add( wxT( "doc" ) ); + altsubdirs.Add( wxT( "help" ) ); + + /* Search for a help file. + * we *must* find a help file. + * so help is searched in directories in this order: + * help/ like help/en_GB + * help/ like help/en + * help/en + */ + + wxLocale* i18n = Pgm().GetLocale(); + + // Step 1 : Try to find help file in help/ + subdirs.Add( i18n->GetCanonicalName() ); + altsubdirs.Add( i18n->GetCanonicalName() ); + + fn = m_bm.m_search.FindFileInSearchPaths( m_bm.m_help_file, &altsubdirs ); + + if( !fn ) + fn = m_bm.m_search.FindFileInSearchPaths( m_bm.m_help_file, &subdirs ); + + // Step 2 : if not found Try to find help file in help/ + if( !fn ) + { + subdirs.RemoveAt( subdirs.GetCount() - 1 ); + altsubdirs.RemoveAt( altsubdirs.GetCount() - 1 ); + + // wxLocale::GetName() does not return always the short name + subdirs.Add( i18n->GetName().BeforeLast( '_' ) ); + altsubdirs.Add( i18n->GetName().BeforeLast( '_' ) ); + + fn = m_bm.m_search.FindFileInSearchPaths( m_bm.m_help_file, &altsubdirs ); + + if( !fn ) + fn = m_bm.m_search.FindFileInSearchPaths( m_bm.m_help_file, &subdirs ); + } + + // Step 3 : if not found Try to find help file in help/en + if( !fn ) + { + subdirs.RemoveAt( subdirs.GetCount() - 1 ); + altsubdirs.RemoveAt( altsubdirs.GetCount() - 1 ); + subdirs.Add( wxT( "en" ) ); + altsubdirs.Add( wxT( "en" ) ); + + fn = m_bm.m_search.FindFileInSearchPaths( m_bm.m_help_file, &altsubdirs ); + + if( !fn ) + fn = m_bm.m_search.FindFileInSearchPaths( m_bm.m_help_file, &subdirs ); + } + + return fn; +} diff --git a/common/kiway.cpp b/common/kiway.cpp index 92086838ca..01197f64c5 100644 --- a/common/kiway.cpp +++ b/common/kiway.cpp @@ -53,9 +53,9 @@ const wxString KIWAY::dso_name( FACE_T aFaceId ) } -PROJECT& KIWAY::Project() +PROJECT& KIWAY::Prj() const { - return m_project; + return *(PROJECT*) &m_project; // strip const-ness, function really is const. } diff --git a/common/kiway_holder.cpp b/common/kiway_holder.cpp new file mode 100644 index 0000000000..8679254d82 --- /dev/null +++ b/common/kiway_holder.cpp @@ -0,0 +1,29 @@ + +#include +#include + + +PROJECT& KIWAY_HOLDER::Prj() const +{ + return Kiway().Prj(); +} + + +// this is not speed critical, hide it out of line. +void KIWAY_HOLDER::SetKiway( wxWindow* aDest, KIWAY* aKiway ) +{ +#if defined(DEBUG) + // offer a trap point for debugging most any window + wxASSERT( aDest ); + if( !strcmp( typeid(aDest).name(), "DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB" ) ) + { + int breakhere=1; + (void) breakhere; + } +#endif + + (void) aDest; + + m_kiway = aKiway; +} + diff --git a/common/page_layout/class_worksheet_layout.cpp b/common/page_layout/class_worksheet_layout.cpp index 67cd12277d..379ba777ab 100644 --- a/common/page_layout/class_worksheet_layout.cpp +++ b/common/page_layout/class_worksheet_layout.cpp @@ -50,13 +50,14 @@ */ #include -#include +#include #include #include #include #include #include + // The layout shape used in the application // It is accessible by WORKSHEET_LAYOUT::GetTheInstance() WORKSHEET_LAYOUT wksTheInstance; @@ -70,21 +71,25 @@ WORKSHEET_LAYOUT::WORKSHEET_LAYOUT() m_bottomMargin = 10.0; // the bottom page margin in mm } + void WORKSHEET_LAYOUT::SetLeftMargin( double aMargin ) { m_leftMargin = aMargin; // the left page margin in mm } + void WORKSHEET_LAYOUT::SetRightMargin( double aMargin ) { m_rightMargin = aMargin; // the right page margin in mm } + void WORKSHEET_LAYOUT::SetTopMargin( double aMargin ) { m_topMargin = aMargin; // the top page margin in mm } + void WORKSHEET_LAYOUT::SetBottomMargin( double aMargin ) { m_bottomMargin = aMargin; // the bottom page margin in mm @@ -98,8 +103,7 @@ void WORKSHEET_LAYOUT::ClearList() m_list.clear(); } -/* Insert an item to the list of items at position aIdx - */ + void WORKSHEET_LAYOUT::Insert( WORKSHEET_DATAITEM* aItem, unsigned aIdx ) { if ( aIdx >= GetCount() ) @@ -108,8 +112,7 @@ void WORKSHEET_LAYOUT::Insert( WORKSHEET_DATAITEM* aItem, unsigned aIdx ) m_list.insert( m_list.begin() + aIdx, aItem ); } -/* Remove the item to the list of items at position aIdx - */ + bool WORKSHEET_LAYOUT::Remove( unsigned aIdx ) { if ( aIdx >= GetCount() ) @@ -118,8 +121,7 @@ bool WORKSHEET_LAYOUT::Remove( unsigned aIdx ) return true; } -/* Remove the item to the list of items at position aIdx - */ + bool WORKSHEET_LAYOUT::Remove( WORKSHEET_DATAITEM* aItem ) { unsigned idx = 0; @@ -135,8 +137,7 @@ bool WORKSHEET_LAYOUT::Remove( WORKSHEET_DATAITEM* aItem ) return Remove( idx ); } -/* return the index of aItem, or -1 if does not exist - */ + int WORKSHEET_LAYOUT::GetItemIndex( WORKSHEET_DATAITEM* aItem ) const { unsigned idx = 0; @@ -161,17 +162,13 @@ WORKSHEET_DATAITEM* WORKSHEET_LAYOUT::GetItem( unsigned aIdx ) const return NULL; } -/* return a short filename from a full filename: - * if the path is the current path,or if the path is the same - * as kicad.pro (in template), returns a shortname - * else do nothing and returns the full filename - */ + const wxString WORKSHEET_LAYOUT::MakeShortFileName( const wxString& aFullFileName ) { - wxFileName fn = aFullFileName; - wxString shortFileName = aFullFileName; + wxFileName fn = aFullFileName; + wxString shortFileName = aFullFileName; + wxString fileName = Kiface().KifaceSearch().FindValidPath( fn.GetFullName() ); - wxString fileName = wxGetApp().GetLibraryPathList().FindValidPath( fn.GetFullName() ); if( !fileName.IsEmpty() ) { fn = fileName; @@ -182,19 +179,15 @@ const wxString WORKSHEET_LAYOUT::MakeShortFileName( const wxString& aFullFileNam return shortFileName; } -/** - * @return a full filename from a short filename, - * if the short filename path is void - * In this case the path is the same as kicad.pro (in template) - * else return the short filename (which have an absolute os relative path - */ + const wxString WORKSHEET_LAYOUT::MakeFullFileName( const wxString& aShortFileName ) { - wxFileName fn = aShortFileName; - wxString fullFileName = aShortFileName; + wxFileName fn = aShortFileName; + wxString fullFileName = aShortFileName; + if( fn.GetPath().IsEmpty() && !fn.GetFullName().IsEmpty() ) { - wxString name = wxGetApp().GetLibraryPathList().FindValidPath( fn.GetFullName() ); + wxString name = Kiface().KifaceSearch().FindValidPath( fn.GetFullName() ); if( !name.IsEmpty() ) fullFileName = name; } diff --git a/common/pgm_base.cpp b/common/pgm_base.cpp new file mode 100644 index 0000000000..736275fcee --- /dev/null +++ b/common/pgm_base.cpp @@ -0,0 +1,742 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file eda_pgm.cpp + * + * @brief For the main application: init functions, and language selection + * (locale handling) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define KICAD_COMMON wxT( "kicad_common" ) + +// some key strings used to store parameters in KICAD_COMMON + +const wxChar PGM_BASE::workingDirKey[] = wxT( "WorkingDir" ); // public + +static const wxChar languageCfgKey[] = wxT( "LanguageID" ); +static const wxChar kicadFpLibPath[] = wxT( "KicadFootprintLibraryPath" ); + + +/** + * A small class to handle the list of existing translations. + * The locale translation is automatic. + * The selection of languages is mainly for maintainer's convenience + * To add a support to a new translation: + * create a new icon (flag of the country) (see Lang_Fr.xpm as an example) + * add a new item to s_Languages[]. + */ +struct LANGUAGE_DESCR +{ + /// wxWidgets locale identifier (See wxWidgets doc) + int m_WX_Lang_Identifier; + + /// KiCad identifier used in menu selection (See id.h) + int m_KI_Lang_Identifier; + + /// The menu language icons + BITMAP_DEF m_Lang_Icon; + + /// Labels used in menus + wxString m_Lang_Label; + + /// Set to true if the m_Lang_Label must not be translated + bool m_DoNotTranslate; +}; + + +/** + * Variable s_Languages + * Note: because this list is not created on the fly, wxTranslation + * must be called when a language name must be displayed after translation. + * Do not change this behavior, because m_Lang_Label is also used as key in config + */ +static LANGUAGE_DESCR s_Languages[] = +{ + // Default language + { + wxLANGUAGE_DEFAULT, + ID_LANGUAGE_DEFAULT, + lang_def_xpm, + _( "Default" ) + }, + + // English language + { + wxLANGUAGE_ENGLISH, + ID_LANGUAGE_ENGLISH, + lang_en_xpm, + wxT( "English" ), + true + }, + + // French language + { + wxLANGUAGE_FRENCH, + ID_LANGUAGE_FRENCH, + lang_fr_xpm, + _( "French" ) + }, + + // Finnish language + { + wxLANGUAGE_FINNISH, + ID_LANGUAGE_FINNISH, + lang_fi_xpm, + _( "Finnish" ) + }, + + // Spanish language + { + wxLANGUAGE_SPANISH, + ID_LANGUAGE_SPANISH, + lang_es_xpm, + _( "Spanish" ) + }, + + // Portuguese language + { + wxLANGUAGE_PORTUGUESE, + ID_LANGUAGE_PORTUGUESE, + lang_pt_xpm, + _( "Portuguese" ) + }, + + // Italian language + { + wxLANGUAGE_ITALIAN, + ID_LANGUAGE_ITALIAN, + lang_it_xpm, + _( "Italian" ) + }, + + // German language + { + wxLANGUAGE_GERMAN, + ID_LANGUAGE_GERMAN, + lang_de_xpm, + _( "German" ) + }, + + // Greek language + { + wxLANGUAGE_GREEK, + ID_LANGUAGE_GREEK, + lang_gr_xpm, + _( "Greek" ) + }, + + // Slovenian language + { + wxLANGUAGE_SLOVENIAN, + ID_LANGUAGE_SLOVENIAN, + lang_sl_xpm, + _( "Slovenian" ) + }, + + // Hungarian language + { + wxLANGUAGE_HUNGARIAN, + ID_LANGUAGE_HUNGARIAN, + lang_hu_xpm, + _( "Hungarian" ) + }, + + // Polish language + { + wxLANGUAGE_POLISH, + ID_LANGUAGE_POLISH, + lang_pl_xpm, + _( "Polish" ) + }, + + // Czech language + { + wxLANGUAGE_CZECH, + ID_LANGUAGE_CZECH, + lang_cs_xpm, + _( "Czech" ) + }, + + // Russian language + { + wxLANGUAGE_RUSSIAN, + ID_LANGUAGE_RUSSIAN, + lang_ru_xpm, + _( "Russian" ) + }, + + // Korean language + { + wxLANGUAGE_KOREAN, + ID_LANGUAGE_KOREAN, + lang_ko_xpm, + _( "Korean" ) + }, + + // Chinese simplified + { + wxLANGUAGE_CHINESE_SIMPLIFIED, + ID_LANGUAGE_CHINESE_SIMPLIFIED, + lang_chinese_xpm, + _( "Chinese simplified" ) + }, + + // Catalan language + { + wxLANGUAGE_CATALAN, + ID_LANGUAGE_CATALAN, + lang_catalan_xpm, + _( "Catalan" ) + }, + + // Dutch language + { + wxLANGUAGE_DUTCH, + ID_LANGUAGE_DUTCH, + lang_nl_xpm, + _( "Dutch" ) + }, + + // Japanese language + { + wxLANGUAGE_JAPANESE, + ID_LANGUAGE_JAPANESE, + lang_jp_xpm, + _( "Japanese" ) + }, + + // Bulgarian language + { + wxLANGUAGE_BULGARIAN, + ID_LANGUAGE_BULGARIAN, + lang_bg_xpm, + _( "Bulgarian" ) + } +}; + + +PGM_BASE::PGM_BASE() +{ + m_pgm_checker = NULL; + m_file_checker = NULL; + m_html_ctrl = NULL; + m_locale = NULL; + m_common_settings = NULL; + + m_wx_app = NULL; + + setLanguageId( wxLANGUAGE_DEFAULT ); +} + + +PGM_BASE::~PGM_BASE() +{ + destroy(); +} + + +void PGM_BASE::destroy() +{ + // unlike a normal destructor, this is designed to be called more than once safely: + + delete m_common_settings; + m_common_settings = 0; + + delete m_pgm_checker; + m_pgm_checker = 0; + + delete m_file_checker; + m_file_checker = 0; + + delete m_locale; + m_locale = 0; + + delete m_html_ctrl; + m_html_ctrl = 0; +} + + +void PGM_BASE::SetEditorName( const wxString& aFileName ) +{ + m_editor_name = aFileName; + wxASSERT( m_common_settings ); + m_common_settings->Write( wxT( "Editor" ), aFileName ); +} + + +const wxString& PGM_BASE::GetEditorName() +{ + wxString editorname = m_editor_name; + + if( !editorname ) + { + // Get the preferred editor name from environment variable first. + if(!wxGetEnv( wxT( "EDITOR" ), &editorname )) + { + // If there is no EDITOR variable set, try the desktop default +#ifdef __WXMAC__ + editorname = "/usr/bin/open"; +#elif __WXX11__ + editorname = "/usr/bin/xdg-open"; +#endif + } + } + + if( !editorname ) // We must get a preferred editor name + { + DisplayInfoMessage( NULL, + _( "No default editor found, you must choose it" ) ); + + wxString mask( wxT( "*" ) ); + +#ifdef __WINDOWS__ + mask += wxT( ".exe" ); +#endif + editorname = EDA_FileSelector( _( "Preferred Editor:" ), wxEmptyString, + wxEmptyString, wxEmptyString, mask, + NULL, wxFD_OPEN, true ); + } + + if( !editorname.IsEmpty() ) + { + m_editor_name = editorname; + m_common_settings->Write( wxT( "Editor" ), m_editor_name ); + } + + return m_editor_name; +} + + +bool PGM_BASE::initPgm() +{ + wxFileName pgm_name( App().argv[0] ); + + wxInitAllImageHandlers(); + + m_pgm_checker = new wxSingleInstanceChecker( pgm_name.GetName().Lower() + wxT( "-" ) + wxGetUserId() ); + + if( m_pgm_checker->IsAnotherRunning() ) + { + wxString quiz = wxString::Format( + _( "%s is already running, Continue?" ), + GetChars( pgm_name.GetName() ) + ); + if( !IsOK( NULL, quiz ) ) + return false; + } + + // Init KiCad environment + // the environment variable KICAD (if exists) gives the kicad path: + // something like set KICAD=d:\kicad + bool isDefined = wxGetEnv( wxT( "KICAD" ), &m_kicad_env ); + + if( isDefined ) // ensure m_kicad_env ends by "/" + { + m_kicad_env.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); + + if( !m_kicad_env.IsEmpty() && m_kicad_env.Last() != '/' ) + m_kicad_env += UNIX_STRING_DIR_SEP; + } + + // Init parameters for configuration + App().SetVendorName( wxT( "KiCad" ) ); + App().SetAppName( pgm_name.GetName().Lower() ); + + // Install some image handlers, mainly for help + wxImage::AddHandler( new wxPNGHandler ); + wxImage::AddHandler( new wxGIFHandler ); + wxImage::AddHandler( new wxJPEGHandler ); + wxFileSystem::AddHandler( new wxZipFSHandler ); + + // Analyze the command line & initialize the binary path + setExecutablePath(); + + SetLanguagePath(); + + // OS specific instantiation of wxConfigBase derivative: + m_common_settings = new wxConfig( KICAD_COMMON ); + + ReadPdfBrowserInfos(); // needs m_common_settings + + loadCommonSettings(); + + + bool succes = SetLanguage( true ); + + if( !succes ) + { + } + + // Set locale option for separator used in float numbers + SetLocaleTo_Default(); + + return true; +} + + +void PGM_BASE::SetHtmlHelpController( wxHtmlHelpController* aController ) +{ + delete m_html_ctrl; + m_html_ctrl = aController; +} + + +void PGM_BASE::InitOnLineHelp() +{ + wxString fullfilename = FindKicadHelpPath(); + +#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML + m_HelpFileName = fullfilename + wxT( ".html" ); + fullfilename += wxT( "kicad.hhp" ); + + if( wxFileExists( fullfilename ) ) + { + m_html_ctrl = new wxHtmlHelpController( wxHF_TOOLBAR | wxHF_CONTENTS | + wxHF_PRINT | wxHF_OPEN_FILES + /*| wxHF_SEARCH */ ); + m_html_ctrl->UseConfig( m_common_settings ); + m_html_ctrl->SetTitleFormat( wxT( "KiCad Help" ) ); + m_html_ctrl->AddBook( fullfilename ); + } + +#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF + m_html_ctrl = NULL; + +#else + #error Help files format not defined +#endif +} + + +bool PGM_BASE::setExecutablePath() +{ +// Apple MacOSx +#ifdef __APPLE__ + + // Derive path from location of the app bundle + CFBundleRef mainBundle = CFBundleGetMainBundle(); + + if( mainBundle == NULL ) + return false; + + CFURLRef urlref = CFBundleCopyBundleURL( mainBundle ); + + if( urlref == NULL ) + return false; + + CFStringRef str = CFURLCopyFileSystemPath( urlref, kCFURLPOSIXPathStyle ); + + if( str == NULL ) + return false; + + char* native_str = NULL; + int len = CFStringGetMaximumSizeForEncoding( CFStringGetLength( str ), + kCFStringEncodingUTF8 ) + 1; + native_str = new char[len]; + + CFStringGetCString( str, native_str, len, kCFStringEncodingUTF8 ); + m_bin_dir = FROM_UTF8( native_str ); + delete[] native_str; + +#else + m_bin_dir = wxStandardPaths::Get().GetExecutablePath(); + +#endif + + // Use unix notation for paths. I am not sure this is a good idea, + // but it simplifies compatibility between Windows and Unices. + // However it is a potential problem in path handling under Windows. + m_bin_dir.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); + + // Remove file name form command line: + while( m_bin_dir.Last() != '/' && !m_bin_dir.IsEmpty() ) + m_bin_dir.RemoveLast(); + + return true; +} + + +void PGM_BASE::loadCommonSettings() +{ + wxASSERT( m_common_settings ); + + m_help_size.x = 500; + m_help_size.y = 400; + + wxString languageSel; + + m_common_settings->Read( languageCfgKey, &languageSel ); + setLanguageId( wxLANGUAGE_DEFAULT ); + + // Search for the current selection + for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) + { + if( s_Languages[ii].m_Lang_Label == languageSel ) + { + setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); + break; + } + } + + m_editor_name = m_common_settings->Read( wxT( "Editor" ) ); +} + + +void PGM_BASE::saveCommonSettings() +{ + // m_common_settings is not initialized until fairly late in the + // process startup: initPgm(), so test before using: + if( m_common_settings ) + { + m_common_settings->Write( workingDirKey, wxGetCwd() ); + } +} + + +bool PGM_BASE::SetLanguage( bool first_time ) +{ + bool retv = true; + + // dictionary file name without extend (full name is kicad.mo) + wxString dictionaryName( wxT( "kicad" ) ); + + delete m_locale; + m_locale = new wxLocale; + +#if wxCHECK_VERSION( 2, 9, 0 ) + if( !m_locale->Init( m_language_id ) ) +#else + if( !m_locale->Init( m_language_id, wxLOCALE_CONV_ENCODING ) ) +#endif + { + wxLogDebug( wxT( "This language is not supported by the system." ) ); + + setLanguageId( wxLANGUAGE_DEFAULT ); + delete m_locale; + + m_locale = new wxLocale; + m_locale->Init(); + retv = false; + } + else if( !first_time ) + { + wxLogDebug( wxT( "Search for dictionary %s.mo in %s" ), + GetChars( dictionaryName ), GetChars( m_locale->GetName() ) ); + } + + // how about a meaningful comment here. + if( !first_time ) + { + wxString languageSel; + + // Search for the current selection + for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) + { + if( s_Languages[ii].m_WX_Lang_Identifier == m_language_id ) + { + languageSel = s_Languages[ii].m_Lang_Label; + break; + } + } + + m_common_settings->Write( languageCfgKey, languageSel ); + } + + // Test if floating point notation is working (bug in cross compilation, using wine) + // Make a conversion double <=> string + double dtst = 0.5; + wxString msg; + + extern bool g_DisableFloatingPointLocalNotation; // See common.cpp + + g_DisableFloatingPointLocalNotation = false; + + msg << dtst; + double result; + msg.ToDouble( &result ); + + if( result != dtst ) // string to double encode/decode does not work! Bug detected + { + // Disable floating point localization: + g_DisableFloatingPointLocalNotation = true; + SetLocaleTo_C_standard( ); + } + + if( !m_locale->IsLoaded( dictionaryName ) ) + m_locale->AddCatalog( dictionaryName ); + + if( !retv ) + return retv; + + return m_locale->IsOk(); +} + + +void PGM_BASE::SetLanguageIdentifier( int menu_id ) +{ + wxLogDebug( wxT( "Select language ID %d from %zd possible languages." ), + menu_id, DIM( s_Languages ) ); + + for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) + { + if( menu_id == s_Languages[ii].m_KI_Lang_Identifier ) + { + setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); + break; + } + } +} + + +void PGM_BASE::SetLanguagePath() +{ + SEARCH_STACK guesses; + + SystemDirsAppend( &guesses ); + + // Add our internat dir to the wxLocale catalog of paths + for( unsigned i = 0; i < guesses.GetCount(); i++ ) + { + wxFileName fn( guesses[i], wxEmptyString ); + + // Append path for Windows and unix KiCad package install + fn.AppendDir( wxT( "share" ) ); + fn.AppendDir( wxT( "internat" ) ); + + if( fn.IsDirReadable() ) + { + wxLogDebug( wxT( "Adding locale lookup path: " ) + fn.GetPath() ); + wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() ); + } + + // Append path for unix standard install + fn.RemoveLastDir(); + fn.AppendDir( wxT( "kicad" ) ); + fn.AppendDir( wxT( "internat" ) ); + + if( fn.IsDirReadable() ) + { + wxLogDebug( wxT( "Adding locale lookup path: " ) + fn.GetPath() ); + wxLocale::AddCatalogLookupPathPrefix( fn.GetPath() ); + } + } +} + + +void PGM_BASE::AddMenuLanguageList( wxMenu* MasterMenu ) +{ + wxMenu* menu = NULL; + wxMenuItem* item = MasterMenu->FindItem( ID_LANGUAGE_CHOICE ); + + if( item ) // This menu exists, do nothing + return; + + menu = new wxMenu; + + for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) + { + wxString label; + + if( s_Languages[ii].m_DoNotTranslate ) + label = s_Languages[ii].m_Lang_Label; + else + label = wxGetTranslation( s_Languages[ii].m_Lang_Label ); + + AddMenuItem( menu, s_Languages[ii].m_KI_Lang_Identifier, + label, KiBitmap(s_Languages[ii].m_Lang_Icon ), + wxITEM_CHECK ); + } + + AddMenuItem( MasterMenu, menu, + ID_LANGUAGE_CHOICE, + _( "Language" ), + _( "Select application language (only for testing!)" ), + KiBitmap( language_xpm ) ); + + // Set Check mark on current selected language + for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) + { + if( m_language_id == s_Languages[ii].m_WX_Lang_Identifier ) + menu->Check( s_Languages[ii].m_KI_Lang_Identifier, true ); + else + menu->Check( s_Languages[ii].m_KI_Lang_Identifier, false ); + } +} + + +bool PGM_BASE::LockFile( const wxString& aFileName ) +{ + // first make absolute and normalize, to avoid that different lock files + // for the same file can be created + wxFileName fn( aFileName ); + + fn.MakeAbsolute(); + + // semaphore to protect the edition of the file by more than one instance + if( m_file_checker != NULL ) + { + // it means that we had an open file and we are opening a different one + delete m_file_checker; + } + + wxString lockFileName = fn.GetFullPath() + wxT( ".lock" ); + + lockFileName.Replace( wxT( "/" ), wxT( "_" ) ); + + // We can have filenames coming from Windows, so also convert Windows separator + lockFileName.Replace( wxT( "\\" ), wxT( "_" ) ); + + m_file_checker = new wxSingleInstanceChecker( lockFileName ); + + if( m_file_checker && + m_file_checker->IsAnotherRunning() ) + { + return false; + } + + return true; +} diff --git a/common/project.cpp b/common/project.cpp new file mode 100644 index 0000000000..48514ffd2a --- /dev/null +++ b/common/project.cpp @@ -0,0 +1,302 @@ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +PROJECT::PROJECT() +{ + memset( m_elems, 0, sizeof(m_elems) ); +} + +PROJECT::~PROJECT() +{ + /* @todo + careful here, this may work, but the virtual destructor may not + be in the same link image as PROJECT. Won't enable this until + we're more stable and destructor is assuredly in same image, i.e. + libki.so + for( unsigned i = 0; iRead( key, wxEmptyString ); + + if( !upath ) + break; + + aDst->AddPaths( upath, aIndex ); + } +} + + +// non-member so it can be moved easily, and kept REALLY private. +// Do NOT Clear() in here. +static void add_search_paths( SEARCH_STACK* aDst, const SEARCH_STACK& aSrc, int aIndex ) +{ + for( unsigned i=0; iAddPaths( aSrc[i], aIndex ); +} + + +/* +bool PROJECT::MaybeLoadProjectSettings( const std::vector& aFileSet ) +{ + // @todo + return true; +} +*/ + + +wxConfigBase* PROJECT::configCreate( const SEARCH_STACK& aSList, const wxString& aFileName, + const wxString& aGroupName, bool aForceUseLocalConfig ) +{ + wxConfigBase* cfg = 0; + wxFileName fn = aFileName; + + fn.SetExt( ProjectFileExtension ); + + // is there an edge transition, a change in m_project_filename? + if( m_project_name != fn ) + { + m_sch_search.Clear(); + + SetProjectFullName( fn.GetFullPath() ); + + // to the empty list, add project dir as first + m_sch_search.AddPaths( fn.GetPath() ); + + // append all paths from aSList + add_search_paths( &m_sch_search, aSList, -1 ); + + // addLibrarySearchPaths( SEARCH_STACK* aSP, wxConfigBase* aCfg ) + // This is undocumented, but somebody wanted to store !schematic! + // library search paths in the .kicad_common file? + add_search_paths( &m_sch_search, Pgm().CommonSettings(), -1 ); + +#if 1 && defined(DEBUG) + m_sch_search.Show( __func__ ); +#endif + } + + // Init local config filename + if( aForceUseLocalConfig || fn.FileExists() ) + { + wxString cur_pro_fn = fn.GetFullPath(); + + cfg = new wxFileConfig( wxEmptyString, wxEmptyString, cur_pro_fn, wxEmptyString ); + + cfg->DontCreateOnDemand(); + + if( aForceUseLocalConfig ) + { + SetProjectFullName( cur_pro_fn ); + return cfg; + } + + /* Check the application version against the version saved in the + * project file. + * + * TODO: Push the version test up the stack so that when one of the + * KiCad application version changes, the other applications + * settings do not get updated. Practically, this can go away. + * It isn't used anywhere as far as I know (WLS). + */ + + cfg->SetPath( aGroupName ); + + int def_version = 0; + int version = cfg->Read( wxT( "version" ), def_version ); + + if( version > 0 ) + { + cfg->SetPath( wxCONFIG_PATH_SEPARATOR ); + SetProjectFullName( cur_pro_fn ); + return cfg; + } + else // Version incorrect + { + delete cfg; + cfg = 0; + } + } + + // Search for the template kicad.pro file by using caller's SEARCH_STACK. + + wxString kicad_pro_template = aSList.FindValidPath( wxT( "kicad.pro" ) ); + + if( !kicad_pro_template ) + { + wxLogDebug( wxT( "Template file not found." ) ); + + fn = wxFileName( wxStandardPaths::Get().GetDocumentsDir(), + wxT( "kicad" ), ProjectFileExtension ); + } + else + { + fn = kicad_pro_template; + } + + cfg = new wxFileConfig( wxEmptyString, wxEmptyString, wxEmptyString, fn.GetFullPath() ); + cfg->DontCreateOnDemand(); + + SetProjectFullName( fn.GetFullPath() ); + return cfg; +} + + +void PROJECT::ConfigSave( const SEARCH_STACK& aSList, const wxString& aFileName, + const wxString& aGroupName, const PARAM_CFG_ARRAY& aParams ) +{ + std::auto_ptr cfg( configCreate( aSList, aFileName, aGroupName, FORCE_LOCAL_CONFIG ) ); + + cfg->SetPath( wxCONFIG_PATH_SEPARATOR ); + + cfg->Write( wxT( "update" ), DateAndTime() ); + + // @todo: pass in aLastClient wxString: + cfg->Write( wxT( "last_client" ), Pgm().App().GetAppName() ); + + // Save parameters + cfg->DeleteGroup( aGroupName ); // Erase all data + cfg->Flush(); + + cfg->SetPath( aGroupName ); + cfg->Write( wxT( "version" ), CONFIG_VERSION ); + + cfg->SetPath( wxCONFIG_PATH_SEPARATOR ); + + wxConfigSaveParams( cfg.get(), aParams, aGroupName ); + + cfg->SetPath( UNIX_STRING_DIR_SEP ); + + // cfg is deleted here by std::auto_ptr, that saves the *.pro file to disk +} + + +bool PROJECT::ConfigLoad( const SEARCH_STACK& aSList, const wxString& aFileName, + const wxString& aGroupName, const PARAM_CFG_ARRAY& aParams, + bool doLoadOnlyIfNew ) +{ + std::auto_ptr cfg( configCreate( aSList, aFileName, aGroupName, false ) ); + + cfg->SetPath( wxCONFIG_PATH_SEPARATOR ); + + wxString timestamp = cfg->Read( wxT( "update" ) ); + + if( doLoadOnlyIfNew && timestamp.size() && + timestamp == m_pro_date_and_time ) + { + return false; + } + + m_pro_date_and_time = timestamp; + + wxConfigLoadParams( cfg.get(), aParams, aGroupName ); + + return true; +} + diff --git a/common/search_stack.cpp b/common/search_stack.cpp new file mode 100644 index 0000000000..f4792f89c2 --- /dev/null +++ b/common/search_stack.cpp @@ -0,0 +1,196 @@ + +#include +#include +#include + + +#if defined(__MINGW32__) + #define PATH_SEPS wxT(";\r\n") +#else + #define PATH_SEPS wxT(":;\r\n") // unix == linux | mac +#endif + + +wxString SEARCH_STACK::FilenameWithRelativePathInSearchList( const wxString& aFullFilename ) +{ + /* If the library path is already in the library search paths + * list, just add the library name to the list. Otherwise, add + * the library name with the full or relative path. + * the relative path, when possible is preferable, + * because it preserve use of default libraries paths, when the path is a sub path of + * these default paths + * Note we accept only sub paths, + * not relative paths starting by ../ that are not subpaths and are outside kicad libs paths + */ + wxFileName fn = aFullFilename; + wxString filename = aFullFilename; + + unsigned pathlen = fn.GetPath().Len(); // path len, used to find the better (shortest) + // subpath within defaults paths + + for( unsigned kk = 0; kk < GetCount(); kk++ ) + { + fn = aFullFilename; + + // Search for the shortest subpath within 'this': + if( fn.MakeRelativeTo( (*this)[kk] ) ) + { + if( fn.GetPathWithSep().StartsWith( wxT("..") ) ) // Path outside kicad libs paths + continue; + + if( pathlen > fn.GetPath().Len() ) // A better (shortest) subpath is found + { + filename = fn.GetPathWithSep() + fn.GetFullName(); + pathlen = fn.GetPath().Len(); + } + } + } + + return filename; +} + + +void SEARCH_STACK::RemovePaths( const wxString& aPaths ) +{ + wxStringTokenizer tokenizer( aPaths, PATH_SEPS, wxTOKEN_STRTOK ); + + while( tokenizer.HasMoreTokens() ) + { + wxString path = tokenizer.GetNextToken(); + + if( Index( path, wxFileName::IsCaseSensitive() ) != wxNOT_FOUND ) + { + Remove( path ); + } + } +} + + +void SEARCH_STACK::AddPaths( const wxString& aPaths, int aIndex ) +{ + bool isCS = wxFileName::IsCaseSensitive(); + wxStringTokenizer tokenizer( aPaths, PATH_SEPS, wxTOKEN_STRTOK ); + + // appending all of them, on large or negative aIndex + if( unsigned( aIndex ) >= GetCount() ) + { + while( tokenizer.HasMoreTokens() ) + { + wxString path = tokenizer.GetNextToken(); + + if( wxFileName::IsDirReadable( path ) + && Index( path, isCS ) == wxNOT_FOUND ) + { + Add( path ); + } + } + } + + // inserting all of them: + else + { + while( tokenizer.HasMoreTokens() ) + { + wxString path = tokenizer.GetNextToken(); + + if( wxFileName::IsDirReadable( path ) + && Index( path, isCS ) == wxNOT_FOUND ) + { + Insert( path, aIndex ); + aIndex++; + } + } + } +} + + +wxString SEARCH_STACK::FindFileInSearchPaths( + const wxString& aFilename, const wxArrayString* aSubdirs ) +{ + wxPathList paths; + + for( unsigned i = 0; i < GetCount(); ++i ) + { + wxFileName fn( (*this)[i] ); + + if( aSubdirs ) + { + for( unsigned j = 0; j < aSubdirs->GetCount(); j++ ) + fn.AppendDir( (*aSubdirs)[j] ); + } + + if( fn.DirExists() ) + { + paths.Add( fn.GetPath() ); + } + } + + return paths.FindValidPath( aFilename ); +} + + +void RETAINED_PATH::Clear() +{ + m_retained_path.Clear(); +} + + +wxString RETAINED_PATH::LastVisitedPath( const SEARCH_STACK& aSStack, const wxString& aSubPathToSearch ) +{ + if( !!m_retained_path ) + return m_retained_path; + + wxString path; + + // Initialize default path to the main default lib path + // this is the second path in list (the first is the project path) + unsigned pcount = aSStack.GetCount(); + + if( pcount ) + { + unsigned ipath = 0; + + if( aSStack[0] == wxGetCwd() ) + ipath = 1; + + // First choice of path: + if( ipath < pcount ) + path = aSStack[ipath]; + + // Search a sub path matching aSubPathToSearch + if( !aSubPathToSearch.IsEmpty() ) + { + for( ; ipath < pcount; ipath++ ) + { + if( aSStack[ipath].Contains( aSubPathToSearch ) ) + { + path = aSStack[ipath]; + break; + } + } + } + } + + if( path.IsEmpty() ) + path = wxGetCwd(); + + return path; +} + + +void RETAINED_PATH::SaveLastVisitedPath( const wxString& aPath ) +{ + m_retained_path = aPath; +} + + +#if defined(DEBUG) +void SEARCH_STACK::Show( const char* aPrefix ) const +{ + printf( "%s SEARCH_STACK:\n", aPrefix ); + for( unsigned i=0; i #include #include #include -#include #include +#include + +#include +#include +#include +#include -/** - * Class PROCESS - * provides its own OnInit() handler. - */ -class PROCESS : public wxApp -{ -public: - - bool OnInit(); -}; - - -IMPLEMENT_APP( PROCESS ) +// The functions we use will cause the program launcher to pull stuff in +// during linkage, keep the map file in mind to see what's going into it. #if !wxCHECK_VERSION( 3, 0, 0 ) @@ -107,41 +104,6 @@ static wxString wxJoin(const wxArrayString& arr, const wxChar sep, #endif -// POLICY CHOICE: return the full path of the DSO to load from single_top. -static const wxString dso_full_path( const wxString& aAbsoluteArgv0 ) -{ - // Prefix basename with '_' and change extension to DSO_EXT. - - // POLICY CHOICE: Keep same path, and therefore installer must put the major DSO - // in same dir as top process module. Obviously alternatives are possible - // and that is why this is a separate function. One alternative would be to use - // a portion of CMAKE_INSTALL_PREFIX and navigate to a "lib" dir, but that - // would require a recompile any time you chose to install into a different place. - - // It is my decision to treat _eeschema.so and _pcbnew.so as "executables", - // not "libraries" in this regard, since most all program functionality lives - // in them. They are basically spin-offs from what was once a top process module. - // That may not make linux package maintainers happy, but that is not my job. - // Get over it. KiCad is not a trivial suite, and multiple platforms come - // into play, not merely linux. If it freaks you out, we can use a different - // file extension than ".so", but they are not purely libraries, else they - // would begin with "lib" in basename. Like I said, get over it, we're serving - // too many masters here: python, windows, linux, OSX, multiple versions of wx... - - wxFileName fn( aAbsoluteArgv0 ); - wxString basename( KIFACE_PREFIX ); // start with special prefix - - basename += fn.GetName(); // add argv[0]'s basename - fn.SetName( basename ); - - // here a suffix == an extension with a preceding '.', - // so skip the preceding '.' to get an extension - fn.SetExt( KIFACE_SUFFIX + 1 ); // special extension, + 1 => &KIFACE_SUFFIX[1] - - return fn.GetFullPath(); -} - - /// Put aPriorityPath in front of all paths in the value of aEnvVar. const wxString PrePendPath( const wxString& aEnvVar, const wxString& aPriorityPath ) { @@ -157,13 +119,13 @@ const wxString PrePendPath( const wxString& aEnvVar, const wxString& aPriorityPa /// Extend LIB_ENV_VAR list with the directory from which I came, prepending it. void SetLibEnvVar( const wxString& aAbsoluteArgv0 ) { - // POLICY CHOICE: Keep same path, so that installer MAY put the - // "subsidiary shared libraries" in the same directory as the top process module. + // POLICY CHOICE 2: Keep same path, so that installer MAY put the + // "subsidiary DSOs" in the same directory as the kiway top process modules. // A subsidiary shared library is one that is not a top level DSO, but rather // some shared library that a top level DSO needs to even be loaded. It is // a static link to a shared object from a top level DSO. - // This directory POLICY CHOICE is not the only dir in play, since LIB_ENV_VAR + // This directory POLICY CHOICE 2 is not the only dir in play, since LIB_ENV_VAR // has numerous path options in it, as does DSO searching on linux, windows, and OSX. // See "man ldconfig" on linux. What's being done here is for quick installs // into a non-standard place, and especially for Windows users who may not @@ -186,28 +148,119 @@ void SetLibEnvVar( const wxString& aAbsoluteArgv0 ) #endif } +// POLICY CHOICE 1: return the full path of the DSO to load from single_top. +static const wxString dso_full_path( const wxString& aAbsoluteArgv0 ) +{ + // Prefix basename with ${KIFACE_PREFIX} and change extension to ${KIFACE_SUFFIX} -// Only a single KIWAY is supported in this single_top top level component, -// which is dedicated to loading only a single DSO. -static KIWAY standalone; + // POLICY CHOICE 1: Keep same path, and therefore installer must put the kiface DSO + // in same dir as top process module. Obviously alternatives are possible + // and that is why this is a separate function. One alternative would be to use + // a portion of CMAKE_INSTALL_PREFIX and navigate to a "lib" dir, but that + // would require a recompile any time you chose to install into a different place. + + // It is my decision to treat _eeschema.kiface and _pcbnew.kiface as "executables", + // not "libraries" in this regard, since most all program functionality lives + // in them. They are basically spin-offs from what was once a top process module. + // That may not make linux package maintainers happy, but that is not my job. + // Get over it. KiCad is not a trivial suite, and multiple platforms come + // into play, not merely linux. For starters they will use extension ".kicad", + // but later in time morph to ".so". They are not purely libraries, else they + // would begin with "lib" in basename. Like I said, get over it, we're serving + // too many masters here: python, windows, linux, OSX, multiple versions of wx... + + wxFileName fn( aAbsoluteArgv0 ); + wxString basename( KIFACE_PREFIX ); // start with special prefix + + basename += fn.GetName(); // add argv[0]'s basename + fn.SetName( basename ); + + // Here a "suffix" == an extension with a preceding '.', + // so skip the preceding '.' to get an extension + fn.SetExt( KIFACE_SUFFIX + 1 ); // + 1 => &KIFACE_SUFFIX[1] + + return fn.GetFullPath(); +} // Use of this is arbitrary, remember single_top only knows about a single DSO. // Could have used one from the KIWAY also. static wxDynamicLibrary dso; +// Only a single KIWAY is supported in this single_top top level component, +// which is dedicated to loading only a single DSO. +static KIWAY kiway; + + +// implement a PGM_BASE and a wxApp side by side: + +/** + * Struct PGM_SINGLE_TOP + * implements PGM_BASE with its own OnPgmInit() and OnPgmExit(). + */ +static struct PGM_SINGLE_TOP : public PGM_BASE +{ + bool OnPgmInit( wxApp* aWxApp ); // overload PGM_BASE virtual + void OnPgmExit(); // overload PGM_BASE virtual + void MacOpenFile( const wxString& aFileName ); // overload PGM_BASE virtual +} program; + + +PGM_BASE& Pgm() +{ + return program; +} + + +/** + * Struct APP_SINGLE_TOP + * implements a bare naked wxApp (so that we don't become dependent on + * functionality in a wxApp derivative that we cannot deliver under wxPython). + */ +struct APP_SINGLE_TOP : public wxApp +{ + bool OnInit() // overload wxApp virtual + { + return Pgm().OnPgmInit( this ); + } + + int OnExit() // overload wxApp virtual + { + Pgm().OnPgmExit(); + return wxApp::OnExit(); + } + + /** + * Function MacOpenFile + * is specific to MacOSX (not used under Linux or Windows). + * MacOSX requires it for file association. + * @see http://wiki.wxwidgets.org/WxMac-specific_topics + */ + void MacOpenFile( const wxString& aFileName ) // overload wxApp virtual + { + Pgm().MacOpenFile( aFileName ); + } +}; + +IMPLEMENT_APP( APP_SINGLE_TOP ); + + /** * Function get_kiface_getter - * returns a KIFACE_GETTER_FUNC for the current process's main implemation link image. + * returns a KIFACE_GETTER_FUNC for the current process's main implementation + * link image. * - * @param aDSOName is an absolute full path to the DSO to load and find KIFACE_GETTER_FUNC within. + * @param aDSOName is an absolute full path to the DSO to load and find + * KIFACE_GETTER_FUNC within. * - * @return KIFACE_GETTER_FUNC* - a pointer to a function which can be called to get the KIFACE - * or NULL if the getter func was not found. If not found, it is possibly not version compatible - * since the lookup is done by name and the name contains the API version. + * @return KIFACE_GETTER_FUNC* - a pointer to a function which can be called to + * get the KIFACE or NULL if the getter func was not found. If not found, + * it is possibly not version compatible since the lookup is done by name and + * the name contains the API version. */ static KIFACE_GETTER_FUNC* get_kiface_getter( const wxString& aDSOName ) { +#if defined(BUILD_KIWAY_DLL) void* addr = NULL; if( !dso.Load( aDSOName, wxDL_VERBATIM | wxDL_NOW ) ) @@ -223,6 +276,11 @@ static KIFACE_GETTER_FUNC* get_kiface_getter( const wxString& aDSOName ) } return (KIFACE_GETTER_FUNC*) addr; + +#else + return &KIFACE_GETTER; + +#endif } @@ -230,32 +288,13 @@ static KIFACE* kiface; static int kiface_version; -bool PROCESS::OnInit() + +bool PGM_SINGLE_TOP::OnPgmInit( wxApp* aWxApp ) { - // Choose to use argv command line processing in base class's OnInit(). - // That choice is not mandatory, see wx's appbase.cpp OnInit(). - if( !wxApp::OnInit() ) - return false; + // first thing: set m_wx_app + m_wx_app = aWxApp; - wxStandardPathsBase& paths = wxStandardPaths::Get(); - -#if defined(DEBUG) - wxString dir = paths.GetLocalizedResourcesDir( wxT( "de" ), - wxStandardPaths::ResourceCat_None ); - - printf( "LocalizeResourcesDir:'%s'\n", TO_UTF8( dir ) ); - - wxString dummy( _( "translate this" ) ); -#endif - - wxString absoluteArgv0 = paths.GetExecutablePath(); - -#if 0 && defined(DEBUG) - printf( "argv[0]:'%s' absoluteArgv0:'%s'\n", - TO_UTF8( wxString( argv[0] ) ), - TO_UTF8( absoluteArgv0 ) - ); -#endif + wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath(); if( !wxIsAbsolutePath( absoluteArgv0 ) ) { @@ -267,6 +306,9 @@ bool PROCESS::OnInit() // KIFACE has hard dependencies on subsidiary DSOs below it. SetLibEnvVar( absoluteArgv0 ); + if( !initPgm() ) + return false; + wxString dname = dso_full_path( absoluteArgv0 ); // Get the getter. @@ -279,24 +321,170 @@ bool PROCESS::OnInit() return false; } - // Get the KIFACE, and give the DSO a single chance to do its - // "process level" initialization. - kiface = getter( &kiface_version, KIFACE_VERSION, &wxGetApp() ); + // Get the KIFACE. + kiface = getter( &kiface_version, KIFACE_VERSION, this ); - // KIFACE_GETTER_FUNC function comment (API) says the non-NULL is uconditional. + // KIFACE_GETTER_FUNC function comment (API) says the non-NULL is unconditional. wxASSERT_MSG( kiface, wxT( "attempted DSO has a bug, failed to return a KIFACE*" ) ); - // Use KIFACE to create a window that the KIFACE knows about, - // pass classId=0 for now. KIFACE::CreateWindow() is a virtual - // so we don't need to link to it. - wxFrame* frame = (wxFrame*) kiface->CreateWindow( 0, &standalone ); + // Give the DSO a single chance to do its "process level" initialization. + // "Process level" specifically means stay away from any projects in there. + if( !kiface->OnKifaceStart( this ) ) + return false; - SetTopWindow( frame ); + // Use KIFACE to create a top window that the KIFACE knows about. + // TOP_FRAME is passed on compiler command line from CMake, and is one of + // the types in ID_DRAWFRAME_TYPE. + // KIFACE::CreateWindow() is a virtual so we don't need to link to it. + // Remember its in the *.kiface DSO. +#if 0 + // this pulls in EDA_DRAW_FRAME type info, which we don't want in single_top + KIWAY_PLAYER* frame = dynamic_cast( kiface->CreateWindow( + NULL, TOP_FRAME, &kiway, KFCTL_STANDALONE ) ); +#else + KIWAY_PLAYER* frame = (KIWAY_PLAYER*) kiface->CreateWindow( + NULL, TOP_FRAME, &kiway, KFCTL_STANDALONE ); +#endif - frame->Centre(); + App().SetTopWindow( frame ); // wxApp gets a face. + + // Open project or file specified on the command line: + int argc = App().argc; + + if( argc > 1 ) + { + +#if defined(TOP_FRAME) && TOP_FRAME==GERBER_FRAME_TYPE + // gerbview handles multiple project data files, i.e. gerber files on cmd line. + + std::vector fileSet; + + // Load all files specified on the command line. + + for( int i=1; iOpenProjectFiles( fileSet ) ) + { + // OpenProjectFiles() API asks that it report failure to the UI. + // Nothing further to say here. + + // Fail the process startup if the file could not be opened, + // although this is an optional choice, one that can be reversed + // also in the KIFACE specific OpenProjectFiles() return value. + return false; + } + +#else + + wxFileName fn( argv[1] ); + + if( !fn.IsOk() ) + { + return false; + } + +#if defined(PGM_DATA_FILE_EXT) + // PGM_DATA_FILE_EXT is different for each compile, it may come from CMake + // on the compiler command line, or not. + if( !fn.GetExt() ) + fn.SetExt( wxT( PGM_DATA_FILE_EXT ) ); +#endif + + if( !Pgm().LockFile( fn.GetFullPath() ) ) + { + wxLogSysError( _( "This file is already open." ) ); + return false; + } + + if( fn.GetPath().size() ) + { + // wxSetWorkingDirectory does not like empty paths + wxSetWorkingDirectory( fn.GetPath() ); + + // @todo: setting CWD is taboo in a multi-project environment + } + + // Use the KIWAY_PLAYER::OpenProjectFiles() API function: + if( !frame->OpenProjectFiles( std::vector( 1, fn.GetFullPath() ) ) ) + { + // OpenProjectFiles() API asks that it report failure to the UI. + // Nothing further to say here. + + // Fail the process startup if the file could not be opened, + // although this is an optional choice, one that can be reversed + // also in the KIFACE specific OpenProjectFiles() return value. + return false; + } +#endif + } + else + { + /* The lean single_top program launcher has no access program settings, + else it would not be lean. That kind of functionality is in the + KIFACE now, but it cannot assume that it is the only KIFACE in memory. + So this looks like a dead concept here, or an expensive one in terms + of code size. + + wxString dir; + + if( m_pgmSettings->Read( workingDirKey, &dir ) && wxDirExists( dir ) ) + { + wxSetWorkingDirectory( dir ); + } + */ + } frame->Show(); return true; } + +void PGM_SINGLE_TOP::OnPgmExit() +{ + if( kiface ) + kiface->OnKifaceEnd(); + + saveCommonSettings(); + + // write common settings to disk, and destroy everything in PGM_BASE, + // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier + // than static destruction would. + PGM_BASE::destroy(); +} + + +void PGM_SINGLE_TOP::MacOpenFile( const wxString& aFileName ) +{ + wxFileName filename( aFileName ); + + if( filename.FileExists() ) + { +#if 0 + // this pulls in EDA_DRAW_FRAME type info, which we don't want in single_top + // link image. + KIWAY_PLAYER* frame = dynamic_cast( App().GetTopWindow() ); +#else + KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow(); +#endif + if( frame ) + frame->OpenProjectFiles( std::vector( 1, aFileName ) ); + } +} diff --git a/common/systemdirsappend.cpp b/common/systemdirsappend.cpp new file mode 100644 index 0000000000..65f7bfc2c0 --- /dev/null +++ b/common/systemdirsappend.cpp @@ -0,0 +1,129 @@ + +#include + +#include +#include +#include + + +// put your best guesses in here, send the computer on a wild goose chase, its +// got nothing else to do. + +void SystemDirsAppend( SEARCH_STACK* aSearchStack ) +{ + // No clearing is done here, the most general approach is NOT to assume that + // our appends will be the only thing in the stack. This function has no + // knowledge of caller's intentions. + + // wxPathList::AddEnvList() is broken, use SEARCH_STACK::AddPaths(). + // SEARCH_STACK::AddPaths() will verify readability and existence of + // each directory before adding. + SEARCH_STACK maybe; + + // User environment variable path is the first search path. Chances are + // if the user is savvy enough to set an environment variable they know + // what they are doing. It should take precedence over anything else. + // Otherwise don't set it. + maybe.AddPaths( wxGetenv( wxT( "KICAD" ) ) ); + + // This is from CMAKE_INSTALL_PREFIX. + // Useful when KiCad is installed by `make install`. + // Use as second ranked place. + maybe.AddPaths( wxT( DEFAULT_INSTALL_PATH ) ); + + // Add the directory for the user-dependent, program specific, data files: + // Unix: ~/.appname + // Windows: C:\Documents and Settings\username\Application Data\appname + // Mac: ~/Library/Application Support/appname + maybe.AddPaths( wxStandardPaths::Get().GetUserDataDir() ); + + { + // Should be full path to this program executable. + wxString bin_dir = Pgm().GetExecutablePath(); + +#if defined(__MINGW32__) + // bin_dir uses unix path separator. So to parse with wxFileName + // use windows separator, especially important for server inclusion: + // like: \\myserver\local_path . + bin_dir.Replace( UNIX_STRING_DIR_SEP, WIN_STRING_DIR_SEP ); +#endif + + wxFileName bin_fn( bin_dir, wxEmptyString ); + + // Dir of the global (not user-specific), application specific, data files. + // From wx docs: + // Unix: prefix/share/appname + // Windows: the directory where the executable file is located + // Mac: appname.app/Contents/SharedSupport bundle subdirectory + wxString data_dir = wxStandardPaths::Get().GetDataDir(); + + if( bin_fn.GetPath() != data_dir ) + { + // add data_dir if it is different from the bin_dir + maybe.AddPaths( data_dir ); + } + + // Up one level relative to binary path with "share" appended below. + bin_fn.RemoveLastDir(); + maybe.AddPaths( bin_fn.GetPath() ); + } + + /* The normal OS program file install paths allow for a binary to be + * installed in a different path from the library files. This is + * useful for development purposes so the library and documentation + * files do not need to be installed separately. If someone can + * figure out a way to implement this without #ifdef, please do. + */ +#if defined(__MINGW32__) + maybe.AddPaths( wxGetenv( wxT( "PROGRAMFILES" ) ) ); +#elif __WXMAC__ + maybe.AddPaths( wxString( wxGetenv( wxT( "HOME" ) ) ) + wxT( "/Library/Application Support" ) ); + maybe.AddPaths( wxT( "/Library/Application Support" ) ); +#else + maybe.AddPaths( wxGetenv( wxT( "PATH" ) ) ); +#endif + +#if defined(DEBUG) && 0 + maybe.Show( "maybe wish list" ); +#endif + + // Append 1) kicad, 2) kicad/share, 3) share, and 4) share/kicad to each + // possible base path in 'maybe'. Since SEARCH_STACK::AddPaths() will verify + // readability and existence of each directory, not all of these will be + // actually appended. + for( unsigned i = 0; i < maybe.GetCount(); ++i ) + { + wxFileName fn( maybe[i], wxEmptyString ); + + if( fn.GetPath().AfterLast( fn.GetPathSeparator() ) == wxT( "bin" ) ) + { + fn.RemoveLastDir(); + + if( !fn.GetDirCount() ) + continue; // at least on linux + } + + aSearchStack->AddPaths( fn.GetPath() ); + + fn.AppendDir( wxT( "kicad" ) ); + aSearchStack->AddPaths( fn.GetPath() ); // add maybe[i]/kicad + + fn.AppendDir( wxT( "share" ) ); + aSearchStack->AddPaths( fn.GetPath() ); // add maybe[i]/kicad/share + + fn.RemoveLastDir(); // ../ clear share + fn.RemoveLastDir(); // ../ clear kicad + + fn.AppendDir( wxT( "share" ) ); + aSearchStack->AddPaths( fn.GetPath() ); // add maybe[i]/share + + fn.AppendDir( wxT( "kicad" ) ); + aSearchStack->AddPaths( fn.GetPath() ); // add maybe[i]/share/kicad + } + +#if defined(DEBUG) && 0 + // final results: + aSearchStack->Show( __func__ ); +#endif +} + diff --git a/common/worksheet.cpp b/common/worksheet.cpp index db15b8b1db..215b2dd4b7 100644 --- a/common/worksheet.cpp +++ b/common/worksheet.cpp @@ -31,13 +31,13 @@ #include -#include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -170,7 +170,7 @@ wxString WS_DRAW_ITEM_LIST::BuildFullText( const wxString& aTextbase ) break; case 'K': - msg += productName + wxGetApp().GetAppName(); + msg += productName + Pgm().App().GetAppName(); msg += wxT( " " ) + GetBuildVersion(); break; diff --git a/common/wxwineda.cpp b/common/wxwineda.cpp index f68fe9a19c..8ff4c2c3d3 100644 --- a/common/wxwineda.cpp +++ b/common/wxwineda.cpp @@ -90,7 +90,7 @@ wxString EDA_GRAPHIC_TEXT_CTRL::FormatSize( EDA_UNITS_T aUnit, int textSize ) if( textSize > 3000 ) textSize = 3000; - return ReturnStringFromValue( aUnit, textSize ); + return StringFromValue( aUnit, textSize ); } @@ -124,7 +124,7 @@ int EDA_GRAPHIC_TEXT_CTRL::ParseSize( const wxString& sizeText, EDA_UNITS_T aUni { int textsize; - textsize = ReturnValueFromString( aUnit, sizeText ); + textsize = ValueFromString( aUnit, sizeText ); // Limit to reasonable size if( textsize < 10 ) @@ -209,8 +209,8 @@ wxPoint EDA_POSITION_CTRL::GetValue() { wxPoint coord; - coord.x = ReturnValueFromString( m_UserUnit, m_FramePosX->GetValue() ); - coord.y = ReturnValueFromString( m_UserUnit, m_FramePosY->GetValue() ); + coord.x = ValueFromString( m_UserUnit, m_FramePosX->GetValue() ); + coord.y = ValueFromString( m_UserUnit, m_FramePosY->GetValue() ); return coord; } @@ -230,11 +230,11 @@ void EDA_POSITION_CTRL::SetValue( int x_value, int y_value ) m_Pos_To_Edit.x = x_value; m_Pos_To_Edit.y = y_value; - msg = ReturnStringFromValue( m_UserUnit, m_Pos_To_Edit.x ); + msg = StringFromValue( m_UserUnit, m_Pos_To_Edit.x ); m_FramePosX->Clear(); m_FramePosX->SetValue( msg ); - msg = ReturnStringFromValue( m_UserUnit, m_Pos_To_Edit.y ); + msg = StringFromValue( m_UserUnit, m_Pos_To_Edit.y ); m_FramePosY->Clear(); m_FramePosY->SetValue( msg ); } @@ -279,7 +279,7 @@ EDA_VALUE_CTRL::EDA_VALUE_CTRL( wxWindow* parent, const wxString& title, BoxSizer->Add( m_Text, 0, wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 ); - wxString stringvalue = ReturnStringFromValue( m_UserUnit, m_Value ); + wxString stringvalue = StringFromValue( m_UserUnit, m_Value ); m_ValueCtrl = new wxTextCtrl( parent, -1, stringvalue ); BoxSizer->Add( m_ValueCtrl, @@ -301,7 +301,7 @@ int EDA_VALUE_CTRL::GetValue() int coord; wxString txtvalue = m_ValueCtrl->GetValue(); - coord = ReturnValueFromString( m_UserUnit, txtvalue ); + coord = ValueFromString( m_UserUnit, txtvalue ); return coord; } @@ -312,7 +312,7 @@ void EDA_VALUE_CTRL::SetValue( int new_value ) m_Value = new_value; - buffer = ReturnStringFromValue( m_UserUnit, m_Value ); + buffer = StringFromValue( m_UserUnit, m_Value ); m_ValueCtrl->SetValue( buffer ); } diff --git a/common/zoom.cpp b/common/zoom.cpp index 6add6bc2f6..b1652d9fa9 100644 --- a/common/zoom.cpp +++ b/common/zoom.cpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index 53f39ada5e..a5942f0f5d 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -1,8 +1,7 @@ -add_definitions( -DCVPCB ) -### -# Includes -### +set( MAKE_LINK_MAPS true ) + +add_definitions( -DCVPCB ) include_directories( BEFORE ${INC_BEFORE} ) include_directories( @@ -15,12 +14,13 @@ include_directories( ${INC_AFTER} ) -### -# Sources -### + set( CVPCB_DIALOGS - dialogs/dialog_cvpcb_config.cpp - dialogs/dialog_cvpcb_config_fbp.cpp + + # These 2 still use search paths, which don't exist in footprint land. +# dialogs/dialog_cvpcb_config.cpp +# dialogs/dialog_cvpcb_config_fbp.cpp + dialogs/dialog_display_options.cpp dialogs/dialog_display_options_base.cpp ../pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -40,101 +40,187 @@ set( CVPCB_SRCS class_footprints_listbox.cpp class_library_listbox.cpp cvframe.cpp - cvpcb.cpp listboxes.cpp menubar.cpp readwrite_dlgs.cpp tool_cvpcb.cpp ) -### -# Windows resource file -### -if( WIN32 ) - if( MINGW ) - # CVPCB_RESOURCES variable is set by the macro. - mingw_resource_compiler( cvpcb ) - else() - set( CVPCB_RESOURCES cvpcb.rc ) - endif() + +if( MINGW ) + # CVPCB_RESOURCES variable is set by the macro. + mingw_resource_compiler( cvpcb ) endif() -### -# Apple resource files -### + if( APPLE ) set( CVPCB_RESOURCES cvpcb.icns cvpcb_doc.icns ) - set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/cvpcb.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/cvpcb.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) - set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/cvpcb_doc.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/cvpcb_doc.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) set( MACOSX_BUNDLE_ICON_FILE cvpcb.icns ) set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.cvpcb ) endif() -### -# Create the cvpcb executable -### -add_executable( cvpcb WIN32 MACOSX_BUNDLE - ${CVPCB_SRCS} - ${CVPCB_DIALOGS} - ${CVPCB_RESOURCES} - ) -### -# Set properties for APPLE on cvpcb target -### -if( APPLE ) - set_target_properties( cvpcb PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ) +if( USE_KIWAY_DLLS ) + add_executable( cvpcb WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ../common/pgm_base.cpp + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=CVPCB_FRAME_TYPE;PGM_DATA_FILE_EXT=\"net\";BUILD_KIWAY_DLL" + ) + target_link_libraries( cvpcb + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. + common + bitmaps + ${wxWidgets_LIBRARIES} + ) + if( MAKE_LINK_MAPS ) + set_target_properties( cvpcb PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=cvpcb.map" ) + endif() + + # the main cvpcb program, in DSO form. + add_library( cvpcb_kiface MODULE + cvpcb.cpp + ${CVPCB_SRCS} + ${CVPCB_DIALOGS} + ${CVPCB_RESOURCES} + ) + set_target_properties( cvpcb_kiface PROPERTIES + OUTPUT_NAME cvpcb + PREFIX ${KIFACE_PREFIX} + SUFFIX ${KIFACE_SUFFIX} + ) + target_link_libraries( cvpcb_kiface + 3d-viewer + pcbcommon + pcad2kicadpcb + common + bitmaps + polygon + gal + ${wxWidgets_LIBRARIES} + ${OPENGL_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ${GLEW_LIBRARIES} + ${CAIRO_LIBRARIES} + ${PIXMAN_LIBRARY} + ) + + # Only for win32 cross compilation using MXE + if( WIN32 AND MSYS AND CMAKE_CROSSCOMPILING ) + target_link_libraries( cvpcb_kiface + opengl32 + glu32 + pixman-1 + fontconfig + freetype + bz2 + ) + endif() + + if( BUILD_GITHUB_PLUGIN ) + target_link_libraries( cvpcb_kiface github_plugin ) + endif() + + # Must follow github_plugin + target_link_libraries( cvpcb_kiface ${Boost_LIBRARIES} ) + + if( UNIX AND NOT APPLE ) + # -lrt must follow Boost + target_link_libraries( cvpcb_kiface rt ) + endif() + + if( APPLE ) + set_target_properties( cvpcb PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) + endif() + + set_source_files_properties( cvpcb.cpp PROPERTIES + # The KIFACE is in cvpcb.cpp, export it: + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + + if( MAKE_LINK_MAPS ) + set_target_properties( cvpcb_kiface PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=_cvpcb.kiface.map" ) + endif() + + # if building cvpcb, then also build cvpcb_kiface if out of date. + add_dependencies( cvpcb cvpcb_kiface ) + + # these 2 binaries are a matched set, keep them together: + install( TARGETS cvpcb + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + install( TARGETS cvpcb_kiface + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +else() + + add_executable( cvpcb WIN32 MACOSX_BUNDLE + ${CVPCB_SRCS} + ${CVPCB_DIALOGS} + ${CVPCB_RESOURCES} + ) + target_link_libraries( cvpcb + 3d-viewer + pcbcommon + pcad2kicadpcb + common + bitmaps + polygon + gal + ${wxWidgets_LIBRARIES} + ${OPENGL_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ${GLEW_LIBRARIES} + ${CAIRO_LIBRARIES} + ${PIXMAN_LIBRARY} + ) + + # Only for win32 cross compilation using MXE + if( WIN32 AND MSYS AND CMAKE_CROSSCOMPILING ) + target_link_libraries( cvpcb + opengl32 + glu32 + pixman-1 + fontconfig + freetype + bz2 + ) + endif() + + if( BUILD_GITHUB_PLUGIN ) + target_link_libraries( cvpcb github_plugin ) + endif() + + # Must follow github_plugin + target_link_libraries( cvpcb ${Boost_LIBRARIES} ) + + if( APPLE ) + set_target_properties( cvpcb PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) + endif() + + install( TARGETS cvpcb + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + endif() - -### -# Link executable target cvpcb with correct libraries -### -target_link_libraries( cvpcb - 3d-viewer - pcbcommon - pcad2kicadpcb - common - bitmaps - polygon - gal - ${wxWidgets_LIBRARIES} - ${OPENGL_LIBRARIES} - ${GDI_PLUS_LIBRARIES} - ${GLEW_LIBRARIES} - ${CAIRO_LIBRARIES} - ${PIXMAN_LIBRARY} - ) - -# Only for win32 cross compilation using MXE -if( WIN32 AND MSYS AND CMAKE_CROSSCOMPILING ) -target_link_libraries(cvpcb - opengl32 - glu32 - pixman-1 - fontconfig - freetype - bz2 - ) -endif() - - -if( BUILD_GITHUB_PLUGIN ) - target_link_libraries( cvpcb github_plugin ) -endif() - -# Must follow github_plugin -target_link_libraries( cvpcb ${Boost_LIBRARIES} ) - - -### -# Add cvpcb as install target -### -install( TARGETS cvpcb - DESTINATION ${KICAD_BIN} - COMPONENT binary - ) diff --git a/cvpcb/autosel.cpp b/cvpcb/autosel.cpp index f9252eddbd..2b40fa4e40 100644 --- a/cvpcb/autosel.cpp +++ b/cvpcb/autosel.cpp @@ -29,9 +29,10 @@ #include #include +#include #include #include -#include +#include #include #include @@ -87,6 +88,7 @@ void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event ) char Line[1024]; FILE* file; size_t ii; + SEARCH_STACK& search = Prj().SchSearchS(); if( m_netlist.IsEmpty() ) return; @@ -99,17 +101,17 @@ void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event ) if( !fn.HasExt() ) { fn.SetExt( FootprintAliasFileExtension ); - // above fails if filename have more than one point + // above fails if filename has more than one point } else { fn.SetExt( fn.GetExt() + wxT( "." ) + FootprintAliasFileExtension ); } - tmp = wxGetApp().FindLibraryPath( fn ); + tmp = search.FindValidPath( fn ); if( !tmp ) { - msg.Printf( _( "Footprint alias library file <%s> could not be found in the " + msg.Printf( _( "Footprint alias library file '%s' could not be found in the " "default search paths." ), GetChars( fn.GetFullName() ) ); wxMessageBox( msg, titleLibLoadError, wxOK | wxICON_ERROR ); diff --git a/cvpcb/cfg.cpp b/cvpcb/cfg.cpp index 6823daa777..28c9d9816e 100644 --- a/cvpcb/cfg.cpp +++ b/cvpcb/cfg.cpp @@ -27,11 +27,12 @@ */ #include -#include +#include +#include #include #include #include -#include +#include #include #include #include @@ -46,24 +47,24 @@ #define GROUPEQU wxT("/cvpcb/libraries") -PARAM_CFG_ARRAY& CVPCB_MAINFRAME::GetProjectFileParameters( void ) +PARAM_CFG_ARRAY& CVPCB_MAINFRAME::GetProjectFileParameters() { if( !m_projectFileParams.empty() ) return m_projectFileParams; - m_projectFileParams.push_back( new PARAM_CFG_BASE( GROUPLIB, - PARAM_COMMAND_ERASE ) ); - m_projectFileParams.push_back( new PARAM_CFG_LIBNAME_LIST( wxT( "LibName" ), - &m_ModuleLibNames, - GROUPLIB ) ); - m_projectFileParams.push_back( new PARAM_CFG_LIBNAME_LIST( wxT( "EquName" ), - &m_AliasLibNames, - GROUPEQU ) ); - m_projectFileParams.push_back( new PARAM_CFG_WXSTRING( wxT( "NetIExt" ), - &m_NetlistFileExtension ) ); - m_projectFileParams.push_back( new PARAM_CFG_FILENAME( wxT( "LibDir" ), - &m_UserLibraryPath, - GROUPLIB ) ); + m_projectFileParams.push_back( new PARAM_CFG_BASE( GROUPLIB, PARAM_COMMAND_ERASE ) ); + + m_projectFileParams.push_back( new PARAM_CFG_LIBNAME_LIST( + wxT( "LibName" ), &m_ModuleLibNames, GROUPLIB ) ); + + m_projectFileParams.push_back( new PARAM_CFG_LIBNAME_LIST( + wxT( "EquName" ), &m_AliasLibNames, GROUPEQU ) ); + + m_projectFileParams.push_back( new PARAM_CFG_WXSTRING( + wxT( "NetIExt" ), &m_NetlistFileExtension ) ); + + m_projectFileParams.push_back( new PARAM_CFG_FILENAME( + wxT( "LibDir" ), &m_UserLibraryPath, GROUPLIB ) ); return m_projectFileParams; } @@ -71,42 +72,37 @@ PARAM_CFG_ARRAY& CVPCB_MAINFRAME::GetProjectFileParameters( void ) void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName ) { - wxFileName fn = aFileName; + wxFileName fn( aFileName ); + PROJECT& prj = Prj(); m_ModuleLibNames.Clear(); m_AliasLibNames.Clear(); - if( fn.GetExt() != ProjectFileExtension ) - fn.SetExt( ProjectFileExtension ); + fn.SetExt( ProjectFileExtension ); - wxGetApp().RemoveLibraryPath( m_UserLibraryPath ); - - wxGetApp().ReadProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters(), false ); + // was: Pgm().ReadProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters(), false ); + prj.ConfigLoad( prj.PcbSearchS(), fn.GetFullPath(), GROUP, GetProjectFileParameters(), false ); if( m_NetlistFileExtension.IsEmpty() ) m_NetlistFileExtension = wxT( "net" ); - // User library path takes precedent over default library search paths. - wxGetApp().InsertLibraryPath( m_UserLibraryPath, 1 ); + // empty the table, Load() it again below. + FootprintLibs()->Clear(); - delete m_footprintLibTable; + /* this is done by ConfigLoad(), and that sets the env var too. + prj.SetProjectFullName( fn.GetFullPath() ); + */ - // Attempt to load the project footprint library table if it exists. - m_footprintLibTable = new FP_LIB_TABLE(); - - if( m_DisplayFootprintFrame ) - m_DisplayFootprintFrame->SetFootprintLibTable( m_footprintLibTable ); - - wxFileName projectFpLibTableFileName; - - projectFpLibTableFileName = FP_LIB_TABLE::GetProjectFileName( fn ); - FP_LIB_TABLE::SetProjectPathEnvVariable( projectFpLibTableFileName ); + wxFileName projectFpLibTableFileName = FP_LIB_TABLE::GetProjectTableFileName( fn.GetFullPath() ); try { - m_footprintLibTable->Load( projectFpLibTableFileName, m_globalFootprintTable ); + // Stack the project specific FP_LIB_TABLE overlay on top of the global table. + // ~FP_LIB_TABLE() will not touch the fallback table, so multiple projects may + // stack this way, all using the same global fallback table. + FootprintLibs()->Load( projectFpLibTableFileName, &GFootprintTable ); } - catch( IO_ERROR ioe ) + catch( const IO_ERROR& ioe ) { DisplayError( this, ioe.errorText ); } @@ -136,5 +132,11 @@ void CVPCB_MAINFRAME::SaveProjectFile( wxCommandEvent& aEvent ) if( !IsWritable( fn ) ) return; - wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters() ); + // was: + // Pgm().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters() ); + + PROJECT& prj = Prj(); + SEARCH_STACK& search = prj.SchSearchS(); + + prj.ConfigSave( search, fn.GetFullPath(), GROUP, GetProjectFileParameters() ); } diff --git a/cvpcb/class_DisplayFootprintsFrame.cpp b/cvpcb/class_DisplayFootprintsFrame.cpp index 4c0b4e266a..8c3054c6c0 100644 --- a/cvpcb/class_DisplayFootprintsFrame.cpp +++ b/cvpcb/class_DisplayFootprintsFrame.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include @@ -73,25 +73,24 @@ END_EVENT_TABLE() #define DISPLAY_FOOTPRINTS_FRAME_NAME wxT( "CmpFrame" ) -DISPLAY_FOOTPRINTS_FRAME::DISPLAY_FOOTPRINTS_FRAME( CVPCB_MAINFRAME* parent, - const wxString& title, - const wxPoint& pos, - const wxSize& size, long style ) : - PCB_BASE_FRAME( parent, CVPCB_DISPLAY_FRAME_TYPE, title, pos, size, - style, DISPLAY_FOOTPRINTS_FRAME_NAME ) +DISPLAY_FOOTPRINTS_FRAME::DISPLAY_FOOTPRINTS_FRAME( KIWAY* aKiway, CVPCB_MAINFRAME* aParent ) : + PCB_BASE_FRAME( aKiway, aParent, CVPCB_DISPLAY_FRAME_TYPE, _( "Module" ), + wxDefaultPosition, wxDefaultSize, + KICAD_DEFAULT_DRAWFRAME_STYLE, DISPLAY_FOOTPRINTS_FRAME_NAME ) { m_FrameName = DISPLAY_FOOTPRINTS_FRAME_NAME; m_showAxis = true; // true to draw axis. // Give an icon wxIcon icon; + icon.CopyFromBitmap( KiBitmap( icon_cvpcb_xpm ) ); SetIcon( icon ); SetBoard( new BOARD() ); SetScreen( new PCB_SCREEN( GetPageSizeIU() ) ); - LoadSettings(); + LoadSettings( config() ); // Initialize grid id to a default value if not found in config or bad: if( (m_LastGridSizeId <= 0) || @@ -149,7 +148,8 @@ DISPLAY_FOOTPRINTS_FRAME::~DISPLAY_FOOTPRINTS_FRAME() delete GetScreen(); SetScreen( NULL ); // Be sure there is no double deletion - ( (CVPCB_MAINFRAME*) wxGetApp().GetTopWindow() )->m_DisplayFootprintFrame = NULL; + // a crash would be better than this uncommented: + // ( (CVPCB_MAINFRAME*) Pgm().GetTopWindow() )->m_DisplayFootprintFrame = NULL; } @@ -438,7 +438,7 @@ void DISPLAY_FOOTPRINTS_FRAME::Show3D_Frame( wxCommandEvent& event ) return; } - m_Draw3DFrame = new EDA_3D_FRAME( this, _( "3D Viewer" ), KICAD_DEFAULT_3D_DRAWFRAME_STYLE ); + m_Draw3DFrame = new EDA_3D_FRAME( &Kiway(), this, _( "3D Viewer" ), KICAD_DEFAULT_3D_DRAWFRAME_STYLE ); m_Draw3DFrame->Show( true ); } @@ -493,7 +493,7 @@ MODULE* DISPLAY_FOOTPRINTS_FRAME::Get_Module( const wxString& aFootprintName ) wxLogDebug( wxT( "Load footprint <%s> from library <%s>." ), fpname.c_str(), nickname.c_str() ); - footprint = m_footprintLibTable->FootprintLoad( FROM_UTF8( nickname.c_str() ), FROM_UTF8( fpname.c_str() ) ); + footprint = FootprintLibs()->FootprintLoad( FROM_UTF8( nickname.c_str() ), FROM_UTF8( fpname.c_str() ) ); } catch( IO_ERROR ioe ) { diff --git a/cvpcb/class_DisplayFootprintsFrame.h b/cvpcb/class_DisplayFootprintsFrame.h index 52b1366813..71e412fc0c 100644 --- a/cvpcb/class_DisplayFootprintsFrame.h +++ b/cvpcb/class_DisplayFootprintsFrame.h @@ -40,10 +40,7 @@ class CVPCB_MAINFRAME; class DISPLAY_FOOTPRINTS_FRAME : public PCB_BASE_FRAME { public: - DISPLAY_FOOTPRINTS_FRAME( CVPCB_MAINFRAME* father, const wxString& title, - const wxPoint& pos, const wxSize& size, - long style = KICAD_DEFAULT_DRAWFRAME_STYLE ); - + DISPLAY_FOOTPRINTS_FRAME( KIWAY* aKiway, CVPCB_MAINFRAME* aParent ); ~DISPLAY_FOOTPRINTS_FRAME(); void OnCloseWindow( wxCloseEvent& Event ); diff --git a/cvpcb/class_footprints_listbox.cpp b/cvpcb/class_footprints_listbox.cpp index fe3b38e572..7c1ab079e4 100644 --- a/cvpcb/class_footprints_listbox.cpp +++ b/cvpcb/class_footprints_listbox.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/cvpcb/cvframe.cpp b/cvpcb/cvframe.cpp index 307ee5829b..4c1e922e5e 100644 --- a/cvpcb/cvframe.cpp +++ b/cvpcb/cvframe.cpp @@ -29,7 +29,8 @@ #include #include -#include +#include +#include #include #include #include @@ -104,9 +105,10 @@ END_EVENT_TABLE() #define CVPCB_MAINFRAME_NAME wxT( "CvpcbFrame" ) -CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : - EDA_BASE_FRAME( NULL, CVPCB_FRAME_TYPE, title, wxDefaultPosition, - wxDefaultSize, style, CVPCB_MAINFRAME_NAME ) + +CVPCB_MAINFRAME::CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ) : + KIWAY_PLAYER( aKiway, aParent, CVPCB_FRAME_TYPE, wxT( "CvPCB" ), wxDefaultPosition, + wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, CVPCB_MAINFRAME_NAME ) { m_FrameName = CVPCB_MAINFRAME_NAME; m_ListCmp = NULL; @@ -119,9 +121,7 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : m_KeepCvpcbOpen = false; m_undefinedComponentCnt = 0; m_skipComponentSelect = false; - - m_globalFootprintTable = NULL; - m_footprintLibTable = NULL; + m_NetlistFileExtension = wxT( "net" ); /* Name of the document footprint list * usually located in share/modules/footprints_doc @@ -137,7 +137,7 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : SetAutoLayout( true ); - LoadSettings(); + LoadSettings( config() ); if( m_FrameSize.x < FRAME_MIN_SIZE_X ) m_FrameSize.x = FRAME_MIN_SIZE_X; @@ -194,36 +194,6 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( const wxString& title, long style ) : Right().BestSize( (int) ( m_FrameSize.x * 0.30 ), m_FrameSize.y ) ); m_auimgr.Update(); - - if( m_globalFootprintTable == NULL ) - { - try - { - m_globalFootprintTable = new FP_LIB_TABLE(); - - if( !FP_LIB_TABLE::LoadGlobalTable( *m_globalFootprintTable ) ) - { - DisplayInfoMessage( this, wxT( "You have run CvPcb for the first time using the " - "new footprint library table method of finding " - "footprints. CvPcb has either copied the default " - "table or created an empty table in your home " - "folder. You must first configure the library " - "table to include all footprint libraries not " - "included with KiCad. See the \"Footprint Library " - "Table\" section of the CvPcb documentation for " - "more information." ) ); - } - } - catch( IO_ERROR ioe ) - { - wxString msg; - msg.Printf( _( "An error occurred attempting to load the global footprint library " - "table:\n\n%s" ), GetChars( ioe.errorText ) ); - DisplayError( this, msg ); - } - - m_footprintLibTable = new FP_LIB_TABLE( m_globalFootprintTable ); - } } @@ -233,28 +203,37 @@ CVPCB_MAINFRAME::~CVPCB_MAINFRAME() } -void CVPCB_MAINFRAME::LoadSettings() +FP_LIB_TABLE* CVPCB_MAINFRAME::FootprintLibs() const { - wxASSERT( wxGetApp().GetSettings() != NULL ); + PROJECT& prj = Prj(); + FP_LIB_TABLE* tbl = dynamic_cast( prj.Elem( PROJECT::FPTBL ) ); - wxConfig* cfg = wxGetApp().GetSettings(); + if( !tbl ) + { + tbl = new FP_LIB_TABLE( &GFootprintTable ); + prj.Elem( PROJECT::FPTBL, tbl ); + } - EDA_BASE_FRAME::LoadSettings(); - cfg->Read( KeepCvpcbOpenEntry, &m_KeepCvpcbOpen, true ); - cfg->Read( FootprintDocFileEntry, &m_DocModulesFileName, + return tbl; +} + + +void CVPCB_MAINFRAME::LoadSettings( wxConfigBase* aCfg ) +{ + EDA_BASE_FRAME::LoadSettings( aCfg ); + + aCfg->Read( KeepCvpcbOpenEntry, &m_KeepCvpcbOpen, true ); + aCfg->Read( FootprintDocFileEntry, &m_DocModulesFileName, DEFAULT_FOOTPRINTS_LIST_FILENAME ); } -void CVPCB_MAINFRAME::SaveSettings() +void CVPCB_MAINFRAME::SaveSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); + EDA_BASE_FRAME::SaveSettings( aCfg ); - wxConfig* cfg = wxGetApp().GetSettings(); - - EDA_BASE_FRAME::SaveSettings(); - cfg->Write( KeepCvpcbOpenEntry, m_KeepCvpcbOpen ); - cfg->Write( FootprintDocFileEntry, m_DocModulesFileName ); + aCfg->Write( KeepCvpcbOpenEntry, m_KeepCvpcbOpen ); + aCfg->Write( FootprintDocFileEntry, m_DocModulesFileName ); int state = 0; @@ -267,7 +246,7 @@ void CVPCB_MAINFRAME::SaveSettings() if( m_mainToolBar->GetToolToggled( ID_CVPCB_FOOTPRINT_DISPLAY_BY_LIBRARY_LIST ) ) state |= FOOTPRINTS_LISTBOX::BY_LIBRARY; - cfg->Write( wxT( FILTERFOOTPRINTKEY ), state ); + aCfg->Write( wxT( FILTERFOOTPRINTKEY ), state ); } @@ -321,10 +300,10 @@ void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& Event ) } // Close the help frame - if( wxGetApp().GetHtmlHelpController() ) + if( Pgm().GetHtmlHelpController() ) { - if( wxGetApp().GetHtmlHelpController()->GetFrame() )// returns NULL if no help frame active - wxGetApp().GetHtmlHelpController()->GetFrame()->Close( true ); + if( Pgm().GetHtmlHelpController()->GetFrame() )// returns NULL if no help frame active + Pgm().GetHtmlHelpController()->GetFrame()->Close( true ); } if( m_NetlistFileName.IsOk() ) @@ -460,9 +439,8 @@ void CVPCB_MAINFRAME::DelAssociations( wxCommandEvent& event ) void CVPCB_MAINFRAME::LoadNetList( wxCommandEvent& event ) { - wxString oldPath; - wxFileName newFileName; int id = event.GetId(); + wxFileName newFileName; if( id >= wxID_FILE1 && id <= wxID_FILE9 ) { @@ -483,45 +461,59 @@ void CVPCB_MAINFRAME::LoadNetList( wxCommandEvent& event ) if( newFileName == m_NetlistFileName ) return; - if( m_NetlistFileName.DirExists() ) - oldPath = m_NetlistFileName.GetPath(); + OpenProjectFiles( std::vector( 1, newFileName.GetFullPath() ) ); +} - /* Update the library search path list. */ - if( wxGetApp().GetLibraryPathList().Index( oldPath ) != wxNOT_FOUND ) - wxGetApp().GetLibraryPathList().Remove( oldPath ); - wxGetApp().GetLibraryPathList().Insert( newFileName.GetPath(), 0 ); - m_NetlistFileName = newFileName; - ReadNetListAndLinkFiles(); +bool CVPCB_MAINFRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) +{ + if( aFileSet.size() == 1 ) + { + m_NetlistFileName = aFileSet[0]; + ReadNetListAndLinkFiles(); + + UpdateTitle(); + + return true; + } + + return false; } void CVPCB_MAINFRAME::ConfigCvpcb( wxCommandEvent& event ) { - DIALOG_CVPCB_CONFIG ConfigFrame( this ); + /* This is showing FOOTPRINT search paths, which are obsoleted. + I am removing this for the time being, since cvpcb will soon be part of pcbnew. - ConfigFrame.ShowModal(); + DIALOG_CVPCB_CONFIG dlg( this ); + + dlg.ShowModal(); + */ } void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent ) { bool tableChanged = false; - int r = InvokePcbLibTableEditor( this, m_globalFootprintTable, m_footprintLibTable ); + int r = InvokePcbLibTableEditor( this, &GFootprintTable, FootprintLibs() ); if( r & 1 ) { try { FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() ); - m_globalFootprintTable->Format( &sf, 0 ); + + GFootprintTable.Format( &sf, 0 ); tableChanged = true; } - catch( IO_ERROR& ioe ) + catch( const IO_ERROR& ioe ) { - wxString msg; - msg.Printf( _( "Error occurred saving the global footprint library " - "table:\n\n%s" ), ioe.errorText.GetData() ); + wxString msg = wxString::Format( _( + "Error occurred saving the global footprint library " + "table:\n\n%s" ), + GetChars( ioe.errorText ) ); + wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } @@ -535,7 +527,7 @@ void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent ) try { FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); - m_footprintLibTable->Format( &sf, 0 ); + FootprintLibs()->Format( &sf, 0 ); tableChanged = true; } catch( IO_ERROR& ioe ) @@ -550,7 +542,7 @@ void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent ) if( tableChanged ) { BuildLIBRARY_LISTBOX(); - m_footprints.ReadFootprintFiles( m_footprintLibTable ); + m_footprints.ReadFootprintFiles( FootprintLibs() ); } } @@ -576,7 +568,7 @@ void CVPCB_MAINFRAME::SetLanguage( wxCommandEvent& event ) void CVPCB_MAINFRAME::DisplayDocFile( wxCommandEvent& event ) { - GetAssociatedDocument( this, m_DocModulesFileName, &wxGetApp().GetLibraryPathList() ); + GetAssociatedDocument( this, m_DocModulesFileName, &Kiface().KifaceSearch() ); } @@ -748,16 +740,17 @@ void CVPCB_MAINFRAME::DisplayStatus() bool CVPCB_MAINFRAME::LoadFootprintFiles() { + FP_LIB_TABLE* fptbl = FootprintLibs(); + // Check if there are footprint libraries in the footprint library table. - if( m_footprintLibTable == NULL || !m_footprintLibTable->GetLogicalLibs().size() ) + if( !fptbl || !fptbl->GetLogicalLibs().size() ) { wxMessageBox( _( "No PCB footprint libraries are listed in the current footprint " "library table." ), _( "Configuration Error" ), wxOK | wxICON_ERROR ); return false; } - if( m_footprintLibTable != NULL ) - m_footprints.ReadFootprintFiles( m_footprintLibTable ); + m_footprints.ReadFootprintFiles( fptbl ); if( m_footprints.GetErrorCount() ) { @@ -770,20 +763,18 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles() void CVPCB_MAINFRAME::UpdateTitle() { - wxString title; + wxString title = wxString::Format( wxT( "Cvpcb %s " ), GetChars( GetBuildVersion() ) ); if( m_NetlistFileName.IsOk() && m_NetlistFileName.FileExists() ) { - title = wxGetApp().GetTitle() + wxT( " " ) + GetBuildVersion() + - wxT( " " ) + m_NetlistFileName.GetFullPath(); + title += m_NetlistFileName.GetFullPath(); if( !m_NetlistFileName.IsFileWritable() ) title += _( " [Read Only]" ); } else { - title = wxGetApp().GetTitle() + wxT( " " ) + GetBuildVersion() + - wxT( " " ) + _( " [no file]" ); + title += _( "[no file]" ); } SetTitle( title ); @@ -868,7 +859,7 @@ int CVPCB_MAINFRAME::ReadSchematicNetlist() // File header. -static char HeaderLinkFile[] = { "Cmp-Mod V01" }; +static char headerLinkFile[] = "Cmp-Mod V01"; bool CVPCB_MAINFRAME::WriteComponentLinkFile( const wxString& aFullFileName ) @@ -876,7 +867,7 @@ bool CVPCB_MAINFRAME::WriteComponentLinkFile( const wxString& aFullFileName ) COMPONENT* component; FILE* outputFile; wxFileName fn( aFullFileName ); - wxString Title = wxGetApp().GetTitle() + wxT( " " ) + GetBuildVersion(); + wxString title = wxString::Format( wxT( "Cvpcb %s " ), GetChars( GetBuildVersion() ) ); outputFile = wxFopen( fn.GetFullPath(), wxT( "wt" ) ); @@ -896,8 +887,8 @@ bool CVPCB_MAINFRAME::WriteComponentLinkFile( const wxString& aFullFileName ) * IdModule = BUS_PC; * EndCmp */ - retval |= fprintf( outputFile, "%s", HeaderLinkFile ); - retval |= fprintf( outputFile, " Created by %s", TO_UTF8( Title ) ); + retval |= fprintf( outputFile, "%s", headerLinkFile ); + retval |= fprintf( outputFile, " Created by %s", TO_UTF8( title ) ); retval |= fprintf( outputFile, " date = %s\n", TO_UTF8( DateAndTime() ) ); for( unsigned i = 0; i < m_netlist.GetCount(); i++ ) @@ -919,15 +910,9 @@ bool CVPCB_MAINFRAME::WriteComponentLinkFile( const wxString& aFullFileName ) void CVPCB_MAINFRAME::CreateScreenCmp() { - if( m_DisplayFootprintFrame == NULL ) + if( !m_DisplayFootprintFrame ) { - m_DisplayFootprintFrame = new DISPLAY_FOOTPRINTS_FRAME( this, _( "Module" ), - wxPoint( 0, 0 ), - wxSize( 600, 400 ), - KICAD_DEFAULT_DRAWFRAME_STYLE ); - - m_DisplayFootprintFrame->SetFootprintLibTable( m_footprintLibTable ); - + m_DisplayFootprintFrame = new DISPLAY_FOOTPRINTS_FRAME( &Kiway(), this ); m_DisplayFootprintFrame->Show( true ); } else @@ -1023,11 +1008,11 @@ void CVPCB_MAINFRAME::BuildLIBRARY_LISTBOX() wxFONTWEIGHT_NORMAL ) ); } - if( m_footprintLibTable ) + if( FootprintLibs() ) { wxArrayString libNames; - std::vector< wxString > libNickNames = m_footprintLibTable->GetLogicalLibs(); + std::vector< wxString > libNickNames = FootprintLibs()->GetLogicalLibs(); for( unsigned ii = 0; ii < libNickNames.size(); ii++ ) libNames.Add( libNickNames[ii] ); diff --git a/cvpcb/cvpcb.cpp b/cvpcb/cvpcb.cpp index 84a1ae8b73..6d2a2ce02b 100644 --- a/cvpcb/cvpcb.cpp +++ b/cvpcb/cvpcb.cpp @@ -27,8 +27,11 @@ */ #include +#include +#include #include -#include +#include +#include #include #include #include @@ -56,11 +59,13 @@ const wxString FootprintAliasFileWildcard( _( "KiCad footprint alias files (*.eq const wxString titleLibLoadError( _( "Library Load Error" ) ); +#if 0 // add this logic to OpenProjectFiles() + /* * MacOSX: Needed for file association * http://wiki.wxwidgets.org/WxMac-specific_topics */ -void EDA_APP::MacOpenFile( const wxString& aFileName ) +void PGM_BASE::MacOpenFile( const wxString& aFileName ) { wxFileName filename = aFileName; wxString oldPath; @@ -74,73 +79,153 @@ void EDA_APP::MacOpenFile( const wxString& aFileName ) oldPath = frame->m_NetlistFileName.GetPath(); // Update the library search path list. - if( wxGetApp().GetLibraryPathList().Index( oldPath ) != wxNOT_FOUND ) - wxGetApp().GetLibraryPathList().Remove( oldPath ); + if( Pgm().GetLibraryPathList().Index( oldPath ) != wxNOT_FOUND ) + Pgm().GetLibraryPathList().Remove( oldPath ); - wxGetApp().GetLibraryPathList().Insert( filename.GetPath(), 0 ); + Pgm().GetLibraryPathList().Insert( filename.GetPath(), 0 ); frame->m_NetlistFileName = filename; frame->ReadNetListAndLinkFiles(); } +#endif -// Create a new application object -IMPLEMENT_APP( EDA_APP ) +namespace CV { - -/************************************/ -/* Called to initialize the program */ -/************************************/ - -bool EDA_APP::OnInit() +static struct IFACE : public KIFACE_I { - wxFileName filename; - wxString message; - CVPCB_MAINFRAME* frame = NULL; + // Of course all are virtual overloads, implementations of the KIFACE. - InitEDA_Appl( wxT( "CvPcb" ), APP_CVPCB_T ); + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} - SetFootprintLibTablePath(); + bool OnKifaceStart( PGM_BASE* aProgram ); - if( m_Checker && m_Checker->IsAnotherRunning() ) + void OnKifaceEnd(); + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) { - if( !IsOK( NULL, _( "CvPcb is already running, Continue?" ) ) ) - return false; + switch( aClassId ) + { + case CVPCB_FRAME_TYPE: + { + CVPCB_MAINFRAME* frame = new CVPCB_MAINFRAME( aKiway, aParent ); + return frame; + } + break; + + default: + ; + } + + return NULL; } - if( argc > 1 ) + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) { - filename = argv[1]; - wxSetWorkingDirectory( filename.GetPath() ); + return NULL; } - // read current setup and reopen last directory if no filename to open in command line - bool reopenLastUsedDirectory = argc == 1; - GetSettings( reopenLastUsedDirectory ); +} kiface( "cvpcb", KIWAY::FACE_CVPCB ); + +} // namespace + +using namespace CV; + + +static PGM_BASE* process; + + +KIFACE_I& Kiface() { return kiface; } + + +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram ) +{ + process = (PGM_BASE*) aProgram; + return &kiface; +} + + +PGM_BASE& Pgm() +{ + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} + + +FP_LIB_TABLE GFootprintTable; + + +// A short lived implementation. cvpcb will get combine into pcbnew shortly, so +// we skip setting KISYSMOD here for now. User should set the environment +// variable. + +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) +{ + // This is process level, not project level, initialization of the DSO. + + // Do nothing in here pertinent to a project! + + start_common(); + + /* Now that there are no *.mod files in the standard library, this function + has no utility. User should simply set the variable manually. + Looking for *.mod files which do not exist is fruitless. + + // SetFootprintLibTablePath(); + */ g_DrawBgColor = BLACK; - wxString Title = GetTitle() + wxT( " " ) + GetBuildVersion(); - frame = new CVPCB_MAINFRAME( Title ); - - // Show the frame - SetTopWindow( frame ); - frame->Show( true ); - frame->m_NetlistFileExtension = wxT( "net" ); - - if( filename.IsOk() && filename.FileExists() ) + try { - frame->m_NetlistFileName = filename; - frame->LoadProjectFile( filename.GetFullPath() ); + // The global table is not related to a specific project. All projects + // will use the same global table. So the KIFACE::OnKifaceStart() contract + // of avoiding anything project specific is not violated here. - if( frame->ReadNetListAndLinkFiles() ) + if( !FP_LIB_TABLE::LoadGlobalTable( GFootprintTable ) ) { - frame->m_NetlistFileExtension = filename.GetExt(); - return true; + DisplayInfoMessage( NULL, wxT( + "You have run CvPcb for the first time using the " + "new footprint library table method for finding " + "footprints. CvPcb has either copied the default " + "table or created an empty table in your home " + "folder. You must first configure the library " + "table to include all footprint libraries not " + "included with KiCad. See the \"Footprint Library " + "Table\" section of the CvPcb documentation for " + "more information." ) ); } } - - frame->UpdateTitle(); + catch( const IO_ERROR& ioe ) + { + wxString msg = wxString::Format( _( + "An error occurred attempting to load the global footprint library " + "table:\n\n%s" ), + GetChars( ioe.errorText ) + ); + DisplayError( NULL, msg ); + return false; + } return true; } + +void IFACE::OnKifaceEnd() +{ + end_common(); +} diff --git a/cvpcb/cvpcb_mainframe.h b/cvpcb/cvpcb_mainframe.h index 01e2962a0d..6a7e00efaa 100644 --- a/cvpcb/cvpcb_mainframe.h +++ b/cvpcb/cvpcb_mainframe.h @@ -35,7 +35,7 @@ #include #include -#include +#include /* Forward declarations of all top-level window classes. */ @@ -47,22 +47,17 @@ class DISPLAY_FOOTPRINTS_FRAME; class COMPONENT; class FP_LIB_TABLE; +namespace CV { struct IFACE; } /** * The CvPcb application main window. */ -class CVPCB_MAINFRAME : public EDA_BASE_FRAME +class CVPCB_MAINFRAME : public KIWAY_PLAYER { + friend struct CV::IFACE; + wxArrayString m_footprintListEntries; - /// The global footprint library table. - FP_LIB_TABLE* m_globalFootprintTable; - - /// The project footprint library table. This is a combination of the project - /// footprint library table and the global footprint table. This is the one to - /// use when finding a #MODULE. - FP_LIB_TABLE* m_footprintLibTable; - public: bool m_KeepCvpcbOpen; FOOTPRINTS_LISTBOX* m_FootprintList; @@ -87,10 +82,19 @@ protected: // (in automatic selection/deletion of associations) PARAM_CFG_ARRAY m_projectFileParams; + CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ); + public: - CVPCB_MAINFRAME( const wxString& title, long style = KICAD_DEFAULT_DRAWFRAME_STYLE ); ~CVPCB_MAINFRAME(); + bool OpenProjectFiles( const std::vector& aFileSet, int aCtl=0 ); // overload KIWAY_PLAYER + + /** + * Function FootprintLibs + * @return the project #FP_LIB_TABLE. + */ + FP_LIB_TABLE* FootprintLibs() const; + /** * Function OnSelectComponent * Called when clicking on a component in component list window @@ -226,23 +230,9 @@ public: */ void LoadProjectFile( const wxString& aFileName ); - /** - * Function LoadSettings - * loads the CvPcb main frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get loaded. - */ - virtual void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual - /** - * Function SaveSettings - * save the CvPcb frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get saved. - */ - virtual void SaveSettings(); + void SaveSettings( wxConfigBase* aCfg ); // override virtual /** * Function DisplayStatus diff --git a/cvpcb/dialogs/dialog_cvpcb_config.cpp b/cvpcb/dialogs/dialog_cvpcb_config.cpp index 44f263d23e..b0836502f4 100644 --- a/cvpcb/dialogs/dialog_cvpcb_config.cpp +++ b/cvpcb/dialogs/dialog_cvpcb_config.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -43,18 +43,19 @@ #include -DIALOG_CVPCB_CONFIG::DIALOG_CVPCB_CONFIG( CVPCB_MAINFRAME* parent ) : - DIALOG_CVPCB_CONFIG_FBP( parent ) +DIALOG_CVPCB_CONFIG::DIALOG_CVPCB_CONFIG( CVPCB_MAINFRAME* aParent ) : + DIALOG_CVPCB_CONFIG_FBP( aParent ) { - wxString title; - wxFileName fn = parent->m_NetlistFileName; + wxString title; + wxFileName fn = aParent->m_NetlistFileName; + fn.SetExt( ProjectFileExtension ); - m_Parent = parent; - m_Config = wxGetApp().GetCommonSettings(); + m_Parent = aParent; + m_Config = Pgm().CommonSettings(); Init( ); - title.Format( _( "Project file: <%s>" ), GetChars( fn.GetFullPath() ) ); + title.Format( _( "Project file: '%s'" ), GetChars( fn.GetFullPath() ) ); SetTitle( title ); if( GetSizer() ) @@ -93,7 +94,7 @@ void DIALOG_CVPCB_CONFIG::Init() } // Display actual libraries paths: - wxPathList libpaths = wxGetApp().GetLibraryPathList(); + wxPathList libpaths = Pgm().GetLibraryPathList(); for( unsigned ii = 0; ii < libpaths.GetCount(); ii++ ) { @@ -112,9 +113,9 @@ void DIALOG_CVPCB_CONFIG::OnCancelClick( wxCommandEvent& event ) if( m_LibPathChanged ) { for( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii++ ) - wxGetApp().RemoveLibraryPath( m_listUserPaths->GetString( ii ) ); + Pgm().RemoveLibraryPath( m_listUserPaths->GetString( ii ) ); - wxGetApp().InsertLibraryPath( m_Parent->m_UserLibraryPath, 1 ); + Pgm().InsertLibraryPath( m_Parent->m_UserLibraryPath, 1 ); } EndModal( wxID_CANCEL ); @@ -295,7 +296,8 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) insert = true; wildcard = FootprintAliasFileWildcard; - wxListBox * list = m_ListEquiv; + + wxListBox* list = m_ListEquiv; if( (event.GetId() == ID_ADD_LIB) || (event.GetId() == ID_INSERT_LIB) ) { @@ -317,7 +319,7 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) libpath = m_DefaultLibraryPathslistBox->GetStringSelection(); if( libpath.IsEmpty() ) - libpath = wxGetApp().ReturnLastVisitedLibraryPath(); + libpath = Pgm().LastVisitedLibraryPath(); wxFileDialog FilesDialog( this, _( "Footprint library files:" ), libpath, wxEmptyString, wildcard, @@ -334,7 +336,7 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) fn = Filenames[jj]; if( jj == 0 ) - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + Pgm().SaveLastVisitedLibraryPath( fn.GetPath() ); /* If the library path is already in the library search paths * list, just add the library name to the list. Otherwise, add @@ -343,7 +345,7 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) * because it preserve use of default libraries paths, when the path * is a sub path of these default paths */ - libfilename = wxGetApp().ReturnFilenameWithRelativePathInLibPath( fn.GetFullPath() ); + libfilename = Pgm().FilenameWithRelativePathInSearchList( fn.GetFullPath() ); // Remove extension: fn = libfilename; @@ -372,7 +374,7 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) void DIALOG_CVPCB_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) { - wxString path = wxGetApp().ReturnLastVisitedLibraryPath(); + wxString path = Pgm().LastVisitedLibraryPath(); bool select = EDA_DirectorySelector( _( "Default Path for Libraries" ), path, @@ -416,10 +418,10 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) m_listUserPaths->Insert( path, ipos ); m_LibPathChanged = true; - wxGetApp().InsertLibraryPath( path, ipos + 1 ); + Pgm().InsertLibraryPath( path, ipos + 1 ); // Display actual libraries paths: - wxPathList libpaths = wxGetApp().GetLibraryPathList(); + wxPathList libpaths = Pgm().GetLibraryPathList(); m_DefaultLibraryPathslistBox->Clear(); for( unsigned ii = 0; ii < libpaths.GetCount(); ii++ ) @@ -432,7 +434,7 @@ void DIALOG_CVPCB_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) DisplayError( this, _( "Path already in use" ) ); } - wxGetApp().SaveLastVisitedLibraryPath( path ); + Pgm().SaveLastVisitedLibraryPath( path ); } @@ -445,13 +447,13 @@ void DIALOG_CVPCB_CONFIG::OnRemoveUserPath( wxCommandEvent& event ) if( ii >= 0 ) { - wxGetApp().RemoveLibraryPath( m_listUserPaths->GetStringSelection() ); + Pgm().RemoveLibraryPath( m_listUserPaths->GetStringSelection() ); m_listUserPaths->Delete( ii ); m_LibPathChanged = true; } // Display actual libraries paths: - wxPathList libpaths = wxGetApp().GetLibraryPathList(); + wxPathList libpaths = Pgm().GetLibraryPathList(); m_DefaultLibraryPathslistBox->Clear(); for( unsigned ii = 0; ii < libpaths.GetCount(); ii++ ) @@ -466,7 +468,7 @@ void DIALOG_CVPCB_CONFIG::OnBrowseModDocFile( wxCommandEvent& event ) wxString FullFileName; wxString docpath, filename; - docpath = wxGetApp().ReturnLastVisitedLibraryPath( wxT( "doc" ) ); + docpath = Pgm().LastVisitedLibraryPath( wxT( "doc" ) ); wxFileDialog FilesDialog( this, _( "Footprint document file:" ), docpath, wxEmptyString, PdfFileWildcard, @@ -485,8 +487,8 @@ void DIALOG_CVPCB_CONFIG::OnBrowseModDocFile( wxCommandEvent& event ) * a sub path of these default paths */ wxFileName fn = FullFileName; - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + Pgm().SaveLastVisitedLibraryPath( fn.GetPath() ); - filename = wxGetApp().ReturnFilenameWithRelativePathInLibPath( FullFileName ); + filename = Pgm().FilenameWithRelativePathInSearchList( FullFileName ); m_TextHelpModulesFileName->SetValue( filename ); } diff --git a/cvpcb/dialogs/dialog_cvpcb_config.h b/cvpcb/dialogs/dialog_cvpcb_config.h index a83847d874..fa9b51794c 100644 --- a/cvpcb/dialogs/dialog_cvpcb_config.h +++ b/cvpcb/dialogs/dialog_cvpcb_config.h @@ -14,8 +14,9 @@ class DIALOG_CVPCB_CONFIG : public DIALOG_CVPCB_CONFIG_FBP { private: CVPCB_MAINFRAME* m_Parent; - wxConfig * m_Config; - wxString m_UserLibDirBufferImg; + wxConfigBase* m_Config; + wxString m_UserLibDirBufferImg; + bool m_LibListChanged; bool m_LibPathChanged; diff --git a/cvpcb/menubar.cpp b/cvpcb/menubar.cpp index f20fcd33d9..b34454e22f 100644 --- a/cvpcb/menubar.cpp +++ b/cvpcb/menubar.cpp @@ -27,7 +27,8 @@ * @brief (Re)Create the menubar for CvPcb */ #include -#include +#include +#include #include #include #include @@ -74,11 +75,13 @@ void CVPCB_MAINFRAME::ReCreateMenuBar() // Add this menu to list menu managed by m_fileHistory // (the file history will be updated when adding/removing files in history if( openRecentMenu ) - wxGetApp().GetFileHistory().RemoveMenu( openRecentMenu ); + Kiface().GetFileHistory().RemoveMenu( openRecentMenu ); openRecentMenu = new wxMenu(); - wxGetApp().GetFileHistory().UseMenu( openRecentMenu ); - wxGetApp().GetFileHistory().AddFilesToMenu(); + + Kiface().GetFileHistory().UseMenu( openRecentMenu ); + Kiface().GetFileHistory().AddFilesToMenu(); + AddMenuItem( filesMenu, openRecentMenu, -1, _( "Open &Recent" ), _( "Open a recent opened netlist document" ), @@ -115,7 +118,7 @@ void CVPCB_MAINFRAME::ReCreateMenuBar() KiBitmap( library_table_xpm ) ); // Language submenu - wxGetApp().AddMenuLanguageList( preferencesMenu ); + Pgm().AddMenuLanguageList( preferencesMenu ); // Keep open on save item = new wxMenuItem( preferencesMenu, ID_CVPCB_CONFIG_KEEP_OPEN_ON_SAVE, diff --git a/cvpcb/readwrite_dlgs.cpp b/cvpcb/readwrite_dlgs.cpp index ea28775faf..d55a79df14 100644 --- a/cvpcb/readwrite_dlgs.cpp +++ b/cvpcb/readwrite_dlgs.cpp @@ -119,6 +119,49 @@ void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName ) } +/** + * Function missingLegacyLibs + * tests the list of \a aLibNames by URI to determine if any of them are missing from + * the #FP_LIB_TABLE. + * + * @note The missing legacy footprint library test is performed by using old library + * file path lookup method. If the library is found, it is compared against all + * of the URIs in the table rather than the nickname. This was done because the + * user could change the nicknames from the default table. Using the full path + * is more reliable. + * + * @param aLibNames is the list of legacy library names. + * @param aErrorMsg is a pointer to a wxString object to store the URIs of any missing + * legacy library paths. Can be NULL. + * @return true if there are missing legacy libraries. Otherwise false. + */ +static bool missingLegacyLibs( FP_LIB_TABLE* aTbl, SEARCH_STACK& aSStack, + const wxArrayString& aLibNames, wxString* aErrorMsg ) +{ + bool retv = false; + + for( unsigned i = 0; i < aLibNames.GetCount(); i++ ) + { + wxFileName fn( wxEmptyString, aLibNames[i], LegacyFootprintLibPathExtension ); + + wxString legacyLibPath = aSStack.FindValidPath( fn ); + + if( legacyLibPath.IsEmpty() ) + continue; + + if( aTbl->FindRowByURI( legacyLibPath ) == 0 ) + { + retv = true; + + if( aErrorMsg ) + *aErrorMsg += wxT( "\"" ) + legacyLibPath + wxT( "\"\n" ); + } + } + + return retv; +} + + bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() { COMPONENT* component; @@ -164,7 +207,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() // Check if footprint links were generated before the footprint library table was implemented. if( isLegacy ) { - if( m_footprintLibTable->MissingLegacyLibs( m_ModuleLibNames, &missingLibs ) ) + if( missingLegacyLibs( FootprintLibs(), Prj().PcbSearchS(), m_ModuleLibNames, &missingLibs ) ) { msg = wxT( "The following legacy libraries are defined in the project file " "were not found in the footprint library table:\n\n" ) + missingLibs; @@ -188,7 +231,9 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles() msg.Clear(); WX_STRING_REPORTER reporter( &msg ); - if( !m_footprintLibTable->ConvertFromLegacy( m_netlist, m_ModuleLibNames, &reporter ) ) + SEARCH_STACK& search = Prj().SchSearchS(); + + if( !FootprintLibs()->ConvertFromLegacy( search, m_netlist, m_ModuleLibNames, &reporter ) ) { HTML_MESSAGE_BOX dlg( this, wxEmptyString ); @@ -270,7 +315,7 @@ int CVPCB_MAINFRAME::SaveCmpLinkFile( const wxString& aFullFileName ) fn.SetExt( ComponentFileExtension ); // Save the project specific footprint library table. - if( !m_footprintLibTable->IsEmpty( false ) ) + if( !FootprintLibs()->IsEmpty( false ) ) { wxFileName fpLibFileName = fn; fpLibFileName.ClearExt(); @@ -282,9 +327,9 @@ int CVPCB_MAINFRAME::SaveCmpLinkFile( const wxString& aFullFileName ) { try { - m_footprintLibTable->Save( fpLibFileName ); + FootprintLibs()->Save( fpLibFileName ); } - catch( IO_ERROR& ioe ) + catch( const IO_ERROR& ioe ) { DisplayError( this, wxString::Format( _( "An error occurred attempting to save the " diff --git a/cvpcb/tool_cvpcb.cpp b/cvpcb/tool_cvpcb.cpp index 700e344c0e..2937670ed3 100644 --- a/cvpcb/tool_cvpcb.cpp +++ b/cvpcb/tool_cvpcb.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include @@ -41,7 +41,7 @@ void CVPCB_MAINFRAME::ReCreateHToolbar() { - wxConfig* config = wxGetApp().GetSettings(); + wxConfigBase* config = Kiface().KifaceSettings(); if( m_mainToolBar != NULL ) return; diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 05dd30bf82..63c6d5cf97 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -1,4 +1,4 @@ -set( MAKE_LINK_MAPS false ) +set( MAKE_LINK_MAPS true ) add_definitions( -DEESCHEMA ) @@ -191,11 +191,11 @@ endif() # auto-generate cmp_library_lexer.h and cmp_library_keywords.cpp for the component # library format. make_lexer( - ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library.keywords - ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_lexer.h - ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_keywords.cpp - TLIB_T - ) + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library.keywords + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/cmp_library_keywords.cpp + TLIB_T + ) make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/template_fieldnames.keywords @@ -235,22 +235,35 @@ set_source_files_properties( dialogs/dialog_bom.cpp ) -# not ready for even building yet: if( USE_KIWAY_DLLS ) - add_executable( eeschema WIN32 MACOSX_BUNDLE ../common/single_top.cpp + ../common/pgm_base.cpp + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=SCHEMATIC_FRAME_TYPE;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL" ) target_link_libraries( eeschema + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. common + bitmaps ${wxWidgets_LIBRARIES} ) + # the DSO (KIFACE) housing the main eeschema code: add_library( eeschema_kiface MODULE ${EESCHEMA_SRCS} ${EESCHEMA_COMMON_SRCS} ${EESCHEMA_RESOURCES} ) + target_link_libraries( eeschema_kiface + common + bitmaps + polygon + ${wxWidgets_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ) set_target_properties( eeschema_kiface PROPERTIES # Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like # _eeschema.so, _eeschema.dll, or _eeschema.kiface @@ -259,6 +272,14 @@ if( USE_KIWAY_DLLS ) SUFFIX ${KIFACE_SUFFIX} ) + # The KIFACE is in eeschema.cpp, export it: + set_source_files_properties( eeschema.cpp PROPERTIES + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + + # if building eeschema, then also build eeschema_kiface if out of date. + add_dependencies( eeschema eeschema_kiface ) + if( APPLE ) set_target_properties( eeschema_kiface PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist @@ -266,31 +287,46 @@ if( USE_KIWAY_DLLS ) endif() if( MAKE_LINK_MAPS ) - # generate a link map with cross reference + # generate link map with cross reference set_target_properties( eeschema_kiface PROPERTIES - LINK_FLAGS "-Wl,-cref -Wl,-Map=${KIFACE_PRE}eeschema.${KIFACE_EXT}.map" + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=${KIFACE_PREFIX}eeschema${KIFACE_SUFFIX}.map" + ) + set_target_properties( eeschema PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=eeschema.map" ) endif() - target_link_libraries( eeschema_kiface + # these 2 binaries are a matched set, keep them together: + install( TARGETS eeschema + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + install( TARGETS eeschema_kiface + # actual filename subject to change at milestone C) + # modular-kicad blueprint. + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +else() + add_executable( eeschema WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ${EESCHEMA_SRCS} + ${EESCHEMA_COMMON_SRCS} + ${EESCHEMA_RESOURCES} + ) + + target_link_libraries( eeschema common +# lib_kicad bitmaps polygon ${wxWidgets_LIBRARIES} ${GDI_PLUS_LIBRARIES} ) - # Note that this filename is subject to change at milestone C) of - # modular-kicad blueprint. - install( TARGETS eeschema_kiface - DESTINATION ${KICAD_BIN} - COMPONENT binary - ) -else() - add_executable( eeschema WIN32 MACOSX_BUNDLE - ${EESCHEMA_SRCS} - ${EESCHEMA_COMMON_SRCS} - ${EESCHEMA_RESOURCES} + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=SCHEMATIC_FRAME_TYPE;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL" ) if( APPLE ) @@ -299,19 +335,12 @@ else() ) endif() - target_link_libraries( eeschema - common - bitmaps - polygon - ${wxWidgets_LIBRARIES} - ${GDI_PLUS_LIBRARIES} + install( TARGETS eeschema + DESTINATION ${KICAD_BIN} + COMPONENT binary ) + endif() -install( TARGETS eeschema - DESTINATION ${KICAD_BIN} - COMPONENT binary - ) - add_subdirectory( plugins ) diff --git a/eeschema/backanno.cpp b/eeschema/backanno.cpp index 2292301d6c..b72509d98b 100644 --- a/eeschema/backanno.cpp +++ b/eeschema/backanno.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -145,8 +145,8 @@ bool SCH_EDIT_FRAME::LoadCmpToFootprintLinkFile() return false; wxString filename = dlg.GetPath(); - wxString title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion(); - title += wxT( " " ) + filename; + wxString title = wxT( "Eeschema " ) + GetBuildVersion() + wxT( ' ' ) + filename; + SetTitle( title ); int response = wxMessageBox( _( "Do you want to force all the footprint fields visibility?" ), diff --git a/eeschema/block.cpp b/eeschema/block.cpp index f4e47bffb9..98ea9e62a1 100644 --- a/eeschema/block.cpp +++ b/eeschema/block.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase ); -int SCH_EDIT_FRAME::ReturnBlockCommand( int key ) +int SCH_EDIT_FRAME::BlockCommand( int key ) { int cmd = BLOCK_IDLE; diff --git a/eeschema/block_libedit.cpp b/eeschema/block_libedit.cpp index 2a03cae331..e9c89d14f5 100644 --- a/eeschema/block_libedit.cpp +++ b/eeschema/block_libedit.cpp @@ -41,7 +41,7 @@ static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wx bool aErase ); -int LIB_EDIT_FRAME::ReturnBlockCommand( int key ) +int LIB_EDIT_FRAME::BlockCommand( int key ) { int cmd = BLOCK_IDLE; diff --git a/eeschema/class_libentry.cpp b/eeschema/class_libentry.cpp index 489114efb8..52fc2adaf5 100644 --- a/eeschema/class_libentry.cpp +++ b/eeschema/class_libentry.cpp @@ -258,7 +258,7 @@ wxString LIB_COMPONENT::GetLibraryName() } -wxString LIB_COMPONENT::ReturnSubReference( int aUnit, bool aAddSeparator ) +wxString LIB_COMPONENT::SubReference( int aUnit, bool aAddSeparator ) { wxString subRef; @@ -568,7 +568,7 @@ LIB_PIN* LIB_COMPONENT::GetPin( const wxString& aNumber, int aUnit, int aConvert { wxASSERT( pinList[i]->Type() == LIB_PIN_T ); - pinList[i]->ReturnPinStringNum( pNumber ); + pinList[i]->PinStringNum( pNumber ); if( aNumber == pNumber ) return pinList[i]; diff --git a/eeschema/class_libentry.h b/eeschema/class_libentry.h index 695102bc20..d9097794e7 100644 --- a/eeschema/class_libentry.h +++ b/eeschema/class_libentry.h @@ -664,7 +664,7 @@ public: bool IsMulti() { return m_unitCount > 1; } /** - * Function ReturnSubReference + * Function SubReference * @return the sub reference for component having multiple parts per package. * The sub reference identify the part (or unit) * @param aUnit = the part identifier ( 1 to max count) @@ -672,7 +672,7 @@ public: * by the separator symbol (if any) * Note: this is a static function. */ - static wxString ReturnSubReference( int aUnit, bool aAddSeparator = true ); + static wxString SubReference( int aUnit, bool aAddSeparator = true ); // Accessors to sub ref parameters static int GetSubpartIdSeparator() { return m_subpartIdSeparator; } diff --git a/eeschema/class_netlist_object.cpp b/eeschema/class_netlist_object.cpp index 56de1ef087..0b62b47dab 100644 --- a/eeschema/class_netlist_object.cpp +++ b/eeschema/class_netlist_object.cpp @@ -353,7 +353,7 @@ wxString NETLIST_OBJECT::GetShortNetName() const netName = wxT("Net-("); netName << link->GetRef( &m_netNameCandidate->m_SheetPath ); netName << wxT("-Pad") - << LIB_PIN::ReturnPinStringNum( m_netNameCandidate->m_PinNum ) + << LIB_PIN::PinStringNum( m_netNameCandidate->m_PinNum ) << wxT(")"); } } diff --git a/eeschema/class_netlist_object.h b/eeschema/class_netlist_object.h index d07dcb7291..e3533a51d4 100644 --- a/eeschema/class_netlist_object.h +++ b/eeschema/class_netlist_object.h @@ -33,7 +33,7 @@ #include -#include // LIB_PIN::ReturnPinStringNum( m_PinNum ) +#include // LIB_PIN::PinStringNum( m_PinNum ) class NETLIST_OBJECT_LIST; class SCH_COMPONENT; @@ -179,7 +179,7 @@ public: wxString GetPinNumText() { // hide the ugliness in here, but do it inline. - return LIB_PIN::ReturnPinStringNum( m_PinNum ); + return LIB_PIN::PinStringNum( m_PinNum ); } /** For Pins (NET_PINS): diff --git a/eeschema/component_references_lister.cpp b/eeschema/component_references_lister.cpp index 10b67d3678..d2b553af5a 100644 --- a/eeschema/component_references_lister.cpp +++ b/eeschema/component_references_lister.cpp @@ -592,12 +592,12 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList ) msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ), GetChars( componentFlatList[ii].GetRef() ), componentFlatList[ii].m_NumRef, - GetChars( LIB_COMPONENT::ReturnSubReference( + GetChars( LIB_COMPONENT::SubReference( componentFlatList[ii].m_Unit ) ), GetChars( componentFlatList[ii].m_Value->GetText() ), GetChars( componentFlatList[next].GetRef() ), componentFlatList[next].m_NumRef, - GetChars( LIB_COMPONENT::ReturnSubReference( + GetChars( LIB_COMPONENT::SubReference( componentFlatList[next].m_Unit ) ), GetChars( componentFlatList[next].m_Value->GetText() ) ); diff --git a/eeschema/cross-probing.cpp b/eeschema/cross-probing.cpp index 9ae5e52035..dcb7788c8d 100644 --- a/eeschema/cross-probing.cpp +++ b/eeschema/cross-probing.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include @@ -58,17 +58,11 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) { char line[1024]; - char* idcmd; - char* text; - wxString part_ref, msg; - SCH_EDIT_FRAME* frame; - - frame = (SCH_EDIT_FRAME*)wxGetApp().GetTopWindow(); strncpy( line, cmdline, sizeof(line) - 1 ); - idcmd = strtok( line, " \n\r" ); - text = strtok( NULL, "\"\n\r" ); + char* idcmd = strtok( line, " \n\r" ); + char* text = strtok( NULL, "\"\n\r" ); if( (idcmd == NULL) || (text == NULL) ) return; @@ -76,14 +70,14 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) if( strcmp( idcmd, "$PART:" ) != 0 ) return; - part_ref = FROM_UTF8( text ); + wxString part_ref = FROM_UTF8( text ); /* look for a complement */ idcmd = strtok( NULL, " \n\r" ); if( idcmd == NULL ) // component only { - frame->FindComponentAndItem( part_ref, true, FIND_COMPONENT_ONLY, wxEmptyString, false ); + FindComponentAndItem( part_ref, true, FIND_COMPONENT_ONLY, wxEmptyString, false ); return; } @@ -92,23 +86,23 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline ) if( text == NULL ) return; - msg = FROM_UTF8( text ); + wxString msg = FROM_UTF8( text ); if( strcmp( idcmd, "$REF:" ) == 0 ) { - frame->FindComponentAndItem( part_ref, true, FIND_REFERENCE, msg, false ); + FindComponentAndItem( part_ref, true, FIND_REFERENCE, msg, false ); } else if( strcmp( idcmd, "$VAL:" ) == 0 ) { - frame->FindComponentAndItem( part_ref, true, FIND_VALUE, msg, false ); + FindComponentAndItem( part_ref, true, FIND_VALUE, msg, false ); } else if( strcmp( idcmd, "$PAD:" ) == 0 ) { - frame->FindComponentAndItem( part_ref, true, FIND_PIN, msg, false ); + FindComponentAndItem( part_ref, true, FIND_PIN, msg, false ); } else { - frame->FindComponentAndItem( part_ref, true, FIND_COMPONENT_ONLY, wxEmptyString, false ); + FindComponentAndItem( part_ref, true, FIND_COMPONENT_ONLY, wxEmptyString, false ); } } @@ -126,14 +120,14 @@ void SCH_EDIT_FRAME::SendMessageToPCBNEW( EDA_ITEM* objectToSync, SCH_COMPONENT* { case SCH_FIELD_T: case LIB_FIELD_T: - { - if( LibItem == NULL ) - break; + { + if( !LibItem ) + break; - sprintf( Line, "$PART: %s", TO_UTF8( LibItem->GetField( REFERENCE )->GetText() ) ); - SendCommand( MSG_TO_PCB, Line ); - } - break; + sprintf( Line, "$PART: %s", TO_UTF8( LibItem->GetField( REFERENCE )->GetText() ) ); + SendCommand( MSG_TO_PCB, Line ); + } + break; case SCH_COMPONENT_T: LibItem = (SCH_COMPONENT*) objectToSync; @@ -142,7 +136,7 @@ void SCH_EDIT_FRAME::SendMessageToPCBNEW( EDA_ITEM* objectToSync, SCH_COMPONENT* break; case LIB_PIN_T: - if( LibItem == NULL ) + if( !LibItem ) break; Pin = (LIB_PIN*) objectToSync; @@ -150,7 +144,7 @@ void SCH_EDIT_FRAME::SendMessageToPCBNEW( EDA_ITEM* objectToSync, SCH_COMPONENT* if( Pin->GetNumber() ) { wxString pinnum; - Pin->ReturnPinStringNum( pinnum ); + Pin->PinStringNum( pinnum ); sprintf( Line, "$PIN: %s $PART: %s", TO_UTF8( pinnum ), TO_UTF8( LibItem->GetField( REFERENCE )->GetText() ) ); } diff --git a/eeschema/database.cpp b/eeschema/database.cpp index 5071a13cdc..4cf8089364 100644 --- a/eeschema/database.cpp +++ b/eeschema/database.cpp @@ -26,15 +26,15 @@ * @file database.cpp */ -#include "fctsys.h" -#include "confirm.h" -#include "eda_doc.h" -#include "kicad_string.h" -#include "wxstruct.h" +#include +#include +#include +#include +#include #include -#include "protos.h" -#include "class_library.h" -#include "dialog_helpers.h" +#include +#include +#include #include diff --git a/eeschema/dialogs/dialog_annotate.cpp b/eeschema/dialogs/dialog_annotate.cpp index c37d8a1e38..8a3c0b6a22 100644 --- a/eeschema/dialogs/dialog_annotate.cpp +++ b/eeschema/dialogs/dialog_annotate.cpp @@ -29,21 +29,20 @@ #include -#include #include #include #include #include +#include + +#define KEY_ANNOTATE_SORT_OPTION wxT( "AnnotateSortOption" ) +#define KEY_ANNOTATE_ALGO_OPTION wxT( "AnnotateAlgoOption" ) +#define KEY_ANNOTATE_AUTOCLOSE_OPTION wxT( "AnnotateAutoCloseOption" ) +#define KEY_ANNOTATE_USE_SILENTMODE wxT( "AnnotateSilentMode" ) -#define KEY_ANNOTATE_SORT_OPTION wxT( "AnnotateSortOption" ) -#define KEY_ANNOTATE_ALGO_OPTION wxT( "AnnotateAlgoOption" ) -#define KEY_ANNOTATE_AUTOCLOSE_OPTION wxT( "AnnotateAutoCloseOption" ) -#define KEY_ANNOTATE_USE_SILENTMODE wxT( "AnnotateSilentMode" ) - - -class wxConfig; +class wxConfigBase; /** @@ -57,7 +56,7 @@ public: private: SCH_EDIT_FRAME* m_Parent; - wxConfig* m_Config; + wxConfigBase* m_Config; /// Initialises member variables void InitValues(); @@ -112,7 +111,7 @@ DIALOG_ANNOTATE::DIALOG_ANNOTATE( SCH_EDIT_FRAME* parent ) void DIALOG_ANNOTATE::InitValues() { - m_Config = wxGetApp().GetSettings(); + m_Config = Kiface().KifaceSettings(); if( m_Config ) { diff --git a/eeschema/dialogs/dialog_bom.cpp b/eeschema/dialogs/dialog_bom.cpp index 105a71fc06..b293a39b17 100644 --- a/eeschema/dialogs/dialog_bom.cpp +++ b/eeschema/dialogs/dialog_bom.cpp @@ -29,7 +29,8 @@ #include -#include +#include +#include #include #include #include @@ -161,7 +162,7 @@ private: // the first is the title // the second is the command line wxArrayString m_plugins; - wxConfig* m_config; // to store the "plugins" + wxConfigBase* m_config; // to store the "plugins" public: // Constructor and destructor @@ -169,7 +170,7 @@ public: ~DIALOG_BOM(); private: - void OnPluginSelected( wxCommandEvent& event ); + void OnPluginSelected( wxCommandEvent& event ); void OnRunPlugin( wxCommandEvent& event ); void OnCancelClick( wxCommandEvent& event ); void OnHelp( wxCommandEvent& event ); @@ -177,10 +178,10 @@ private: void OnChoosePlugin( wxCommandEvent& event ); void OnRemovePlugin( wxCommandEvent& event ); void OnEditPlugin( wxCommandEvent& event ); - void OnCommandLineEdited( wxCommandEvent& event ); - void OnNameEdited( wxCommandEvent& event ); + void OnCommandLineEdited( wxCommandEvent& event ); + void OnNameEdited( wxCommandEvent& event ); - void pluginInit(); + void pluginInit(); void installPluginsList(); }; @@ -195,7 +196,7 @@ DIALOG_BOM::DIALOG_BOM( SCH_EDIT_FRAME* parent ) : DIALOG_BOM_BASE( parent ) { m_parent = parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); installPluginsList(); GetSizer()->SetSizeHints( this ); @@ -377,38 +378,37 @@ void DIALOG_BOM::OnAddPlugin( wxCommandEvent& event ) */ void DIALOG_BOM::OnChoosePlugin( wxCommandEvent& event ) { - wxString FullFileName, Mask, Path; + wxString mask = wxT( "*" ); + wxString path = Pgm().GetExecutablePath(); - Mask = wxT( "*" ); - Path = wxGetApp().GetExecutablePath(); - FullFileName = EDA_FileSelector( _( "Plugin files:" ), - Path, - FullFileName, + wxString fullFileName = EDA_FileSelector( _( "Plugin files:" ), + path, wxEmptyString, - Mask, + wxEmptyString, + mask, this, wxFD_OPEN, true ); - if( FullFileName.IsEmpty() ) + if( fullFileName.IsEmpty() ) return; // Creates a default command line, // suitable to run the external tool xslproc or python // The default command line depending on plugin extension, currently // "xsl" or "exe" or "py" - wxString cmdLine; - wxFileName fn( FullFileName ); - wxString ext = fn.GetExt(); + wxString cmdLine; + wxFileName fn( fullFileName ); + wxString ext = fn.GetExt(); if( ext == wxT("xsl" ) ) - cmdLine.Printf(wxT("xsltproc -o \"%%O\" \"%s\" \"%%I\""), GetChars(FullFileName) ); + cmdLine.Printf(wxT("xsltproc -o \"%%O\" \"%s\" \"%%I\""), GetChars( fullFileName ) ); else if( ext == wxT("exe" ) || ext.IsEmpty() ) - cmdLine.Printf(wxT("\"%s\" < \"%%I\" > \"%%O\""), GetChars(FullFileName) ); + cmdLine.Printf(wxT("\"%s\" < \"%%I\" > \"%%O\""), GetChars( fullFileName ) ); else if( ext == wxT("py" ) || ext.IsEmpty() ) - cmdLine.Printf(wxT("python \"%s\" \"%%I\" \"%%O\""), GetChars(FullFileName) ); + cmdLine.Printf(wxT("python \"%s\" \"%%I\" \"%%O\""), GetChars( fullFileName ) ); else - cmdLine.Printf(wxT("\"%s\""), GetChars(FullFileName) ); + cmdLine.Printf(wxT("\"%s\""), GetChars( fullFileName ) ); m_textCtrlCommand->SetValue( cmdLine ); } @@ -449,7 +449,7 @@ void DIALOG_BOM::OnEditPlugin( wxCommandEvent& event ) } } AddDelimiterString( pluginName ); - wxString editorname = wxGetApp().GetEditorName(); + wxString editorname = Pgm().GetEditorName(); if( !editorname.IsEmpty() ) ExecuteFile( this, editorname, pluginName ); diff --git a/eeschema/dialogs/dialog_color_config.cpp b/eeschema/dialogs/dialog_color_config.cpp index 7daa6988e8..1ed7ae72dc 100644 --- a/eeschema/dialogs/dialog_color_config.cpp +++ b/eeschema/dialogs/dialog_color_config.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/eeschema/dialogs/dialog_edit_component_in_lib.cpp b/eeschema/dialogs/dialog_edit_component_in_lib.cpp index 72b4c4c69a..8866b25c1f 100644 --- a/eeschema/dialogs/dialog_edit_component_in_lib.cpp +++ b/eeschema/dialogs/dialog_edit_component_in_lib.cpp @@ -26,10 +26,11 @@ */ #include +#include #include #include #include -#include +#include #include #include @@ -435,22 +436,22 @@ bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::SetUnsetConvert() void DIALOG_EDIT_COMPONENT_IN_LIBRARY::BrowseAndSelectDocFile( wxCommandEvent& event ) { - wxString FullFileName, mask; - wxString docpath, filename; + PROJECT& prj = Prj(); + SEARCH_STACK& search = prj.SchSearchS(); - docpath = wxGetApp().ReturnLastVisitedLibraryPath( wxT( "doc" ) ); + wxString docpath = prj.RPath(PROJECT::DOC).LastVisitedPath( search, wxT( "doc" ) ); + wxString mask = wxT( "*" ); - mask = wxT( "*" ); - FullFileName = EDA_FileSelector( _( "Doc Files" ), - docpath, /* Chemin par defaut */ - wxEmptyString, /* nom fichier par defaut */ - wxEmptyString, /* extension par defaut */ - mask, /* Masque d'affichage */ + wxString fullFileName = EDA_FileSelector( _( "Doc Files" ), + docpath, + wxEmptyString, + wxEmptyString, + mask, this, wxFD_OPEN, true ); - if( FullFileName.IsEmpty() ) + if( fullFileName.IsEmpty() ) return; /* If the path is already in the library search paths @@ -460,10 +461,12 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::BrowseAndSelectDocFile( wxCommandEvent& e * because it preserve use of default libraries paths, when the path is a sub path of * these default paths */ - wxFileName fn = FullFileName; - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + wxFileName fn = fullFileName; + + prj.RPath(PROJECT::DOC).SaveLastVisitedPath( fn.GetPath() ); + + wxString filename = search.FilenameWithRelativePathInSearchList( fullFileName ); - filename = wxGetApp().ReturnFilenameWithRelativePathInLibPath( FullFileName ); // Filenames are always stored in unix like mode, ie separator "\" is stored as "/" // to ensure files are identical under unices and windows #ifdef __WINDOWS__ diff --git a/eeschema/dialogs/dialog_edit_component_in_schematic.cpp b/eeschema/dialogs/dialog_edit_component_in_schematic.cpp index 91449c9399..9a6644d327 100644 --- a/eeschema/dialogs/dialog_edit_component_in_schematic.cpp +++ b/eeschema/dialogs/dialog_edit_component_in_schematic.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include @@ -766,10 +766,10 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copySelectedFieldToPanel() // top of each other. } - wxString coordText = ReturnStringFromValue( g_UserUnit, coord.x ); + wxString coordText = StringFromValue( g_UserUnit, coord.x ); posXTextCtrl->SetValue( coordText ); - coordText = ReturnStringFromValue( g_UserUnit, coord.y ); + coordText = StringFromValue( g_UserUnit, coord.y ); posYTextCtrl->SetValue( coordText ); } @@ -828,8 +828,8 @@ bool DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::copyPanelToSelectedField() field.SetBold( (style & 2 ) != 0 ); wxPoint pos; - pos.x = ReturnValueFromString( g_UserUnit, posXTextCtrl->GetValue() ); - pos.y = ReturnValueFromString( g_UserUnit, posYTextCtrl->GetValue() ); + pos.x = ValueFromString( g_UserUnit, posXTextCtrl->GetValue() ); + pos.y = ValueFromString( g_UserUnit, posYTextCtrl->GetValue() ); field.SetTextPosition( pos ); return true; diff --git a/eeschema/dialogs/dialog_edit_label.cpp b/eeschema/dialogs/dialog_edit_label.cpp index fb1805e298..91fcc91cda 100644 --- a/eeschema/dialogs/dialog_edit_label.cpp +++ b/eeschema/dialogs/dialog_edit_label.cpp @@ -203,7 +203,7 @@ void DIALOG_LABEL_EDITOR::InitDialog() msg.Printf( _( "H%s x W%s" ), GetChars( units ), GetChars( units ) ); m_staticSizeUnits->SetLabel( msg ); - msg = ReturnStringFromValue( g_UserUnit, m_CurrentText->GetSize().x ); + msg = StringFromValue( g_UserUnit, m_CurrentText->GetSize().x ); m_TextSize->SetValue( msg ); if( m_CurrentText->Type() != SCH_GLOBAL_LABEL_T @@ -272,7 +272,7 @@ void DIALOG_LABEL_EDITOR::TextPropertiesAccept( wxCommandEvent& aEvent ) m_CurrentText->SetOrientation( m_TextOrient->GetSelection() ); text = m_TextSize->GetValue(); - value = ReturnValueFromString( g_UserUnit, text ); + value = ValueFromString( g_UserUnit, text ); m_CurrentText->SetSize( wxSize( value, value ) ); if( m_TextShape ) diff --git a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp index 1e2ccb6502..4036c36cb5 100644 --- a/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp +++ b/eeschema/dialogs/dialog_edit_libentry_fields_in_lib.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -675,13 +675,13 @@ void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copySelectedFieldToPanel() // top of each other. } - wxString coordText = ReturnStringFromValue( g_UserUnit, coord.x ); + wxString coordText = StringFromValue( g_UserUnit, coord.x ); posXTextCtrl->SetValue( coordText ); // Note: the Y axis for components in lib is from bottom to top // and the screen axis is top to bottom: we must change the y coord sign for editing NEGATE( coord.y ); - coordText = ReturnStringFromValue( g_UserUnit, coord.y ); + coordText = StringFromValue( g_UserUnit, coord.y ); posYTextCtrl->SetValue( coordText ); } @@ -747,8 +747,8 @@ bool DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::copyPanelToSelectedField() field.SetItalic( (style & 1 ) != 0 ); field.SetBold( (style & 2 ) != 0 ); - wxPoint pos( ReturnValueFromString( g_UserUnit, posXTextCtrl->GetValue() ), - ReturnValueFromString( g_UserUnit, posYTextCtrl->GetValue() ) ); + wxPoint pos( ValueFromString( g_UserUnit, posXTextCtrl->GetValue() ), + ValueFromString( g_UserUnit, posYTextCtrl->GetValue() ) ); // Note: the Y axis for components in lib is from bottom to top // and the screen axis is top to bottom: we must change the y coord sign for editing diff --git a/eeschema/dialogs/dialog_edit_one_field.cpp b/eeschema/dialogs/dialog_edit_one_field.cpp index af48030656..055eb77aa1 100644 --- a/eeschema/dialogs/dialog_edit_one_field.cpp +++ b/eeschema/dialogs/dialog_edit_one_field.cpp @@ -53,7 +53,7 @@ void DIALOG_EDIT_ONE_FIELD::initDlg_base() m_CommonConvert->Show(false); m_CommonUnit->Show(false); - msg = ReturnStringFromValue( g_UserUnit, m_textsize ); + msg = StringFromValue( g_UserUnit, m_textsize ); m_TextSize->SetValue( msg ); if( m_textorient == TEXT_ORIENT_VERT ) @@ -132,7 +132,7 @@ void DIALOG_EDIT_ONE_FIELD::TransfertDataToField() { m_textorient = m_Orient->GetValue() ? TEXT_ORIENT_VERT : TEXT_ORIENT_HORIZ; wxString msg = m_TextSize->GetValue(); - m_textsize = ReturnValueFromString( g_UserUnit, msg ); + m_textsize = ValueFromString( g_UserUnit, msg ); switch( m_TextHJustificationOpt->GetSelection() ) { diff --git a/eeschema/dialogs/dialog_eeschema_config.cpp b/eeschema/dialogs/dialog_eeschema_config.cpp index b3f9284067..f4f01e4043 100644 --- a/eeschema/dialogs/dialog_eeschema_config.cpp +++ b/eeschema/dialogs/dialog_eeschema_config.cpp @@ -27,10 +27,12 @@ */ #include -#include +#include +#include #include #include #include +#include #include #include @@ -40,20 +42,50 @@ #include -#include + +#include + +class SCH_EDIT_FRAME; +class EDA_DRAW_FRAME; + +class DIALOG_EESCHEMA_CONFIG : public DIALOG_EESCHEMA_CONFIG_FBP +{ +public: + DIALOG_EESCHEMA_CONFIG( SCH_EDIT_FRAME* parent, wxFrame* activeWindow ); + +private: + SCH_EDIT_FRAME* m_Parent; + bool m_LibListChanged; + bool m_LibPathChanged; + wxString m_UserLibDirBufferImg; // Copy of original g_UserLibDirBuffer + + + // event handlers, overiding the fbp handlers + void Init(); + void OnCloseWindow( wxCloseEvent& event ); + void OnRemoveLibClick( wxCommandEvent& event ); + void OnAddOrInsertLibClick( wxCommandEvent& event ); + void OnAddOrInsertPath( wxCommandEvent& event ); + void OnOkClick( wxCommandEvent& event ); + void OnCancelClick( wxCommandEvent& event ); + void OnRemoveUserPath( wxCommandEvent& event ); + void OnButtonUpClick( wxCommandEvent& event ); + void OnButtonDownClick( wxCommandEvent& event ); +}; DIALOG_EESCHEMA_CONFIG::DIALOG_EESCHEMA_CONFIG( SCH_EDIT_FRAME* aSchFrame, - EDA_DRAW_FRAME* aParent ) - : DIALOG_EESCHEMA_CONFIG_FBP( aParent ) + wxFrame* aParent ) : + DIALOG_EESCHEMA_CONFIG_FBP( aParent ) { - wxString msg; - m_Parent = aSchFrame; Init(); - msg.Printf( _( "from <%s>" ), GetChars( wxGetApp().GetCurrentOptionFile() ) ); + wxString msg = wxString::Format( + _( "from '%s'" ), + GetChars( Prj().GetProjectFullName() ) ); + SetTitle( msg ); if( GetSizer() ) @@ -74,21 +106,22 @@ void DIALOG_EESCHEMA_CONFIG::Init() m_ListLibr->InsertItems( m_Parent->GetComponentLibraries(), 0 ); // Load user libs paths: - wxStringTokenizer Token( m_UserLibDirBufferImg, wxT( ";\n\r" ) ); - while( Token.HasMoreTokens() ) + wxStringTokenizer tokenizer( m_UserLibDirBufferImg, wxT( ";\n\r" ) ); + + while( tokenizer.HasMoreTokens() ) { - wxString path = Token.GetNextToken(); + wxString path = tokenizer.GetNextToken(); if( wxFileName::DirExists( path ) ) m_listUserPaths->Append( path ); } // Display actual libraries paths: - wxPathList libpaths = wxGetApp().GetLibraryPathList(); + SEARCH_STACK& libpaths = Prj().SchSearchS(); for( unsigned ii = 0; ii < libpaths.GetCount(); ii++ ) { - m_DefaultLibraryPathslistBox->Append( libpaths[ii]); + m_DefaultLibraryPathslistBox->Append( libpaths[ii] ); } // select the first path after the current path project @@ -153,7 +186,7 @@ void DIALOG_EESCHEMA_CONFIG::OnButtonDownClick( wxCommandEvent& event ) EXCHG( libnames[jj], libnames[jj+1]); } - m_ListLibr->Set(libnames); + m_ListLibr->Set( libnames ); // Reselect previously selected names for( size_t ii = 0; ii < selections.GetCount(); ii++ ) @@ -168,13 +201,15 @@ void DIALOG_EESCHEMA_CONFIG::OnButtonDownClick( wxCommandEvent& event ) void DIALOG_EESCHEMA_CONFIG::OnCancelClick( wxCommandEvent& event ) { - // Recreate the user lib path - if ( m_LibPathChanged ) - { - for ( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii++ ) - wxGetApp().RemoveLibraryPath( m_listUserPaths->GetString(ii) ); + SEARCH_STACK& lib_search = Prj().SchSearchS(); - wxGetApp().InsertLibraryPath( m_Parent->GetUserLibraryPath(), 1); + // Recreate the user lib path + if( m_LibPathChanged ) + { + for( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii++ ) + lib_search.RemovePaths( m_listUserPaths->GetString(ii) ); + + lib_search.AddPaths( m_Parent->GetUserLibraryPath(), 1 ); } EndModal( wxID_CANCEL ); @@ -184,13 +219,13 @@ void DIALOG_EESCHEMA_CONFIG::OnCancelClick( wxCommandEvent& event ) void DIALOG_EESCHEMA_CONFIG::OnOkClick( wxCommandEvent& event ) { // Recreate the user lib path - if ( m_LibPathChanged ) + if( m_LibPathChanged ) { wxString path; - for ( unsigned ii = 0; ii < m_listUserPaths->GetCount(); ii++ ) + for( unsigned ii = 0; ii < m_listUserPaths->GetCount(); ii++ ) { - if ( ii > 0 ) + if( ii > 0 ) path << wxT( ";" ); path << m_listUserPaths->GetString( ii ); @@ -206,7 +241,7 @@ void DIALOG_EESCHEMA_CONFIG::OnOkClick( wxCommandEvent& event ) { wxArrayString list; - for ( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii ++ ) + for( unsigned ii = 0; ii < m_ListLibr->GetCount(); ii ++ ) list.Add( m_ListLibr->GetString( ii ) ); // Recreate lib list @@ -268,10 +303,13 @@ void DIALOG_EESCHEMA_CONFIG::OnRemoveLibClick( wxCommandEvent& event ) */ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) { - int ii; - wxString libfilename; - wxFileName fn; - wxArrayInt selections; + int ii; + wxString libfilename; + wxFileName fn; + wxArrayInt selections; + + PROJECT& prj = Prj(); + SEARCH_STACK& search = prj.SchSearchS(); m_ListLibr->GetSelections( selections ); @@ -282,28 +320,28 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) else ii = 0; - wxString libpath; - libpath = m_DefaultLibraryPathslistBox->GetStringSelection(); + wxString libpath = m_DefaultLibraryPathslistBox->GetStringSelection(); - if ( libpath.IsEmpty() ) - libpath = wxGetApp().ReturnLastVisitedLibraryPath(); + if( libpath.IsEmpty() ) + libpath = prj.RPath(PROJECT::SCH_LIB).LastVisitedPath( search ); - wxFileDialog FilesDialog( this, _( "Library files:" ), libpath, + wxFileDialog filesDialog( this, _( "Library files:" ), libpath, wxEmptyString, SchematicLibraryFileWildcard, wxFD_DEFAULT_STYLE | wxFD_MULTIPLE ); - if( FilesDialog.ShowModal() != wxID_OK ) + if( filesDialog.ShowModal() != wxID_OK ) return; - wxArrayString Filenames; - FilesDialog.GetPaths( Filenames ); + wxArrayString filenames; - for( unsigned jj = 0; jj < Filenames.GetCount(); jj++ ) + filesDialog.GetPaths( filenames ); + + for( unsigned jj = 0; jj < filenames.GetCount(); jj++ ) { - fn = Filenames[jj]; + fn = filenames[jj]; - if ( jj == 0 ) - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + if( jj == 0 ) + prj.RPath(PROJECT::SCH_LIB).SaveLastVisitedPath( fn.GetPath() ); /* If the library path is already in the library search paths * list, just add the library name to the list. Otherwise, add @@ -312,14 +350,14 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) * because it preserve use of default libraries paths, when the path * is a sub path of these default paths */ - libfilename = wxGetApp().ReturnFilenameWithRelativePathInLibPath( fn.GetFullPath() ); + libfilename = search.FilenameWithRelativePathInSearchList( fn.GetFullPath() ); // Remove extension: fn = libfilename; - fn.SetExt(wxEmptyString); + fn.SetExt( wxEmptyString ); libfilename = fn.GetFullPath(); - //Add or insert new library name, if not already in list + // Add or insert new library name, if not already in list if( m_ListLibr->FindString( libfilename, fn.IsCaseSensitive() ) == wxNOT_FOUND ) { m_LibListChanged = true; @@ -342,7 +380,9 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertLibClick( wxCommandEvent& event ) void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) { - wxString path = wxGetApp().ReturnLastVisitedLibraryPath(); + PROJECT& prj = Prj(); + SEARCH_STACK& search = Prj().SchSearchS(); + wxString path = prj.RPath(PROJECT::SCH_LIB).LastVisitedPath( search ); bool select = EDA_DirectorySelector( _( "Default Path for Libraries" ), path, wxDD_DEFAULT_STYLE, @@ -359,14 +399,14 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) { int ipos = m_listUserPaths->GetCount(); - if ( event.GetId() == wxID_INSERT_PATH ) + if( event.GetId() == wxID_INSERT_PATH ) { - if ( ipos ) + if( ipos ) ipos--; int jj = m_listUserPaths->GetSelection(); - if ( jj >= 0 ) + if( jj >= 0 ) ipos = jj; } @@ -375,7 +415,8 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) wxYES_NO | wxICON_QUESTION, this ); if( diag == wxYES ) - { // Make it relative + { + // Make it relative wxFileName fn = path; fn.MakeRelativeTo( wxT(".") ); path = fn.GetPathWithSep() + fn.GetFullName(); @@ -383,15 +424,15 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) m_listUserPaths->Insert(path, ipos); m_LibPathChanged = true; - wxGetApp().InsertLibraryPath( path, ipos+1 ); + + search.AddPaths( path, ipos+1 ); // Display actual libraries paths: - wxPathList libpaths = wxGetApp().GetLibraryPathList(); m_DefaultLibraryPathslistBox->Clear(); - for( unsigned ii = 0; ii < libpaths.GetCount(); ii++ ) + for( unsigned ii = 0; ii < search.GetCount(); ii++ ) { - m_DefaultLibraryPathslistBox->Append( libpaths[ii]); + m_DefaultLibraryPathslistBox->Append( search[ii] ); } } else @@ -399,30 +440,42 @@ void DIALOG_EESCHEMA_CONFIG::OnAddOrInsertPath( wxCommandEvent& event ) DisplayError( this, _("Path already in use") ); } - wxGetApp().SaveLastVisitedLibraryPath( path ); + prj.RPath(PROJECT::SCH_LIB).SaveLastVisitedPath( path ); } void DIALOG_EESCHEMA_CONFIG::OnRemoveUserPath( wxCommandEvent& event ) { + SEARCH_STACK& lib_search = Prj().SchSearchS(); + int ii = m_listUserPaths->GetSelection(); - if ( ii < 0 ) + if( ii < 0 ) ii = m_listUserPaths->GetCount()-1; - if ( ii >= 0 ) + if( ii >= 0 ) { - wxGetApp().RemoveLibraryPath( m_listUserPaths->GetStringSelection() ); + lib_search.RemovePaths( m_listUserPaths->GetStringSelection() ); + m_listUserPaths->Delete( ii ); m_LibPathChanged = true; } // Display actual libraries paths: - wxPathList libpaths = wxGetApp().GetLibraryPathList(); m_DefaultLibraryPathslistBox->Clear(); - for( unsigned ii = 0; ii < libpaths.GetCount(); ii++ ) + for( unsigned ii = 0; ii < lib_search.GetCount(); ii++ ) { - m_DefaultLibraryPathslistBox->Append( libpaths[ii] ); + m_DefaultLibraryPathslistBox->Append( lib_search[ii] ); } } + + +int InvokeEeschemaConfig( SCH_EDIT_FRAME* aEditFrame, wxFrame* aParent ) +{ + DIALOG_EESCHEMA_CONFIG dlg( aEditFrame, aParent ); + + dlg.ShowModal(); + + return 1; +} diff --git a/eeschema/dialogs/dialog_eeschema_config.h b/eeschema/dialogs/dialog_eeschema_config.h deleted file mode 100644 index 32bc536d9d..0000000000 --- a/eeschema/dialogs/dialog_eeschema_config.h +++ /dev/null @@ -1,42 +0,0 @@ - -#ifndef _DIALOG_EESCHEMA_CONFIG_H_ -#define _DIALOG_EESCHEMA_CONFIG_H_ - - -#include - - -class SCH_EDIT_FRAME; -class EDA_DRAW_FRAME; - - -class DIALOG_EESCHEMA_CONFIG : public DIALOG_EESCHEMA_CONFIG_FBP -{ -private: - SCH_EDIT_FRAME* m_Parent; - bool m_LibListChanged; - bool m_LibPathChanged; - wxString m_UserLibDirBufferImg; // Copy of original g_UserLibDirBuffer - -private: - - // event handlers, overiding the fbp handlers - void Init(); - void OnCloseWindow( wxCloseEvent& event ); - void OnRemoveLibClick( wxCommandEvent& event ); - void OnAddOrInsertLibClick( wxCommandEvent& event ); - void OnAddOrInsertPath( wxCommandEvent& event ); - void OnOkClick( wxCommandEvent& event ); - void OnCancelClick( wxCommandEvent& event ); - void OnRemoveUserPath( wxCommandEvent& event ); - void OnButtonUpClick( wxCommandEvent& event ); - void OnButtonDownClick( wxCommandEvent& event ); - - -public: - DIALOG_EESCHEMA_CONFIG( SCH_EDIT_FRAME* parent, EDA_DRAW_FRAME* activeWindow ); - ~DIALOG_EESCHEMA_CONFIG() {}; -}; - - -#endif // _DIALOG_EESCHEMA_CONFIG_H_ diff --git a/eeschema/dialogs/dialog_eeschema_config_fbp.cpp b/eeschema/dialogs/dialog_eeschema_config_fbp.cpp index 6ef268f328..99297fb844 100644 --- a/eeschema/dialogs/dialog_eeschema_config_fbp.cpp +++ b/eeschema/dialogs/dialog_eeschema_config_fbp.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 5 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -9,7 +9,7 @@ /////////////////////////////////////////////////////////////////////////// -DIALOG_EESCHEMA_CONFIG_FBP::DIALOG_EESCHEMA_CONFIG_FBP( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +DIALOG_EESCHEMA_CONFIG_FBP::DIALOG_EESCHEMA_CONFIG_FBP( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); diff --git a/eeschema/dialogs/dialog_eeschema_config_fbp.fbp b/eeschema/dialogs/dialog_eeschema_config_fbp.fbp index 0e7f0d960f..2062d5e43c 100644 --- a/eeschema/dialogs/dialog_eeschema_config_fbp.fbp +++ b/eeschema/dialogs/dialog_eeschema_config_fbp.fbp @@ -20,8 +20,10 @@ . 1 + 1 1 1 + UI 1 0 @@ -44,7 +46,7 @@ -1,-1 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER - + DIALOG_SHIM; dialog_shim.h diff --git a/eeschema/dialogs/dialog_eeschema_config_fbp.h b/eeschema/dialogs/dialog_eeschema_config_fbp.h index d0b91eeb14..84b86341c4 100644 --- a/eeschema/dialogs/dialog_eeschema_config_fbp.h +++ b/eeschema/dialogs/dialog_eeschema_config_fbp.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 5 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,6 +11,9 @@ #include #include #include +class DIALOG_SHIM; + +#include "dialog_shim.h" #include #include #include @@ -28,7 +31,7 @@ /////////////////////////////////////////////////////////////////////////////// /// Class DIALOG_EESCHEMA_CONFIG_FBP /////////////////////////////////////////////////////////////////////////////// -class DIALOG_EESCHEMA_CONFIG_FBP : public wxDialog +class DIALOG_EESCHEMA_CONFIG_FBP : public DIALOG_SHIM { private: diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp index 03a6630236..9e4bf1aae4 100644 --- a/eeschema/dialogs/dialog_erc.cpp +++ b/eeschema/dialogs/dialog_erc.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -562,7 +562,7 @@ void DIALOG_ERC::TestErc( wxArrayString* aMessagesList ) if( WriteDiagnosticERC( dlg.GetPath() ) ) { Close( true ); - ExecuteFile( this, wxGetApp().GetEditorName(), QuoteFullPath( fn ) ); + ExecuteFile( this, Pgm().GetEditorName(), QuoteFullPath( fn ) ); } } } diff --git a/eeschema/dialogs/dialog_lib_edit_pin.cpp b/eeschema/dialogs/dialog_lib_edit_pin.cpp index 245ebd628b..7f3307ad83 100644 --- a/eeschema/dialogs/dialog_lib_edit_pin.cpp +++ b/eeschema/dialogs/dialog_lib_edit_pin.cpp @@ -94,10 +94,10 @@ void DIALOG_LIB_EDIT_PIN::OnPropertiesChange( wxCommandEvent& event ) if( ! IsShown() ) // do nothing at init time return; - int pinNameSize = ReturnValueFromString( g_UserUnit, GetNameTextSize() ); - int pinNumSize = ReturnValueFromString( g_UserUnit, GetPadNameTextSize()); + int pinNameSize = ValueFromString( g_UserUnit, GetNameTextSize() ); + int pinNumSize = ValueFromString( g_UserUnit, GetPadNameTextSize()); int pinOrient = LIB_PIN::GetOrientationCode( GetOrientation() ); - int pinLength = ReturnValueFromString( g_UserUnit, GetLength() ); + int pinLength = ValueFromString( g_UserUnit, GetLength() ); int pinShape = LIB_PIN::GetStyleCode( GetStyle() ); int pinType = GetElectricalType(); diff --git a/eeschema/dialogs/dialog_lib_edit_text.cpp b/eeschema/dialogs/dialog_lib_edit_text.cpp index 674b5cf820..6530175407 100644 --- a/eeschema/dialogs/dialog_lib_edit_text.cpp +++ b/eeschema/dialogs/dialog_lib_edit_text.cpp @@ -64,7 +64,7 @@ void DIALOG_LIB_EDIT_TEXT::initDlg( ) if ( m_graphicText ) { - msg = ReturnStringFromValue( g_UserUnit, m_graphicText->GetSize().x ); + msg = StringFromValue( g_UserUnit, m_graphicText->GetSize().x ); m_TextSize->SetValue( msg ); m_TextValue->SetValue( m_graphicText->GetText() ); @@ -116,7 +116,7 @@ void DIALOG_LIB_EDIT_TEXT::initDlg( ) } else { - msg = ReturnStringFromValue( g_UserUnit, m_parent->m_textSize ); + msg = StringFromValue( g_UserUnit, m_parent->m_textSize ); m_TextSize->SetValue( msg ); if ( ! m_parent->m_drawSpecificUnit ) @@ -148,7 +148,7 @@ void DIALOG_LIB_EDIT_TEXT::OnOkClick( wxCommandEvent& event ) Line = m_TextValue->GetValue(); m_parent->m_textOrientation = m_Orient->GetValue() ? TEXT_ORIENT_VERT : TEXT_ORIENT_HORIZ; wxString msg = m_TextSize->GetValue(); - m_parent->m_textSize = ReturnValueFromString( g_UserUnit, msg ); + m_parent->m_textSize = ValueFromString( g_UserUnit, msg ); m_parent->m_drawSpecificConvert = m_CommonConvert->GetValue() ? false : true; m_parent->m_drawSpecificUnit = m_CommonUnit->GetValue() ? false : true; diff --git a/eeschema/dialogs/dialog_netlist.cpp b/eeschema/dialogs/dialog_netlist.cpp index 8266c2d0c8..90a6babe90 100644 --- a/eeschema/dialogs/dialog_netlist.cpp +++ b/eeschema/dialogs/dialog_netlist.cpp @@ -39,7 +39,8 @@ */ #include -#include +#include +#include #include #include #include @@ -123,7 +124,7 @@ public: NETLIST_PAGE_DIALOG* m_PanelNetType[4 + CUSTOMPANEL_COUNTMAX]; private: - wxConfig* m_config; + wxConfigBase* m_config; public: @@ -169,17 +170,17 @@ private: } /** - * Function ReturnUserNetlistTypeName + * Function UserNetlistTypeName * to retrieve user netlist type names * @param first_item = true: return first name of the list, false = return next * @return a wxString : name of the type netlist or empty string * this function must be called first with "first_item" = true * and after with "first_item" = false to get all the other existing netlist names */ - const wxString ReturnUserNetlistTypeName( bool first_item ); + const wxString UserNetlistTypeName( bool first_item ); /** - * Function ReturnFilenamePrms + * Function FilenamePrms * returns the filename extension and the wildcard string for this curr * or a void name if there is no default name * @param aNetTypeId = the netlist type ( NET_TYPE_PCBNEW ... ) @@ -187,7 +188,7 @@ private: * @param aWildCard = reference to a wxString to return the default wildcard. * @return true for known netlist type, false for custom formats */ - bool ReturnFilenamePrms( NETLIST_TYPE_ID aNetTypeId, + bool FilenamePrms( NETLIST_TYPE_ID aNetTypeId, wxString * aExt, wxString * aWildCard ); DECLARE_EVENT_TABLE() @@ -347,7 +348,7 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) : NETLIST_DIALOG_BASE( parent ) { m_Parent = parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); long tmp; m_config->Read( NETLIST_USE_DEFAULT_NETNAME, &tmp, 0l ); @@ -388,7 +389,7 @@ NETLIST_DIALOG::NETLIST_DIALOG( SCH_EDIT_FRAME* parent ) : } -const wxString NETLIST_DIALOG::ReturnUserNetlistTypeName( bool first_item ) +const wxString NETLIST_DIALOG::UserNetlistTypeName( bool first_item ) { static int index; wxString name, msg; @@ -448,7 +449,7 @@ void NETLIST_DIALOG::InstallCustomPages() for( ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ ) { - title = ReturnUserNetlistTypeName( ii == 0 ? true : false ); + title = UserNetlistTypeName( ii == 0 ? true : false ); if( title.IsEmpty() ) break; // No more panel to install @@ -532,7 +533,7 @@ void NETLIST_DIALOG::OnNetlistTypeSelection( wxNotebookEvent& event ) m_cbUseDefaultNetlistName->Enable( currPage->m_IdNetType < NET_TYPE_CUSTOM1 ); wxString fileExt; - if( ReturnFilenamePrms( currPage->m_IdNetType, &fileExt, NULL ) ) + if( FilenamePrms( currPage->m_IdNetType, &fileExt, NULL ) ) { wxFileName fn = g_RootSheet->GetScreen()->GetFileName(); fn.SetExt( fileExt ); @@ -591,7 +592,7 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event ) // Calculate the netlist filename fn = g_RootSheet->GetScreen()->GetFileName(); - ReturnFilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard ); + FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard ); // Set some parameters switch( currPage->m_IdNetType ) @@ -653,7 +654,7 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event ) } -bool NETLIST_DIALOG::ReturnFilenamePrms( NETLIST_TYPE_ID aNetTypeId, +bool NETLIST_DIALOG::FilenamePrms( NETLIST_TYPE_ID aNetTypeId, wxString * aExt, wxString * aWildCard ) { wxString fileExt; @@ -913,7 +914,7 @@ void NETLIST_DIALOG_ADD_PLUGIN::OnBrowsePlugins( wxCommandEvent& event ) wxString FullFileName, Mask, Path; Mask = wxT( "*" ); - Path = wxGetApp().GetExecutablePath(); + Path = Pgm().GetExecutablePath(); FullFileName = EDA_FileSelector( _( "Plugin files:" ), Path, FullFileName, diff --git a/eeschema/dialogs/dialog_plot_schematic.cpp b/eeschema/dialogs/dialog_plot_schematic.cpp index 1b175b625d..9390e6d6e1 100644 --- a/eeschema/dialogs/dialog_plot_schematic.cpp +++ b/eeschema/dialogs/dialog_plot_schematic.cpp @@ -29,7 +29,8 @@ */ #include -#include +#include +#include #include #include #include @@ -63,7 +64,7 @@ DIALOG_PLOT_SCHEMATIC::DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* parent ) : DIALOG_PLOT_SCHEMATIC_BASE( parent ) { m_parent = parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); initDlg(); @@ -177,7 +178,7 @@ void DIALOG_PLOT_SCHEMATIC::getPlotOptions() m_config->Write( PLOT_HPGL_PEN_SIZE_KEY, m_HPGLPenSize/IU_PER_MM ); m_pageSizeSelect = m_PaperSizeOption->GetSelection(); - SetDefaultLineThickness( ReturnValueFromTextCtrl( *m_DefaultLineSizeCtrl ) ); + SetDefaultLineThickness( ValueFromTextCtrl( *m_DefaultLineSizeCtrl ) ); } diff --git a/eeschema/dialogs/dialog_plot_schematic.h b/eeschema/dialogs/dialog_plot_schematic.h index baa03bd4d1..df547ffbe6 100644 --- a/eeschema/dialogs/dialog_plot_schematic.h +++ b/eeschema/dialogs/dialog_plot_schematic.h @@ -46,7 +46,7 @@ class DIALOG_PLOT_SCHEMATIC : public DIALOG_PLOT_SCHEMATIC_BASE { private: SCH_EDIT_FRAME* m_parent; - wxConfig* m_config; + wxConfigBase* m_config; static int m_pageSizeSelect; // Static to keep last option for some format: // Static to keep last option: // use default size or force A or A4 size @@ -58,10 +58,10 @@ public: DIALOG_PLOT_SCHEMATIC( SCH_EDIT_FRAME* parent ); private: - void OnPlotFormatSelection( wxCommandEvent& event ); - void OnButtonPlotCurrentClick( wxCommandEvent& event ); - void OnButtonPlotAllClick( wxCommandEvent& event ); - void OnButtonCancelClick( wxCommandEvent& event ); + void OnPlotFormatSelection( wxCommandEvent& event ); + void OnButtonPlotCurrentClick( wxCommandEvent& event ); + void OnButtonPlotAllClick( wxCommandEvent& event ); + void OnButtonCancelClick( wxCommandEvent& event ); void initDlg(); diff --git a/eeschema/dialogs/dialog_print_using_printer.cpp b/eeschema/dialogs/dialog_print_using_printer.cpp index cd6548c2ca..15fbdc8055 100644 --- a/eeschema/dialogs/dialog_print_using_printer.cpp +++ b/eeschema/dialogs/dialog_print_using_printer.cpp @@ -3,7 +3,7 @@ /****************************************/ #include -#include +#include #include #include #include diff --git a/eeschema/eelibs_read_libraryfiles.cpp b/eeschema/eelibs_read_libraryfiles.cpp index 5d623767ed..8eaaafd8de 100644 --- a/eeschema/eelibs_read_libraryfiles.cpp +++ b/eeschema/eelibs_read_libraryfiles.cpp @@ -4,9 +4,10 @@ */ #include +#include #include #include -#include +#include #include #include @@ -16,18 +17,23 @@ #include -void SCH_EDIT_FRAME::LoadLibraries( void ) +void SCH_EDIT_FRAME::LoadLibraries() { - size_t ii; - wxFileName fn; - wxString msg, tmp, errMsg; - wxString libraries_not_found; - wxArrayString sortOrder; + size_t ii; + wxFileName fn; + wxString msg, tmp, errMsg; + wxString libraries_not_found; + wxArrayString sortOrder; + SEARCH_STACK& lib_search = Prj().SchSearchS(); + +#if defined(DEBUG) && 1 + lib_search.Show( __func__ ); +#endif CMP_LIBRARY_LIST::iterator i = CMP_LIBRARY::GetLibraryList().begin(); - /* Free the unwanted libraries but keep the cache library. */ - while ( i < CMP_LIBRARY::GetLibraryList().end() ) + // Free the unwanted libraries but keep the cache library. + while( i < CMP_LIBRARY::GetLibraryList().end() ) { if( i->IsCache() ) { @@ -35,26 +41,28 @@ void SCH_EDIT_FRAME::LoadLibraries( void ) continue; } + DBG(printf( "ll:%s\n", TO_UTF8( i->GetName() ) );) + if( m_componentLibFiles.Index( i->GetName(), false ) == wxNOT_FOUND ) i = CMP_LIBRARY::GetLibraryList().erase( i ); else i++; } - /* Load missing libraries. */ + // Load missing libraries. for( ii = 0; ii < m_componentLibFiles.GetCount(); ii++ ) { fn.Clear(); fn.SetName( m_componentLibFiles[ii] ); fn.SetExt( SchematicLibraryFileExtension ); - /* Skip if the file name is not valid.. */ + // Skip if the file name is not valid.. if( !fn.IsOk() ) continue; if( !fn.FileExists() ) { - tmp = wxGetApp().FindLibraryPath( fn ); + tmp = lib_search.FindValidPath( fn ); if( !tmp ) { @@ -72,24 +80,24 @@ void SCH_EDIT_FRAME::LoadLibraries( void ) if( CMP_LIBRARY::AddLibrary( fn, errMsg ) ) { - msg.Printf( _( "Library <%s> loaded" ), GetChars( tmp ) ); + msg.Printf( _( "Library '%s' loaded" ), GetChars( tmp ) ); sortOrder.Add( fn.GetName() ); } else { wxString prompt; - prompt.Printf( _( "Component library <%s> failed to load.\nError: %s" ), + prompt.Printf( _( "Component library '%s' failed to load.\nError: %s" ), GetChars( fn.GetFullPath() ), GetChars( errMsg ) ); DisplayError( this, prompt ); - msg.Printf( _( "Library <%s> error!" ), GetChars( tmp ) ); + msg.Printf( _( "Library '%s' error!" ), GetChars( tmp ) ); } PrintMsg( msg ); } - /* Print the libraries not found */ + // Print the libraries not found if( !libraries_not_found.IsEmpty() ) { HTML_MESSAGE_BOX dialog( this, _("Files not found") ); @@ -99,11 +107,11 @@ void SCH_EDIT_FRAME::LoadLibraries( void ) dialog.ShowModal(); } - /* Put the libraries in the correct order. */ + // Put the libraries in the correct order. CMP_LIBRARY::SetSortOrder( sortOrder ); CMP_LIBRARY::GetLibraryList().sort(); -#if 0 // #ifdef __WXDEBUG__ +#if 0 && defined(__WXDEBUG__) wxLogDebug( wxT( "LoadLibraries() requested component library sort order:" ) ); for( size_t i = 0; i < sortOrder.GetCount(); i++ ) @@ -118,3 +126,4 @@ void SCH_EDIT_FRAME::LoadLibraries( void ) wxLogDebug( wxT( "end LoadLibraries ()" ) ); #endif } + diff --git a/eeschema/eeschema.cpp b/eeschema/eeschema.cpp index 5efa3e62c8..c7e72dd048 100644 --- a/eeschema/eeschema.cpp +++ b/eeschema/eeschema.cpp @@ -29,12 +29,13 @@ */ #include -#include +#include +#include #include -#include #include #include #include +#include #include #include @@ -45,23 +46,65 @@ #include #include -#include - - -#if defined( USE_KIWAY_DLLS ) - #include -#include -static struct SCH_FACE : public KIFACE + +// Global variables +wxSize g_RepeatStep; +int g_RepeatDeltaLabel; +int g_DefaultBusWidth; +SCH_SHEET* g_RootSheet = NULL; + +TRANSFORM DefaultTransform = TRANSFORM( 1, 0, 0, -1 ); + + +namespace SCH { + +static struct IFACE : public KIFACE_I { - wxWindow* CreateWindow( int aClassId, KIWAY* aKIWAY, int aCtlBits = 0 ) + // Of course all are virtual overloads, implementations of the KIFACE. + + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} + + bool OnKifaceStart( PGM_BASE* aProgram ); + + void OnKifaceEnd( PGM_BASE* aProgram ) + { + end_common(); + } + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) { switch( aClassId ) { + case LIBEDITOR_FRAME_TYPE: + { + LIB_EDIT_FRAME* frame = new LIB_EDIT_FRAME( aKiway, + dynamic_cast( aParent ) ); + return frame; + } + break; + + case SCHEMATIC_FRAME_TYPE: + { + SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent ); + + frame->Zoom_Automatique( true ); + + // Read a default config file in case no project given on command line. + frame->LoadProjectFile( wxEmptyString, true ); + + // @todo temporary + CreateServer( frame, KICAD_SCH_PORT_SERVICE_NUMBER ); + + return frame; + } + break; + default: - return new SCH_EDIT_FRAME( NULL, wxT( "Eeschema" ), - wxPoint( 0, 0 ), wxSize( 600, 400 ) ); + return NULL; } } @@ -81,139 +124,51 @@ static struct SCH_FACE : public KIFACE return NULL; } -} kiface; +} kiface( "eeschema", KIWAY::FACE_SCH ); + +} // namespace + +using namespace SCH; + +static PGM_BASE* process; + + +KIFACE_I& Kiface() { return kiface; } -static EDA_APP* process; // KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. // KIFACE_GETTER will not have name mangling due to declaration in kiway.h. -MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, wxApp* aProcess ) +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram ) { - process = (EDA_APP*) aProcess; + process = (PGM_BASE*) aProgram; return &kiface; } -EDA_APP& wxGetApp() +PGM_BASE& Pgm() { wxASSERT( process ); // KIFACE_GETTER has already been called. return *process; } -#else -// Create a new application object: this macro will allow wxWindows to create -// the application object during program execution (it's better than using a -// static object for many reasons) and also declares the accessor function -// wxGetApp() which will return the reference of the right type (i.e. MyApp and -// not wxApp) -IMPLEMENT_APP( EDA_APP ) - -#endif - - -// Global variables -wxSize g_RepeatStep; -int g_RepeatDeltaLabel; -int g_DefaultBusWidth; -SCH_SHEET* g_RootSheet = NULL; - -TRANSFORM DefaultTransform = TRANSFORM( 1, 0, 0, -1 ); - - -/************************************/ -/* Called to initialize the program */ -/************************************/ - -/* MacOSX: Needed for file association - * http://wiki.wxwidgets.org/WxMac-specific_topics - */ -void EDA_APP::MacOpenFile( const wxString& aFileName ) +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) { - wxFileName filename = aFileName; - SCH_EDIT_FRAME* frame = ((SCH_EDIT_FRAME*) GetTopWindow()); + // This is process level, not project level, initialization of the DSO. - if( !frame ) - return; + // Do nothing in here pertinent to a project! - if( !filename.FileExists() ) - return; - - frame->LoadOneEEProject( aFileName, false ); -} - - -bool EDA_APP::OnInit() -{ - wxFileName filename; - SCH_EDIT_FRAME* frame = NULL; - bool fileReady = false; - - InitEDA_Appl( wxT( "Eeschema" ), APP_EESCHEMA_T ); - - if( argc > 1 ) - filename = argv[1]; - - if( filename.IsOk() ) - { - if( filename.GetExt() != SchematicFileExtension ) - filename.SetExt( SchematicFileExtension ); - - if( !wxGetApp().LockFile( filename.GetFullPath() ) ) - { - DisplayError( NULL, _( "This file is already open." ) ); - return false; - } - - fileReady = true; - } - - if( m_Checker && m_Checker->IsAnotherRunning() ) - { - if( !IsOK( NULL, _( "Eeschema is already running, Continue?" ) ) ) - return false; - } + start_common(); // Give a default colour for all layers // (actual color will be initialized by config) for( int ii = 0; ii < NB_SCH_LAYERS; ii++ ) SetLayerColor( DARKGRAY, ii ); - // read current setup and reopen last directory if no filename to open in - // command line - bool reopenLastUsedDirectory = argc == 1; - GetSettings( reopenLastUsedDirectory ); - - /* Must be called before creating the main frame in order to - * display the real hotkeys in menus or tool tips */ + // Must be called before creating the main frame in order to + // display the real hotkeys in menus or tool tips ReadHotkeyConfig( wxT("SchematicFrame"), s_Eeschema_Hokeys_Descr ); - // Create main frame (schematic frame) : - frame = new SCH_EDIT_FRAME( NULL, wxT( "Eeschema" ), wxPoint( 0, 0 ), wxSize( 600, 400 ) ); - - SetTopWindow( frame ); - frame->Show( true ); - - CreateServer( frame, KICAD_SCH_PORT_SERVICE_NUMBER ); - - frame->Zoom_Automatique( true ); - - // Load file specified in the command line: - if( fileReady ) - { - if( !filename.GetPath().IsEmpty() ) - // wxSetWorkingDirectory does not like empty paths - wxSetWorkingDirectory( filename.GetPath() ); - - if( frame->LoadOneEEProject( filename.GetFullPath(), false ) ) - frame->GetCanvas()->Refresh( true ); - } - else - { - // Read a default config file if no file to load. - frame->LoadProjectFile( wxEmptyString, true ); - frame->GetCanvas()->Refresh( true ); - } - return true; } + diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp index 43e5ec21e3..e335d9d4b6 100644 --- a/eeschema/eeschema_config.cpp +++ b/eeschema/eeschema_config.cpp @@ -26,11 +26,13 @@ */ #include -#include +#include +#include #include #include #include #include +#include #include #include @@ -44,7 +46,6 @@ #include #include -#include #include #include @@ -117,9 +118,7 @@ EDA_COLOR_T GetInvisibleItemColor() void LIB_EDIT_FRAME::InstallConfigFrame( wxCommandEvent& event ) { - DIALOG_EESCHEMA_CONFIG CfgFrame( (SCH_EDIT_FRAME *)GetParent(), this ); - - CfgFrame.ShowModal(); + InvokeEeschemaConfig( (SCH_EDIT_FRAME *)GetParent(), this ); } @@ -194,9 +193,7 @@ void SCH_EDIT_FRAME::OnColorConfig( wxCommandEvent& aEvent ) void SCH_EDIT_FRAME::InstallConfigFrame( wxCommandEvent& event ) { - DIALOG_EESCHEMA_CONFIG CfgFrame( this, this ); - - CfgFrame.ShowModal(); + InvokeEeschemaConfig( this, this ); } @@ -212,21 +209,20 @@ void SCH_EDIT_FRAME::Process_Config( wxCommandEvent& event ) break; case ID_CONFIG_READ: - { - fn = g_RootSheet->GetScreen()->GetFileName(); - fn.SetExt( ProjectFileExtension ); + { + fn = g_RootSheet->GetScreen()->GetFileName(); + fn.SetExt( ProjectFileExtension ); - wxFileDialog dlg( this, _( "Read Project File" ), fn.GetPath(), - fn.GetFullName(), ProjectFileWildcard, - wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + wxFileDialog dlg( this, _( "Read Project File" ), fn.GetPath(), + fn.GetFullName(), ProjectFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); - if( dlg.ShowModal() == wxID_CANCEL ) - break; - - LoadProjectFile( dlg.GetPath(), true ); - } - break; + if( dlg.ShowModal() == wxID_CANCEL ) + break; + LoadProjectFile( dlg.GetPath(), true ); + } + break; // Hotkey IDs case ID_PREFERENCES_HOTKEY_EXPORT_CONFIG: @@ -398,9 +394,10 @@ PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetProjectFileParametersList() bool SCH_EDIT_FRAME::LoadProjectFile( const wxString& aFileName, bool aForceReread ) { - wxFileName fn; - bool IsRead = true; - wxArrayString liblist_tmp = m_componentLibFiles; + wxFileName fn; + bool isRead = true; + wxArrayString liblist_tmp = m_componentLibFiles; + PROJECT& prj = Prj(); if( aFileName.IsEmpty() ) fn = g_RootSheet->GetScreen()->GetFileName(); @@ -409,18 +406,15 @@ bool SCH_EDIT_FRAME::LoadProjectFile( const wxString& aFileName, bool aForceRere m_componentLibFiles.Clear(); - /* Change the schematic file extension (.sch) to the project file - * extension (.pro). */ + // Change the schematic file extension (.sch) to the project file + // extension (.pro). fn.SetExt( ProjectFileExtension ); - wxGetApp().RemoveLibraryPath( m_userLibraryPath ); - - if( !wxGetApp().ReadProjectConfig( fn.GetFullPath(), GROUP, - GetProjectFileParametersList(), - !aForceReread ) ) + if( !prj.ConfigLoad( Kiface().KifaceSearch(), fn.GetFullPath(), GROUP, + GetProjectFileParametersList(), !aForceReread ) ) { m_componentLibFiles = liblist_tmp; - IsRead = false; + isRead = false; } // Verify some values, because the config file can be edited by hand, @@ -434,28 +428,26 @@ bool SCH_EDIT_FRAME::LoadProjectFile( const wxString& aFileName, bool aForceRere WORKSHEET_LAYOUT& pglayout = WORKSHEET_LAYOUT::GetTheInstance(); pglayout.SetPageLayout(BASE_SCREEN::m_PageLayoutDescrFileName); - // Load libraries. - // User library path takes precedent over default library search paths. - wxGetApp().InsertLibraryPath( m_userLibraryPath, 1 ); + // libraries in the *.pro file take precedence over standard library search paths, + // but not over the director of the project, which is at index 0. + prj.SchSearchS().AddPaths( m_userLibraryPath, 1 ); - /* If the list is void, force loading the library "power.lib" that is - * the "standard" library for power symbols. - */ + // If the list is empty, force loading the standard power symbol library. if( m_componentLibFiles.GetCount() == 0 ) m_componentLibFiles.Add( wxT( "power" ) ); LoadLibraries(); GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); - return IsRead; + return isRead; } void SCH_EDIT_FRAME::SaveProjectSettings( bool aAskForSave ) { - wxFileName fn; + PROJECT& prj = Prj(); + wxFileName fn = g_RootSheet->GetScreen()->GetFileName(); //ConfigFileName - fn = g_RootSheet->GetScreen()->GetFileName(); //ConfigFileName fn.SetExt( ProjectFileExtension ); if( !IsWritable( fn ) ) @@ -470,37 +462,37 @@ void SCH_EDIT_FRAME::SaveProjectSettings( bool aAskForSave ) if( dlg.ShowModal() == wxID_CANCEL ) return; - wxGetApp().WriteProjectConfig( dlg.GetPath(), GROUP, - GetProjectFileParametersList() ); + fn = dlg.GetPath(); } - else - wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, - GetProjectFileParametersList() ); + + prj.ConfigSave( Kiface().KifaceSearch(), + fn.GetFullPath(), GROUP, GetProjectFileParametersList() ); } -static const wxString DefaultBusWidthEntry( wxT( "DefaultBusWidth" ) ); -static const wxString DefaultDrawLineWidthEntry( wxT( "DefaultDrawLineWidth" ) ); -static const wxString ShowHiddenPinsEntry( wxT( "ShowHiddenPins" ) ); -static const wxString HorzVertLinesOnlyEntry( wxT( "HorizVertLinesOnly" ) ); -static const wxString PreviewFramePositionXEntry( wxT( "PreviewFramePositionX" ) ); -static const wxString PreviewFramePositionYEntry( wxT( "PreviewFramePositionY" ) ); -static const wxString PreviewFrameWidthEntry( wxT( "PreviewFrameWidth" ) ); -static const wxString PreviewFrameHeightEntry( wxT( "PreviewFrameHeight" ) ); -static const wxString PrintDialogPositionXEntry( wxT( "PrintDialogPositionX" ) ); -static const wxString PrintDialogPositionYEntry( wxT( "PrintDialogPositionY" ) ); -static const wxString PrintDialogWidthEntry( wxT( "PrintDialogWidth" ) ); -static const wxString PrintDialogHeightEntry( wxT( "PrintDialogHeight" ) ); -static const wxString FindDialogPositionXEntry( wxT( "FindDialogPositionX" ) ); -static const wxString FindDialogPositionYEntry( wxT( "FindDialogPositionY" ) ); -static const wxString FindDialogWidthEntry( wxT( "FindDialogWidth" ) ); -static const wxString FindDialogHeightEntry( wxT( "FindDialogHeight" ) ); -static const wxString FindReplaceFlagsEntry( wxT( "LastFindReplaceFlags" ) ); -static const wxString FindStringEntry( wxT( "LastFindString" ) ); -static const wxString ReplaceStringEntry( wxT( "LastReplaceString" ) ); -static const wxString FindStringHistoryEntry( wxT( "FindStringHistoryList%d" ) ); -static const wxString ReplaceStringHistoryEntry( wxT( "ReplaceStringHistoryList%d" ) ); -static const wxString FieldNamesEntry( wxT( "FieldNames" ) ); -static const wxString SimulatorCommandEntry( wxT( "SimCmdLine" ) ); + +static const wxChar DefaultBusWidthEntry[] = wxT( "DefaultBusWidth" ); +static const wxChar DefaultDrawLineWidthEntry[] = wxT( "DefaultDrawLineWidth" ); +static const wxChar ShowHiddenPinsEntry[] = wxT( "ShowHiddenPins" ); +static const wxChar HorzVertLinesOnlyEntry[] = wxT( "HorizVertLinesOnly" ); +static const wxChar PreviewFramePositionXEntry[] = wxT( "PreviewFramePositionX" ); +static const wxChar PreviewFramePositionYEntry[] = wxT( "PreviewFramePositionY" ); +static const wxChar PreviewFrameWidthEntry[] = wxT( "PreviewFrameWidth" ); +static const wxChar PreviewFrameHeightEntry[] = wxT( "PreviewFrameHeight" ); +static const wxChar PrintDialogPositionXEntry[] = wxT( "PrintDialogPositionX" ); +static const wxChar PrintDialogPositionYEntry[] = wxT( "PrintDialogPositionY" ); +static const wxChar PrintDialogWidthEntry[] = wxT( "PrintDialogWidth" ); +static const wxChar PrintDialogHeightEntry[] = wxT( "PrintDialogHeight" ); +static const wxChar FindDialogPositionXEntry[] = wxT( "FindDialogPositionX" ); +static const wxChar FindDialogPositionYEntry[] = wxT( "FindDialogPositionY" ); +static const wxChar FindDialogWidthEntry[] = wxT( "FindDialogWidth" ); +static const wxChar FindDialogHeightEntry[] = wxT( "FindDialogHeight" ); +static const wxChar FindReplaceFlagsEntry[] = wxT( "LastFindReplaceFlags" ); +static const wxChar FindStringEntry[] = wxT( "LastFindString" ); +static const wxChar ReplaceStringEntry[] = wxT( "LastReplaceString" ); +static const wxChar FindStringHistoryEntry[] = wxT( "FindStringHistoryList%d" ); +static const wxChar ReplaceStringHistoryEntry[] = wxT( "ReplaceStringHistoryList%d" ); +static const wxChar FieldNamesEntry[] = wxT( "FieldNames" ); +static const wxChar SimulatorCommandEntry[] = wxT( "SimCmdLine" ); PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetConfigurationSettings( void ) @@ -592,64 +584,62 @@ PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetConfigurationSettings( void ) } -void SCH_EDIT_FRAME::LoadSettings() +void SCH_EDIT_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); + EDA_DRAW_FRAME::LoadSettings( aCfg ); long tmp; - wxConfig* cfg = wxGetApp().GetSettings(); - - EDA_DRAW_FRAME::LoadSettings(); - - wxGetApp().ReadCurrentSetupValues( GetConfigurationSettings() ); + wxConfigLoadSetups( aCfg, GetConfigurationSettings() ); // This is required until someone gets rid of the global variable s_layerColor. m_GridColor = GetLayerColor( LAYER_GRID ); - SetDefaultBusThickness( cfg->Read( DefaultBusWidthEntry, 12l ) ); - SetDefaultLineThickness( cfg->Read( DefaultDrawLineWidthEntry, 6l ) ); - cfg->Read( ShowHiddenPinsEntry, &m_showAllPins, false ); - cfg->Read( HorzVertLinesOnlyEntry, &m_forceHVLines, true ); + SetDefaultBusThickness( aCfg->Read( DefaultBusWidthEntry, 12l ) ); + SetDefaultLineThickness( aCfg->Read( DefaultDrawLineWidthEntry, 6l ) ); + aCfg->Read( ShowHiddenPinsEntry, &m_showAllPins, false ); + aCfg->Read( HorzVertLinesOnlyEntry, &m_forceHVLines, true ); // Load print preview window session settings. - cfg->Read( PreviewFramePositionXEntry, &tmp, -1 ); + aCfg->Read( PreviewFramePositionXEntry, &tmp, -1 ); m_previewPosition.x = (int) tmp; - cfg->Read( PreviewFramePositionYEntry, &tmp, -1 ); + aCfg->Read( PreviewFramePositionYEntry, &tmp, -1 ); m_previewPosition.y = (int) tmp; - cfg->Read( PreviewFrameWidthEntry, &tmp, -1 ); + aCfg->Read( PreviewFrameWidthEntry, &tmp, -1 ); m_previewSize.SetWidth( (int) tmp ); - cfg->Read( PreviewFrameHeightEntry, &tmp, -1 ); + aCfg->Read( PreviewFrameHeightEntry, &tmp, -1 ); m_previewSize.SetHeight( (int) tmp ); // Load print dialog session settings. - cfg->Read( PrintDialogPositionXEntry, &tmp, -1 ); + aCfg->Read( PrintDialogPositionXEntry, &tmp, -1 ); m_printDialogPosition.x = (int) tmp; - cfg->Read( PrintDialogPositionYEntry, &tmp, -1 ); + aCfg->Read( PrintDialogPositionYEntry, &tmp, -1 ); m_printDialogPosition.y = (int) tmp; - cfg->Read( PrintDialogWidthEntry, &tmp, -1 ); + aCfg->Read( PrintDialogWidthEntry, &tmp, -1 ); m_printDialogSize.SetWidth( (int) tmp ); - cfg->Read( PrintDialogHeightEntry, &tmp, -1 ); + aCfg->Read( PrintDialogHeightEntry, &tmp, -1 ); m_printDialogSize.SetHeight( (int) tmp ); // Load netlists options: - cfg->Read( SimulatorCommandEntry, &m_simulatorCommand ); + aCfg->Read( SimulatorCommandEntry, &m_simulatorCommand ); // Load find dialog session setting. - cfg->Read( FindDialogPositionXEntry, &tmp, -1 ); + aCfg->Read( FindDialogPositionXEntry, &tmp, -1 ); m_findDialogPosition.x = (int) tmp; - cfg->Read( FindDialogPositionYEntry, &tmp, -1 ); + aCfg->Read( FindDialogPositionYEntry, &tmp, -1 ); m_findDialogPosition.y = (int) tmp; - cfg->Read( FindDialogWidthEntry, &tmp, -1 ); + aCfg->Read( FindDialogWidthEntry, &tmp, -1 ); m_findDialogSize.SetWidth( (int) tmp ); - cfg->Read( FindDialogHeightEntry, &tmp, -1 ); + aCfg->Read( FindDialogHeightEntry, &tmp, -1 ); m_findDialogSize.SetHeight( (int) tmp ); + wxASSERT_MSG( m_findReplaceData, wxT( "Find dialog data settings object not created. Bad programmer!" ) ); - cfg->Read( FindReplaceFlagsEntry, &tmp, (long) wxFR_DOWN ); + + aCfg->Read( FindReplaceFlagsEntry, &tmp, (long) wxFR_DOWN ); m_findReplaceData->SetFlags( (wxUint32) tmp & ~FR_REPLACE_ITEM_FOUND ); - m_findReplaceData->SetFindString( cfg->Read( FindStringEntry, wxEmptyString ) ); - m_findReplaceData->SetReplaceString( cfg->Read( ReplaceStringEntry, wxEmptyString ) ); + m_findReplaceData->SetFindString( aCfg->Read( FindStringEntry, wxEmptyString ) ); + m_findReplaceData->SetReplaceString( aCfg->Read( ReplaceStringEntry, wxEmptyString ) ); // Load the find and replace string history list. for( int i = 0; i < FR_HISTORY_LIST_CNT; ++i ) @@ -657,19 +647,19 @@ void SCH_EDIT_FRAME::LoadSettings() wxString tmpHistory; wxString entry; entry.Printf( FindStringHistoryEntry, i ); - tmpHistory = cfg->Read( entry, wxEmptyString ); + tmpHistory = aCfg->Read( entry, wxEmptyString ); if( !tmpHistory.IsEmpty() ) m_findStringHistoryList.Add( tmpHistory ); entry.Printf( ReplaceStringHistoryEntry, i ); - tmpHistory = cfg->Read( entry, wxEmptyString ); + tmpHistory = aCfg->Read( entry, wxEmptyString ); if( !tmpHistory.IsEmpty() ) m_replaceStringHistoryList.Add( tmpHistory ); } - wxString templateFieldNames = cfg->Read( FieldNamesEntry, wxEmptyString ); + wxString templateFieldNames = aCfg->Read( FieldNamesEntry, wxEmptyString ); if( !templateFieldNames.IsEmpty() ) { @@ -688,47 +678,43 @@ void SCH_EDIT_FRAME::LoadSettings() } -void SCH_EDIT_FRAME::SaveSettings() +void SCH_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); + EDA_DRAW_FRAME::SaveSettings( aCfg ); - wxConfig* cfg = wxGetApp().GetSettings(); + wxConfigSaveSetups( aCfg, GetConfigurationSettings() ); - EDA_DRAW_FRAME::SaveSettings(); - - wxGetApp().SaveCurrentSetupValues( GetConfigurationSettings() ); - - cfg->Write( DefaultBusWidthEntry, (long) GetDefaultBusThickness() ); - cfg->Write( DefaultDrawLineWidthEntry, (long) GetDefaultLineThickness() ); - cfg->Write( ShowHiddenPinsEntry, m_showAllPins ); - cfg->Write( HorzVertLinesOnlyEntry, GetForceHVLines() ); + aCfg->Write( DefaultBusWidthEntry, (long) GetDefaultBusThickness() ); + aCfg->Write( DefaultDrawLineWidthEntry, (long) GetDefaultLineThickness() ); + aCfg->Write( ShowHiddenPinsEntry, m_showAllPins ); + aCfg->Write( HorzVertLinesOnlyEntry, GetForceHVLines() ); // Save print preview window session settings. - cfg->Write( PreviewFramePositionXEntry, m_previewPosition.x ); - cfg->Write( PreviewFramePositionYEntry, m_previewPosition.y ); - cfg->Write( PreviewFrameWidthEntry, m_previewSize.GetWidth() ); - cfg->Write( PreviewFrameHeightEntry, m_previewSize.GetHeight() ); + aCfg->Write( PreviewFramePositionXEntry, m_previewPosition.x ); + aCfg->Write( PreviewFramePositionYEntry, m_previewPosition.y ); + aCfg->Write( PreviewFrameWidthEntry, m_previewSize.GetWidth() ); + aCfg->Write( PreviewFrameHeightEntry, m_previewSize.GetHeight() ); // Save print dialog session settings. - cfg->Write( PrintDialogPositionXEntry, m_printDialogPosition.x ); - cfg->Write( PrintDialogPositionYEntry, m_printDialogPosition.y ); - cfg->Write( PrintDialogWidthEntry, m_printDialogSize.GetWidth() ); - cfg->Write( PrintDialogHeightEntry, m_printDialogSize.GetHeight() ); + aCfg->Write( PrintDialogPositionXEntry, m_printDialogPosition.x ); + aCfg->Write( PrintDialogPositionYEntry, m_printDialogPosition.y ); + aCfg->Write( PrintDialogWidthEntry, m_printDialogSize.GetWidth() ); + aCfg->Write( PrintDialogHeightEntry, m_printDialogSize.GetHeight() ); // Save netlists options: - cfg->Write( SimulatorCommandEntry, m_simulatorCommand ); + aCfg->Write( SimulatorCommandEntry, m_simulatorCommand ); // Save find dialog session setting. - cfg->Write( FindDialogPositionXEntry, m_findDialogPosition.x ); - cfg->Write( FindDialogPositionYEntry, m_findDialogPosition.y ); - cfg->Write( FindDialogWidthEntry, m_findDialogSize.GetWidth() ); - cfg->Write( FindDialogHeightEntry, m_findDialogSize.GetHeight() ); + aCfg->Write( FindDialogPositionXEntry, m_findDialogPosition.x ); + aCfg->Write( FindDialogPositionYEntry, m_findDialogPosition.y ); + aCfg->Write( FindDialogWidthEntry, m_findDialogSize.GetWidth() ); + aCfg->Write( FindDialogHeightEntry, m_findDialogSize.GetHeight() ); wxASSERT_MSG( m_findReplaceData, wxT( "Find dialog data settings object not created. Bad programmer!" ) ); - cfg->Write( FindReplaceFlagsEntry, + aCfg->Write( FindReplaceFlagsEntry, (long) m_findReplaceData->GetFlags() & ~FR_REPLACE_ITEM_FOUND ); - cfg->Write( FindStringEntry, m_findReplaceData->GetFindString() ); - cfg->Write( ReplaceStringEntry, m_findReplaceData->GetReplaceString() ); + aCfg->Write( FindStringEntry, m_findReplaceData->GetFindString() ); + aCfg->Write( ReplaceStringEntry, m_findReplaceData->GetReplaceString() ); // Save the find and replace string history list. unsigned i; @@ -738,13 +724,13 @@ void SCH_EDIT_FRAME::SaveSettings() for( i = 0; i < m_findStringHistoryList.GetCount() && i < FR_HISTORY_LIST_CNT; i++ ) { entry.Printf( FindStringHistoryEntry, i ); - cfg->Write( entry, m_findStringHistoryList[ i ] ); + aCfg->Write( entry, m_findStringHistoryList[ i ] ); } for( i = 0; i < m_replaceStringHistoryList.GetCount() && i < FR_HISTORY_LIST_CNT; i++ ) { entry.Printf( ReplaceStringHistoryEntry, i ); - cfg->Write( entry, m_replaceStringHistoryList[ i ] ); + aCfg->Write( entry, m_replaceStringHistoryList[ i ] ); } // Save template fieldnames @@ -758,5 +744,5 @@ void SCH_EDIT_FRAME::SaveSettings() record.Replace( wxT("\n"), wxT(""), true ); // strip all newlines record.Replace( wxT(" "), wxT(" "), true ); // double space to single - cfg->Write( FieldNamesEntry, record ); + aCfg->Write( FieldNamesEntry, record ); } diff --git a/eeschema/eeschema_config.h b/eeschema/eeschema_config.h index 0c9135066c..8bdfa54ec6 100644 --- a/eeschema/eeschema_config.h +++ b/eeschema/eeschema_config.h @@ -2,7 +2,7 @@ * @file eeschema_config.h */ -#include +#include #define GROUP wxT( "/eeschema" ) #define GROUPCOMMON wxT( "/common" ) diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index fa6f17b91e..8e83cdc524 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -243,14 +243,15 @@ bool SCH_EDIT_FRAME::LoadCacheLibrary( const wxString& aFilename ) } -bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) +bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) { SCH_SCREEN* screen; - wxString FullFileName, msg; - bool LibCacheExist = false; - SCH_SCREENS ScreenList; + wxString fullFileName( aFileSet[0] ); + wxString msg; + bool libCacheExist = false; + SCH_SCREENS screenList; - for( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() ) + for( screen = screenList.GetFirst(); screen != NULL; screen = screenList.GetNext() ) { if( screen->IsModify() ) break; @@ -258,10 +259,12 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) if( screen ) { - int response = YesNoCancelDialog( this, _( "The current schematic has been modified. Do " - "you wish to save the changes?" ), - wxEmptyString, - _( "Save and Load" ), _( "Load Without Saving" ) ); + int response = YesNoCancelDialog( this, + _( "The current schematic has been modified. Do you wish to save the changes?" ), + wxEmptyString, + _( "Save and Load" ), + _( "Load Without Saving" ) + ); if( response == wxID_CANCEL ) { @@ -274,9 +277,8 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) } } - FullFileName = aFileName; - - if( FullFileName.IsEmpty() && !aIsNew ) +/* + if( fullFileName.IsEmpty() && !aIsNew ) { wxFileDialog dlg( this, _( "Open Schematic" ), wxGetCwd(), wxEmptyString, SchematicFileWildcard, @@ -287,16 +289,17 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) FullFileName = dlg.GetPath(); } +*/ - wxFileName fn = FullFileName; + wxFileName fn = fullFileName; if( fn.IsRelative() ) { fn.MakeAbsolute(); - FullFileName = fn.GetFullPath(); + fullFileName = fn.GetFullPath(); } - if( !wxGetApp().LockFile( FullFileName ) ) + if( !Pgm().LockFile( fullFileName ) ) { DisplayError( this, _( "This file is already open." ) ); return false; @@ -312,16 +315,19 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) CreateScreens(); screen = GetScreen(); - wxLogDebug( wxT( "Loading schematic " ) + FullFileName ); + wxLogDebug( wxT( "Loading schematic " ) + fullFileName ); + + // @todo: this is bad: wxSetWorkingDirectory( fn.GetPath() ); - screen->SetFileName( FullFileName ); - g_RootSheet->SetFileName( FullFileName ); + screen->SetFileName( fullFileName ); + g_RootSheet->SetFileName( fullFileName ); SetStatusText( wxEmptyString ); ClearMsgPanel(); screen->ClrModify(); +#if 0 if( aIsNew ) { /* SCH_SCREEN constructor does this now @@ -347,9 +353,10 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) m_canvas->Refresh(); return true; } +#endif // Reloading configuration. - msg.Printf( _( "Ready\nWorking dir: <%s>\n" ), GetChars( wxGetCwd() ) ); + msg.Printf( _( "Ready\nWorking dir: '%s'\n" ), GetChars( wxGetCwd() ) ); PrintMsg( msg ); LoadProjectFile( wxEmptyString, false ); @@ -361,12 +368,12 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) // Delete old caches. CMP_LIBRARY::RemoveCacheLibrary(); - LibCacheExist = LoadCacheLibrary( g_RootSheet->GetScreen()->GetFileName() ); + libCacheExist = LoadCacheLibrary( g_RootSheet->GetScreen()->GetFileName() ); - if( !wxFileExists( g_RootSheet->GetScreen()->GetFileName() ) && !LibCacheExist ) + if( !wxFileExists( g_RootSheet->GetScreen()->GetFileName() ) && !libCacheExist ) { Zoom_Automatique( false ); - msg.Printf( _( "File <%s> not found." ), + msg.Printf( _( "File '%s' not found." ), GetChars( g_RootSheet->GetScreen()->GetFileName() ) ); DisplayInfoMessage( this, msg ); return false; @@ -379,11 +386,12 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) UpdateFileHistory( g_RootSheet->GetScreen()->GetFileName() ); - /* Redraw base screen (ROOT) if necessary. */ + // Redraw base screen (ROOT) if necessary. GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); Zoom_Automatique( false ); SetSheetNumberAndCount(); m_canvas->Refresh( true ); + return diag; } @@ -391,8 +399,8 @@ bool SCH_EDIT_FRAME::LoadOneEEProject( const wxString& aFileName, bool aIsNew ) bool SCH_EDIT_FRAME::AppendOneEEProject() { SCH_SCREEN* screen; - wxString FullFileName; - wxString msg; + wxString fullFileName; + wxString msg; screen = GetScreen(); @@ -410,22 +418,22 @@ bool SCH_EDIT_FRAME::AppendOneEEProject() if( dlg.ShowModal() == wxID_CANCEL ) return false; - FullFileName = dlg.GetPath(); + fullFileName = dlg.GetPath(); - wxFileName fn = FullFileName; + wxFileName fn = fullFileName; if( fn.IsRelative() ) { fn.MakeAbsolute(); - FullFileName = fn.GetFullPath(); + fullFileName = fn.GetFullPath(); } - LoadCacheLibrary( FullFileName ); + LoadCacheLibrary( fullFileName ); - wxLogDebug( wxT( "Importing schematic " ) + FullFileName ); + wxLogDebug( wxT( "Importing schematic " ) + fullFileName ); // load the project - bool success = LoadOneEEFile( screen, FullFileName, true ); + bool success = LoadOneEEFile( screen, fullFileName, true ); if( success ) { // load sub-sheets diff --git a/eeschema/find.cpp b/eeschema/find.cpp index ed52efe966..d29cd4aba8 100644 --- a/eeschema/find.cpp +++ b/eeschema/find.cpp @@ -34,7 +34,7 @@ * in current sheet or whole the project */ #include -#include +#include #include #include #include diff --git a/eeschema/getpart.cpp b/eeschema/getpart.cpp index a423d2ea72..f30d6a827b 100644 --- a/eeschema/getpart.cpp +++ b/eeschema/getpart.cpp @@ -29,7 +29,7 @@ */ #include -#include +#include #include #include #include @@ -56,12 +56,13 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( void ) wxString cmpname; // Close the current Lib browser, if open, and open a new one, in "modal" mode: - LIB_VIEW_FRAME * viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer();; + LIB_VIEW_FRAME* viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer( this ); if( viewlibFrame ) viewlibFrame->Destroy(); - viewlibFrame = new LIB_VIEW_FRAME( this, NULL, &semaphore, + viewlibFrame = new LIB_VIEW_FRAME( &Kiway(), this, NULL, &semaphore, KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT ); + // Show the library viewer frame until it is closed // Wait for viewer closing event: while( semaphore.TryWait() == wxSEMA_BUSY ) diff --git a/eeschema/invoke_sch_dialog.h b/eeschema/invoke_sch_dialog.h index 4cd27be957..b2a8fba3f8 100644 --- a/eeschema/invoke_sch_dialog.h +++ b/eeschema/invoke_sch_dialog.h @@ -75,5 +75,6 @@ int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller ); #define NET_PLUGIN_CHANGE 1 int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller ); +int InvokeEeschemaConfig( SCH_EDIT_FRAME* aEditFrame, wxFrame* aParent ); #endif // INVOKE_SCH_DIALOG_H_ diff --git a/eeschema/lib_arc.cpp b/eeschema/lib_arc.cpp index c4a3735f8c..66bb12b24d 100644 --- a/eeschema/lib_arc.cpp +++ b/eeschema/lib_arc.cpp @@ -553,7 +553,7 @@ void LIB_ARC::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) LIB_ITEM::GetMsgPanelInfo( aList ); - msg = ReturnStringFromValue( g_UserUnit, m_Width, true ); + msg = StringFromValue( g_UserUnit, m_Width, true ); aList.push_back( MSG_PANEL_ITEM( _( "Line width" ), msg, BLUE ) ); diff --git a/eeschema/lib_bezier.cpp b/eeschema/lib_bezier.cpp index 1d4601950a..b58e11cb6b 100644 --- a/eeschema/lib_bezier.cpp +++ b/eeschema/lib_bezier.cpp @@ -411,7 +411,7 @@ void LIB_BEZIER::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) LIB_ITEM::GetMsgPanelInfo( aList ); - msg = ReturnStringFromValue( g_UserUnit, m_Width, true ); + msg = StringFromValue( g_UserUnit, m_Width, true ); aList.push_back( MSG_PANEL_ITEM( _( "Line width" ), msg, BLUE ) ); diff --git a/eeschema/lib_circle.cpp b/eeschema/lib_circle.cpp index 9dadd713fe..82a19b9585 100644 --- a/eeschema/lib_circle.cpp +++ b/eeschema/lib_circle.cpp @@ -269,11 +269,11 @@ void LIB_CIRCLE::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) LIB_ITEM::GetMsgPanelInfo( aList ); - msg = ReturnStringFromValue( g_UserUnit, m_Width, true ); + msg = StringFromValue( g_UserUnit, m_Width, true ); aList.push_back( MSG_PANEL_ITEM( _( "Line width" ), msg, BLUE ) ); - msg = ReturnStringFromValue( g_UserUnit, m_Radius, true ); + msg = StringFromValue( g_UserUnit, m_Radius, true ); aList.push_back( MSG_PANEL_ITEM( _( "Radius" ), msg, RED ) ); msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x, diff --git a/eeschema/lib_field.cpp b/eeschema/lib_field.cpp index 4e924a5333..392daecc8c 100644 --- a/eeschema/lib_field.cpp +++ b/eeschema/lib_field.cpp @@ -27,7 +27,7 @@ */ #include -#include +#include #include #include #include @@ -517,7 +517,7 @@ wxString LIB_FIELD::GetFullText( int unit ) text << wxT( "?" ); if( GetParent()->IsMulti() ) - text << LIB_COMPONENT::ReturnSubReference( unit ); + text << LIB_COMPONENT::SubReference( unit ); return text; } @@ -763,10 +763,10 @@ void LIB_FIELD::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) msg = GetTextStyleName(); aList.push_back( MSG_PANEL_ITEM( _( "Style" ), msg, MAGENTA ) ); - msg = ReturnStringFromValue( g_UserUnit, m_Size.x, true ); + msg = StringFromValue( g_UserUnit, m_Size.x, true ); aList.push_back( MSG_PANEL_ITEM( _( "Size X" ), msg, BLUE ) ); - msg = ReturnStringFromValue( g_UserUnit, m_Size.y, true ); + msg = StringFromValue( g_UserUnit, m_Size.y, true ); aList.push_back( MSG_PANEL_ITEM( _( "Size Y" ), msg, BLUE ) ); // Display field name (ref, value ...) diff --git a/eeschema/lib_pin.cpp b/eeschema/lib_pin.cpp index 481c083c6f..b8e8f7897a 100644 --- a/eeschema/lib_pin.cpp +++ b/eeschema/lib_pin.cpp @@ -27,7 +27,7 @@ */ #include -#include +#include #include #include #include @@ -602,7 +602,7 @@ bool LIB_PIN::Save( OUTPUTFORMATTER& aFormatter ) break; } - ReturnPinStringNum( StringPinNum ); + PinStringNum( StringPinNum ); if( StringPinNum.IsEmpty() ) StringPinNum = wxT( "~" ); @@ -824,7 +824,7 @@ void LIB_PIN::drawGraphic( EDA_DRAW_PANEL* aPanel, DrawPinText = false; /* Calculate pin orient taking in account the component orientation. */ - int orient = ReturnPinDrawOrient( aTransform ); + int orient = PinDrawOrient( aTransform ); /* Calculate the pin position */ wxPoint pos1 = aTransform.TransformCoordinate( m_position ) + aOffset; @@ -1102,7 +1102,7 @@ void LIB_PIN::DrawPinTexts( EDA_DRAW_PANEL* panel, GetLayerColor( LAYER_PINNUM ) : Color ); /* Create the pin num string */ - ReturnPinStringNum( StringPinNum ); + PinStringNum( StringPinNum ); x1 = pin_pos.x; y1 = pin_pos.y; @@ -1396,7 +1396,7 @@ void LIB_PIN::PlotPinTexts( PLOTTER* plotter, NumColor = GetLayerColor( LAYER_PINNUM ); /* Create the pin num string */ - ReturnPinStringNum( StringPinNum ); + PinStringNum( StringPinNum ); x1 = pin_pos.x; y1 = pin_pos.y; @@ -1565,7 +1565,7 @@ void LIB_PIN::PlotPinTexts( PLOTTER* plotter, } -wxPoint LIB_PIN::ReturnPinEndPoint() const +wxPoint LIB_PIN::PinEndPoint() const { wxPoint pos = m_position; @@ -1592,7 +1592,7 @@ wxPoint LIB_PIN::ReturnPinEndPoint() const } -int LIB_PIN::ReturnPinDrawOrient( const TRANSFORM& aTransform ) const +int LIB_PIN::PinDrawOrient( const TRANSFORM& aTransform ) const { int orient; wxPoint end; // position of pin end starting at 0,0 according to its orientation, length = 1 @@ -1637,13 +1637,13 @@ int LIB_PIN::ReturnPinDrawOrient( const TRANSFORM& aTransform ) const } -void LIB_PIN::ReturnPinStringNum( wxString& aStringBuffer ) const +void LIB_PIN::PinStringNum( wxString& aStringBuffer ) const { - aStringBuffer = ReturnPinStringNum( m_number ); + aStringBuffer = PinStringNum( m_number ); } -wxString LIB_PIN::ReturnPinStringNum( long aPinNum ) +wxString LIB_PIN::PinStringNum( long aPinNum ) { char ascii_buf[5]; @@ -1714,7 +1714,7 @@ void LIB_PIN::SetOffset( const wxPoint& aOffset ) bool LIB_PIN::Inside( EDA_RECT& rect ) const { - wxPoint end = ReturnPinEndPoint(); + wxPoint end = PinEndPoint(); return rect.Contains( m_position.x, -m_position.y ) || rect.Contains( end.x, -end.y ); } @@ -1809,7 +1809,7 @@ void LIB_PIN::Plot( PLOTTER* plotter, const wxPoint& offset, bool fill, if( ! IsVisible() ) return; - int orient = ReturnPinDrawOrient( aTransform ); + int orient = PinDrawOrient( aTransform ); wxPoint pos = aTransform.TransformCoordinate( m_position ) + offset; @@ -1842,7 +1842,7 @@ void LIB_PIN::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) if( m_number == 0 ) Text = wxT( "?" ); else - ReturnPinStringNum( Text ); + PinStringNum( Text ); aList.push_back( MSG_PANEL_ITEM( _( "Number" ), Text, DARKCYAN ) ); @@ -1860,7 +1860,7 @@ void LIB_PIN::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) aList.push_back( MSG_PANEL_ITEM( _( "Visible" ), Text, DARKGREEN ) ); // Display pin length - Text = ReturnStringFromValue( g_UserUnit, m_length, true ); + Text = StringFromValue( g_UserUnit, m_length, true ); aList.push_back( MSG_PANEL_ITEM( _( "Length" ), Text, MAGENTA ) ); Text = wxGetTranslation( pin_orientation_names[ GetOrientationCodeIndex( m_orientation ) ] ); @@ -1937,7 +1937,7 @@ const EDA_RECT LIB_PIN::GetBoundingBox() const } // Now, calculate boundary box corners position for the actual pin orientation - int orient = ReturnPinDrawOrient( DefaultTransform ); + int orient = PinDrawOrient( DefaultTransform ); /* Calculate the pin position */ switch( orient ) diff --git a/eeschema/lib_pin.h b/eeschema/lib_pin.h index c89538a216..bf4c504776 100644 --- a/eeschema/lib_pin.h +++ b/eeschema/lib_pin.h @@ -142,20 +142,20 @@ public: const EDA_RECT GetBoundingBox() const; // Virtual /** - * Function ReturnPinEndPoint + * Function PinEndPoint * * @return The pin end position for a component in the normal orientation. */ - wxPoint ReturnPinEndPoint() const; + wxPoint PinEndPoint() const; /** - * Function ReturnPinDrawOrient + * Function PinDrawOrient * returns the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT), * according to its orientation and the matrix transform (rot, mirror) \a aTransform * * @param aTransform Transform matrix */ - int ReturnPinDrawOrient( const TRANSFORM& aTransform ) const; + int PinDrawOrient( const TRANSFORM& aTransform ) const; /** * Fill a string buffer with pin number. @@ -165,20 +165,20 @@ public: * * @param aStringBuffer - the wxString to store the pin num as an unicode string */ - void ReturnPinStringNum( wxString& aStringBuffer ) const; + void PinStringNum( wxString& aStringBuffer ) const; long GetNumber() const { return m_number; } - wxString GetNumberString() const { return ReturnPinStringNum( m_number ); } + wxString GetNumberString() const { return PinStringNum( m_number ); } /** - * Function ReturnPinStringNum (static function) + * Function PinStringNum (static function) * Pin num is coded as a long or 4 ascii chars * @param aPinNum = a long containing a pin num * @return aStringBuffer = the wxString to store the pin num as an * unicode string */ - static wxString ReturnPinStringNum( long aPinNum ); + static wxString PinStringNum( long aPinNum ); /** * Function SetPinNumFromString diff --git a/eeschema/lib_polyline.cpp b/eeschema/lib_polyline.cpp index 2b3fabc71b..ce0c7e93ef 100644 --- a/eeschema/lib_polyline.cpp +++ b/eeschema/lib_polyline.cpp @@ -399,7 +399,7 @@ void LIB_POLYLINE::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) LIB_ITEM::GetMsgPanelInfo( aList ); - msg = ReturnStringFromValue( g_UserUnit, m_Width, true ); + msg = StringFromValue( g_UserUnit, m_Width, true ); aList.push_back( MSG_PANEL_ITEM( _( "Line width" ), msg, BLUE ) ); diff --git a/eeschema/lib_rectangle.cpp b/eeschema/lib_rectangle.cpp index 42c7a1b395..e21bc9054d 100644 --- a/eeschema/lib_rectangle.cpp +++ b/eeschema/lib_rectangle.cpp @@ -249,7 +249,7 @@ void LIB_RECTANGLE::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) LIB_ITEM::GetMsgPanelInfo( aList ); - msg = ReturnStringFromValue( g_UserUnit, m_Width, true ); + msg = StringFromValue( g_UserUnit, m_Width, true ); aList.push_back( MSG_PANEL_ITEM( _( "Line width" ), msg, BLUE ) ); } diff --git a/eeschema/lib_text.cpp b/eeschema/lib_text.cpp index a197b9251a..d52acdda97 100644 --- a/eeschema/lib_text.cpp +++ b/eeschema/lib_text.cpp @@ -423,7 +423,7 @@ void LIB_TEXT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) LIB_ITEM::GetMsgPanelInfo( aList ); - msg = ReturnStringFromValue( g_UserUnit, m_Thickness, true ); + msg = StringFromValue( g_UserUnit, m_Thickness, true ); aList.push_back( MSG_PANEL_ITEM( _( "Line width" ), msg, BLUE ) ); } diff --git a/eeschema/libedit.cpp b/eeschema/libedit.cpp index e5f3b6511d..e8d2cf64e7 100644 --- a/eeschema/libedit.cpp +++ b/eeschema/libedit.cpp @@ -29,9 +29,10 @@ */ #include +#include #include #include -#include +#include #include #include #include @@ -318,8 +319,13 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) } if( newFile ) - { // Get a new name for the library - wxString default_path = wxGetApp().ReturnLastVisitedLibraryPath(); + { + PROJECT& prj = Prj(); + SEARCH_STACK& search = prj.SchSearchS(); + + // Get a new name for the library + wxString default_path = prj.RPath(PROJECT::SCH_LIB).LastVisitedPath( search ); + wxFileDialog dlg( this, _( "Component Library Name:" ), default_path, wxEmptyString, SchematicLibraryFileExtension, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); @@ -334,7 +340,7 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) if( fn.GetExt().IsEmpty() ) fn.SetExt( SchematicLibraryFileExtension ); - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + prj.RPath(PROJECT::SCH_LIB).SaveLastVisitedPath( fn.GetPath() ); } else { @@ -402,6 +408,7 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) if( docFileName.FileExists() ) { backupFileName.SetExt( wxT( "bck" ) ); + if( backupFileName.FileExists() ) wxRemoveFile( backupFileName.GetFullPath() ); diff --git a/eeschema/libedit_plot_component.cpp b/eeschema/libedit_plot_component.cpp index 45bf13a412..39d3dbafcb 100644 --- a/eeschema/libedit_plot_component.cpp +++ b/eeschema/libedit_plot_component.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp index 8b7b5a1794..2b26819d7d 100644 --- a/eeschema/libeditframe.cpp +++ b/eeschema/libeditframe.cpp @@ -29,7 +29,8 @@ */ #include -#include +#include +#include #include #include #include @@ -188,15 +189,11 @@ END_EVENT_TABLE() #define LIB_EDIT_FRAME_NAME wxT( "LibeditFrame" ) -LIB_EDIT_FRAME::LIB_EDIT_FRAME( SCH_EDIT_FRAME* aParent, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style ) : - SCH_BASE_FRAME( aParent, LIBEDITOR_FRAME_TYPE, title, pos, size, - style, GetLibEditFrameName() ) +LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, SCH_EDIT_FRAME* aParent ) : + SCH_BASE_FRAME( aKiway, aParent, LIBEDITOR_FRAME_TYPE, _( "Library Editor" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, GetLibEditFrameName() ) { - wxASSERT( aParent ); + wxASSERT( aParent ); // LIB_EDIT_FRAME needs a parent, since it peeks up there. m_FrameName = GetLibEditFrameName(); m_showAxis = true; // true to draw axis @@ -219,7 +216,7 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( SCH_EDIT_FRAME* aParent, SetCrossHairPosition( wxPoint( 0, 0 ) ); - LoadSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); @@ -295,17 +292,29 @@ LIB_EDIT_FRAME* LIB_EDIT_FRAME::GetActiveLibraryEditor() } -void LIB_EDIT_FRAME::LoadSettings() +void LIB_EDIT_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* cfg; +#if 0 // original + + wxConfigBase* cfg; EDA_DRAW_FRAME::LoadSettings(); wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - cfg = wxGetApp().GetSettings(); + cfg = Pgm().GetSettings(); +#else - m_lastLibExportPath = cfg->Read( lastLibExportPathEntry, ::wxGetCwd() ); - m_lastLibImportPath = cfg->Read( lastLibImportPathEntry, ::wxGetCwd() ); + EDA_DRAW_FRAME::LoadSettings( aCfg ); + + wxConfigPathChanger cpc( aCfg, m_configPath ); + + m_lastLibExportPath = aCfg->Read( lastLibExportPathEntry, ::wxGetCwd() ); + m_lastLibImportPath = aCfg->Read( lastLibImportPathEntry, ::wxGetCwd() ); + +#endif + + m_lastLibExportPath = aCfg->Read( lastLibExportPathEntry, ::wxGetCwd() ); + m_lastLibImportPath = aCfg->Read( lastLibImportPathEntry, ::wxGetCwd() ); } @@ -316,17 +325,14 @@ void LIB_EDIT_FRAME::SetDrawItem( LIB_ITEM* drawItem ) -void LIB_EDIT_FRAME::SaveSettings() +void LIB_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* cfg; + EDA_DRAW_FRAME::SaveSettings( aCfg ); - EDA_DRAW_FRAME::SaveSettings(); + wxConfigPathChanger cpc( aCfg, m_configPath ); - wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - cfg = wxGetApp().GetSettings(); - - cfg->Write( lastLibExportPathEntry, m_lastLibExportPath ); - cfg->Write( lastLibImportPathEntry, m_lastLibImportPath ); + aCfg->Write( lastLibExportPathEntry, m_lastLibExportPath ); + aCfg->Write( lastLibImportPathEntry, m_lastLibImportPath ); } @@ -457,7 +463,7 @@ void LIB_EDIT_FRAME::UpdatePartSelectList() { for( int i = 0; i < m_component->GetPartCount(); i++ ) { - wxString sub = LIB_COMPONENT::ReturnSubReference( i+1, false ); + wxString sub = LIB_COMPONENT::SubReference( i+1, false ); wxString part = wxString::Format( _( "Unit %s" ), GetChars( sub ) ); m_partSelectBox->Append( part ); } @@ -606,15 +612,19 @@ void LIB_EDIT_FRAME::OnViewEntryDoc( wxCommandEvent& event ) if( m_component == NULL ) return; - wxString fileName; - LIB_ALIAS* alias = m_component->GetAlias( m_aliasName ); + wxString fileName; + LIB_ALIAS* alias = m_component->GetAlias( m_aliasName ); wxCHECK_RET( alias != NULL, wxT( "Alias not found." ) ); fileName = alias->GetDocFileName(); if( !fileName.IsEmpty() ) - GetAssociatedDocument( this, fileName, &wxGetApp().GetLibraryPathList() ); + { + SEARCH_STACK* lib_search = &Prj().SchSearchS(); + + GetAssociatedDocument( this, fileName, lib_search ); + } } diff --git a/eeschema/libeditframe.h b/eeschema/libeditframe.h index 16802af6b0..45582f34d8 100644 --- a/eeschema/libeditframe.h +++ b/eeschema/libeditframe.h @@ -45,16 +45,15 @@ class LIB_ALIAS; class LIB_FIELD; class DIALOG_LIB_EDIT_TEXT; - /** * The component library editor main window. */ class LIB_EDIT_FRAME : public SCH_BASE_FRAME { - LIB_COMPONENT* m_tempCopyComponent; ///< Temporary copy of current component during edit. - LIB_COLLECTOR m_collectedItems; // Used for hit testing. - wxComboBox* m_partSelectBox; // a Box to select a part to edit (if any) - wxComboBox* m_aliasSelectBox; // a box to select the alias to edit (if any) + LIB_COMPONENT* m_tempCopyComponent; ///< Temporary copy of current component during edit. + LIB_COLLECTOR m_collectedItems; ///< Used for hit testing. + wxComboBox* m_partSelectBox; ///< a Box to select a part to edit (if any) + wxComboBox* m_aliasSelectBox; ///< a box to select the alias to edit (if any) wxString m_configPath; wxString m_lastLibImportPath; @@ -122,9 +121,8 @@ class LIB_EDIT_FRAME : public SCH_BASE_FRAME LIB_ITEM* locateItem( const wxPoint& aPosition, const KICAD_T aFilterList[] ); public: - LIB_EDIT_FRAME( SCH_EDIT_FRAME* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); + + LIB_EDIT_FRAME( KIWAY* aKiway, SCH_EDIT_FRAME* aParent ); ~LIB_EDIT_FRAME(); @@ -294,23 +292,9 @@ public: void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); - /** - * Function LoadSettings - * loads the library editor frame specific configuration settings. - * - * Don't forget to call this method from any derived classes or the settings will not - * get loaded. - */ - void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); - /** - * Function SaveSettings - * saves the library editor frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the settings will - * not get saved. - */ - void SaveSettings(); + void SaveSettings( wxConfigBase* aCfg ); /** * Function CloseWindow @@ -575,11 +559,11 @@ public: /* Block commands: */ /** - * Function ReturnBlockCommand + * Function BlockCommand * returns the block command (BLOCK_MOVE, BLOCK_COPY...) corresponding to * the \a aKey (ALT, SHIFT ALT ..) */ - virtual int ReturnBlockCommand( int aKey ); + virtual int BlockCommand( int aKey ); /** * Function HandleBlockPlace diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp index 32d93a5c35..8c20b87633 100644 --- a/eeschema/menubar.cpp +++ b/eeschema/menubar.cpp @@ -32,7 +32,8 @@ #endif #include -#include +#include +#include #include #include @@ -86,11 +87,13 @@ void SCH_EDIT_FRAME::ReCreateMenuBar() // Add this menu to list menu managed by m_fileHistory // (the file history will be updated when adding/removing files in history if( openRecentMenu ) - wxGetApp().GetFileHistory().RemoveMenu( openRecentMenu ); + Kiface().GetFileHistory().RemoveMenu( openRecentMenu ); openRecentMenu = new wxMenu(); - wxGetApp().GetFileHistory().UseMenu( openRecentMenu ); - wxGetApp().GetFileHistory().AddFilesToMenu( openRecentMenu ); + + Kiface().GetFileHistory().UseMenu( openRecentMenu ); + Kiface().GetFileHistory().AddFilesToMenu( openRecentMenu ); + AddMenuItem( fileMenu, openRecentMenu, wxID_ANY, _( "Open &Recent" ), _( "Open a recent opened schematic project" ), @@ -427,7 +430,7 @@ void SCH_EDIT_FRAME::ReCreateMenuBar() // Language submenu - wxGetApp().AddMenuLanguageList( preferencesMenu ); + Pgm().AddMenuLanguageList( preferencesMenu ); // Hotkey submenu AddHotkeyConfigMenu( preferencesMenu ); diff --git a/eeschema/menubar_libedit.cpp b/eeschema/menubar_libedit.cpp index eba56c6188..1671b0769e 100644 --- a/eeschema/menubar_libedit.cpp +++ b/eeschema/menubar_libedit.cpp @@ -28,7 +28,7 @@ * @brief (Re)Create the main menubar for the component editor frame (LibEdit) */ #include -#include +#include #include #include @@ -239,7 +239,7 @@ void LIB_EDIT_FRAME::ReCreateMenuBar() KiBitmap( palette_xpm ) ); // Language submenu - wxGetApp().AddMenuLanguageList( preferencesMenu ); + Pgm().AddMenuLanguageList( preferencesMenu ); // Hotkey submenu AddHotkeyConfigMenu( preferencesMenu ); diff --git a/eeschema/netform.cpp b/eeschema/netform.cpp index a0665d675f..3a97b08849 100644 --- a/eeschema/netform.cpp +++ b/eeschema/netform.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include @@ -644,8 +644,7 @@ XNODE* NETLIST_EXPORT_TOOL::makeGenericDesignHeader() xdesign->AddChild( node( wxT( "date" ), DateAndTime() ) ); // which Eeschema tool - xdesign->AddChild( node( wxT( "tool" ), wxGetApp().GetAppName() + wxChar(' ') + - GetBuildVersion() ) ); + xdesign->AddChild( node( wxT( "tool" ), wxT( "Eeschema " ) + GetBuildVersion() ) ); /* @todo might do a list of schematic pages @@ -1727,13 +1726,13 @@ bool NETLIST_EXPORT_TOOL::WriteNetListCADSTAR( FILE* f ) wxString footprint; SCH_SHEET_PATH* sheet; EDA_ITEM* DrawList; - SCH_COMPONENT* Component; - wxString Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion(); + SCH_COMPONENT* component; + wxString title = wxT( "Eeschema " ) + GetBuildVersion(); ret |= fprintf( f, "%sHEA\n", TO_UTF8( StartLine ) ); ret |= fprintf( f, "%sTIM %s\n", TO_UTF8( StartLine ), TO_UTF8( DateAndTime() ) ); ret |= fprintf( f, "%sAPP ", TO_UTF8( StartLine ) ); - ret |= fprintf( f, "\"%s\"\n", TO_UTF8( Title ) ); + ret |= fprintf( f, "\"%s\"\n", TO_UTF8( title ) ); ret |= fprintf( f, "\n" ); // Prepare list of nets generation @@ -1749,27 +1748,27 @@ bool NETLIST_EXPORT_TOOL::WriteNetListCADSTAR( FILE* f ) { for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Next() ) { - DrawList = Component = findNextComponentAndCreatePinList( DrawList, sheet ); + DrawList = component = findNextComponentAndCreatePinList( DrawList, sheet ); - if( Component == NULL ) + if( component == NULL ) break; /* doing nothing with footprint - if( !Component->GetField( FOOTPRINT )->IsVoid() ) + if( !component->GetField( FOOTPRINT )->IsVoid() ) { - footprint = Component->GetField( FOOTPRINT )->m_Text; + footprint = component->GetField( FOOTPRINT )->m_Text; footprint.Replace( wxT( " " ), wxT( "_" ) ); } else footprint = wxT( "$noname" ); */ - msg = Component->GetRef( sheet ); + msg = component->GetRef( sheet ); ret |= fprintf( f, "%s ", TO_UTF8( StartCmpDesc ) ); ret |= fprintf( f, "%s", TO_UTF8( msg ) ); - msg = Component->GetField( VALUE )->GetText(); + msg = component->GetField( VALUE )->GetText(); msg.Replace( wxT( " " ), wxT( "_" ) ); ret |= fprintf( f, " \"%s\"", TO_UTF8( msg ) ); ret |= fprintf( f, "\n" ); @@ -1836,18 +1835,18 @@ bool NETLIST_EXPORT_TOOL::writeListOfNetsCADSTAR( FILE* f ) switch( print_ter ) { case 0: - { - char buf[5]; - wxString str_pinnum; - strncpy( buf, (char*) &nitem->m_PinNum, 4 ); - buf[4] = 0; - str_pinnum = FROM_UTF8( buf ); - InitNetDescLine.Printf( wxT( "\n%s %s %.4s %s" ), - GetChars( InitNetDesc ), - GetChars( refstr ), - GetChars( str_pinnum ), - GetChars( netcodeName ) ); - } + { + char buf[5]; + wxString str_pinnum; + strncpy( buf, (char*) &nitem->m_PinNum, 4 ); + buf[4] = 0; + str_pinnum = FROM_UTF8( buf ); + InitNetDescLine.Printf( wxT( "\n%s %s %.4s %s" ), + GetChars( InitNetDesc ), + GetChars( refstr ), + GetChars( str_pinnum ), + GetChars( netcodeName ) ); + } print_ter++; break; diff --git a/eeschema/operations_on_items_lists.cpp b/eeschema/operations_on_items_lists.cpp index 2b417e0020..7fa79f879e 100644 --- a/eeschema/operations_on_items_lists.cpp +++ b/eeschema/operations_on_items_lists.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include diff --git a/eeschema/pinedit.cpp b/eeschema/pinedit.cpp index eee9cf5dca..202a7d691f 100644 --- a/eeschema/pinedit.cpp +++ b/eeschema/pinedit.cpp @@ -86,13 +86,13 @@ void LIB_EDIT_FRAME::OnEditPin( wxCommandEvent& event ) LIB_PIN::GetElectricalTypeSymbols() ); dlg.SetElectricalType( pin->GetType() ); dlg.SetName( pin->GetName() ); - dlg.SetNameTextSize( ReturnStringFromValue( g_UserUnit, pin->GetNameTextSize() ) ); + dlg.SetNameTextSize( StringFromValue( g_UserUnit, pin->GetNameTextSize() ) ); dlg.SetNameTextSizeUnits( units ); dlg.SetPadName( pin->GetNumberString() ); - dlg.SetPadNameTextSize( ReturnStringFromValue( g_UserUnit, pin->GetNumberTextSize() ) ); + dlg.SetPadNameTextSize( StringFromValue( g_UserUnit, pin->GetNumberTextSize() ) ); dlg.SetPadNameTextSizeUnits( units ); - dlg.SetLength( ReturnStringFromValue( g_UserUnit, pin->GetLength() ) ); + dlg.SetLength( StringFromValue( g_UserUnit, pin->GetLength() ) ); dlg.SetLengthUnits( units ); dlg.SetAddToAllParts( pin->GetUnit() == 0 ); dlg.SetAddToAllBodyStyles( pin->GetConvert() == 0 ); @@ -120,10 +120,10 @@ void LIB_EDIT_FRAME::OnEditPin( wxCommandEvent& event ) } // Save the pin properties to use for the next new pin. - LastPinNameSize = ReturnValueFromString( g_UserUnit, dlg.GetNameTextSize() ); - LastPinNumSize = ReturnValueFromString( g_UserUnit, dlg.GetPadNameTextSize() ); + LastPinNameSize = ValueFromString( g_UserUnit, dlg.GetNameTextSize() ); + LastPinNumSize = ValueFromString( g_UserUnit, dlg.GetPadNameTextSize() ); LastPinOrient = LIB_PIN::GetOrientationCode( dlg.GetOrientation() ); - LastPinLength = ReturnValueFromString( g_UserUnit, dlg.GetLength() ); + LastPinLength = ValueFromString( g_UserUnit, dlg.GetLength() ); LastPinShape = LIB_PIN::GetStyleCode( dlg.GetStyle() ); LastPinType = dlg.GetElectricalType(); LastPinCommonConvert = dlg.GetAddToAllBodyStyles(); @@ -546,7 +546,7 @@ void LIB_EDIT_FRAME::RepeatPinItem( wxDC* DC, LIB_PIN* SourcePin ) IncrementLabelMember( nextName ); Pin->SetName( nextName ); - Pin->ReturnPinStringNum( msg ); + Pin->PinStringNum( msg ); IncrementLabelMember( msg ); Pin->SetPinNumFromString( msg ); @@ -644,11 +644,11 @@ void LIB_EDIT_FRAME::OnCheckComponent( wxCommandEvent& event ) continue; dup_error++; - Pin->ReturnPinStringNum( stringPinNum ); + Pin->PinStringNum( stringPinNum ); /* TODO I dare someone to find a way to make happy translators on this thing! Lorenzo */ - curr_pin->ReturnPinStringNum( stringCurrPinNum ); + curr_pin->PinStringNum( stringCurrPinNum ); msg.Printf( _( "Duplicate pin %s \"%s\" at location (%.3f, \ %.3f) conflicts with pin %s \"%s\" at location (%.3f, %.3f)" ), GetChars( stringCurrPinNum ), @@ -692,7 +692,8 @@ void LIB_EDIT_FRAME::OnCheckComponent( wxCommandEvent& event ) // A pin is found here off grid offgrid_error++; wxString stringPinNum; - Pin->ReturnPinStringNum( stringPinNum ); + Pin->PinStringNum( stringPinNum ); + msg.Printf( _( "Off grid pin %s \"%s\" at location (%.3f, %.3f)" ), GetChars( stringPinNum ), GetChars( Pin->GetName() ), diff --git a/eeschema/plot_schematic_HPGL.cpp b/eeschema/plot_schematic_HPGL.cpp index b520cced70..f1a4dff409 100644 --- a/eeschema/plot_schematic_HPGL.cpp +++ b/eeschema/plot_schematic_HPGL.cpp @@ -97,7 +97,7 @@ static const wxChar* plot_sheet_list( int aSize ) void DIALOG_PLOT_SCHEMATIC::SetHPGLPenWidth() { - m_HPGLPenSize = ReturnValueFromTextCtrl( *m_penHPGLWidthCtrl ); + m_HPGLPenSize = ValueFromTextCtrl( *m_penHPGLWidthCtrl ); if( m_HPGLPenSize > Millimeter2iu( 2 ) ) m_HPGLPenSize = Millimeter2iu( 2 ); diff --git a/eeschema/plot_schematic_SVG.cpp b/eeschema/plot_schematic_SVG.cpp index de1ffb0466..050bad1105 100644 --- a/eeschema/plot_schematic_SVG.cpp +++ b/eeschema/plot_schematic_SVG.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include @@ -80,12 +80,12 @@ void DIALOG_PLOT_SCHEMATIC::createSVGFile( bool aPrintAll, bool aPrintFrameRef ) if( !success ) { - msg.Printf( _( "Error creating file <%s>\n" ), + msg.Printf( _( "Error creating file <%s>\n" ), GetChars( fn.GetFullPath() ) ); } else { - msg.Printf( _( "File <%s> OK\n" ), + msg.Printf( _( "File <%s> OK\n" ), GetChars( fn.GetFullPath() ) ); } diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index 891a1c1f29..686efce6de 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -27,24 +27,25 @@ #include #include -SCH_BASE_FRAME::SCH_BASE_FRAME( wxWindow* aParent, - ID_DRAWFRAME_TYPE aWindowType, - const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle, const wxString & aFrameName ) : - EDA_DRAW_FRAME( aParent, aWindowType, aTitle, aPosition, aSize, aStyle, aFrameName ) + +SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, + ID_DRAWFRAME_TYPE aWindowType, const wxString& aTitle, + const wxPoint& aPosition, const wxSize& aSize, long aStyle, + const wxString& aFrameName ) : + EDA_DRAW_FRAME( aKiway, aParent, aWindowType, aTitle, aPosition, + aSize, aStyle, aFrameName ) { } void SCH_BASE_FRAME::OnOpenLibraryViewer( wxCommandEvent& event ) { - LIB_VIEW_FRAME * viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer();; + LIB_VIEW_FRAME* viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer( this ); if( viewlibFrame ) viewlibFrame->Show( true ); else - new LIB_VIEW_FRAME( this ); + new LIB_VIEW_FRAME( &Kiway(), this ); } diff --git a/eeschema/sch_component.cpp b/eeschema/sch_component.cpp index d83c892591..e25bd51b4e 100644 --- a/eeschema/sch_component.cpp +++ b/eeschema/sch_component.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp index af21d0add0..8a7d814b3b 100644 --- a/eeschema/sch_field.cpp +++ b/eeschema/sch_field.cpp @@ -104,7 +104,7 @@ const wxString SCH_FIELD::GetFullyQualifiedText() const wxT( "No component associated with field" ) + text ); if( component->GetPartCount() > 1 ) - text << LIB_COMPONENT::ReturnSubReference( component->GetUnit() ); + text << LIB_COMPONENT::SubReference( component->GetUnit() ); } return text; @@ -409,7 +409,7 @@ bool SCH_FIELD::Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint text = component->GetRef( (SCH_SHEET_PATH*) aAuxData ); if( component->GetPartCount() > 1 ) - text << LIB_COMPONENT::ReturnSubReference( component->GetUnit() ); + text << LIB_COMPONENT::SubReference( component->GetUnit() ); } match = SCH_ITEM::Matches( text, aSearchData ); @@ -447,7 +447,7 @@ bool SCH_FIELD::Replace( wxFindReplaceData& aSearchData, void* aAuxData ) text = component->GetRef( (SCH_SHEET_PATH*) aAuxData ); // if( component->GetPartCount() > 1 ) - // text << LIB_COMPONENT::ReturnSubReference( component->GetUnit() ); + // text << LIB_COMPONENT::SubReference( component->GetUnit() ); isReplaced = EDA_ITEM::Replace( aSearchData, text ); @@ -588,7 +588,7 @@ void SCH_FIELD::Plot( PLOTTER* aPlotter ) else /* We plot the reference, for a multiple parts per package */ { /* Adding A, B ... to the reference */ - wxString Text = m_Text + LIB_COMPONENT::ReturnSubReference( parent->GetUnit() ); + wxString Text = m_Text + LIB_COMPONENT::SubReference( parent->GetUnit() ); aPlotter->Text( textpos, color, Text, orient, m_Size, hjustify, vjustify, thickness, m_Italic, m_Bold ); diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index 52d512a78a..86a8ed9727 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index dd54465b99..95c268dcaa 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -636,9 +636,9 @@ const EDA_RECT SCH_SHEET::GetBoundingBox() const // Determine length of texts wxString text = wxT( "Sheet: " ) + m_name; - int textlen = ReturnGraphicTextWidth( text, m_sheetNameSize, false, lineWidth ); + int textlen = GraphicTextWidth( text, m_sheetNameSize, false, lineWidth ); text = wxT( "File: " ) + m_fileName; - int textlen2 = ReturnGraphicTextWidth( text, m_fileNameSize, false, lineWidth ); + int textlen2 = GraphicTextWidth( text, m_fileNameSize, false, lineWidth ); // Calculate bounding box X size: textlen = std::max( textlen, textlen2 ); diff --git a/eeschema/sch_text.cpp b/eeschema/sch_text.cpp index 90f932cf2d..7893abfa5f 100644 --- a/eeschema/sch_text.cpp +++ b/eeschema/sch_text.cpp @@ -795,7 +795,7 @@ void SCH_TEXT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList ) } // Display text size (X or Y value, with are the same value in Eeschema) - msg = ReturnStringFromValue( g_UserUnit, m_Size.x, true ); + msg = StringFromValue( g_UserUnit, m_Size.x, true ); aList.push_back( MSG_PANEL_ITEM( _( "Size" ), msg, RED ) ); } diff --git a/eeschema/schedit.cpp b/eeschema/schedit.cpp index 8f3d425bb1..262d20376a 100644 --- a/eeschema/schedit.cpp +++ b/eeschema/schedit.cpp @@ -28,8 +28,9 @@ */ #include +#include #include -#include +#include #include #include #include @@ -294,8 +295,9 @@ void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) if( LibEntry && LibEntry->GetDocFileName() != wxEmptyString ) { - GetAssociatedDocument( this, LibEntry->GetDocFileName(), - &wxGetApp().GetLibraryPathList() ); + SEARCH_STACK* lib_search = &Prj().SchSearchS(); + + GetAssociatedDocument( this, LibEntry->GetDocFileName(), lib_search ); } } break; diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp index f69760a292..fd948f4d91 100644 --- a/eeschema/schframe.cpp +++ b/eeschema/schframe.cpp @@ -27,7 +27,9 @@ */ #include -#include +#include +#include +#include #include #include #include @@ -173,11 +175,9 @@ END_EVENT_TABLE() #define SCH_EDIT_FRAME_NAME wxT( "SchematicFrame" ) -SCH_EDIT_FRAME::SCH_EDIT_FRAME( wxWindow* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle ) : - SCH_BASE_FRAME( aParent, SCHEMATIC_FRAME_TYPE, aTitle, aPosition, aSize, - aStyle, SCH_EDIT_FRAME_NAME ), +SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ): + SCH_BASE_FRAME( aKiway, aParent, SCHEMATIC_FRAME_TYPE, wxT( "Eeschema" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, SCH_EDIT_FRAME_NAME ), m_item_to_repeat( 0 ) { m_FrameName = SCH_EDIT_FRAME_NAME; @@ -211,8 +211,7 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( wxWindow* aParent, const wxString& aTitle, // Initialize grid id to the default value (50 mils): m_LastGridSizeId = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000; - /* Get config */ - LoadSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); @@ -440,7 +439,7 @@ void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent ) if( libeditFrame && !libeditFrame->Close() ) // Can close component editor? return; - LIB_VIEW_FRAME * viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer();; + LIB_VIEW_FRAME* viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer( this ); if( viewlibFrame && !viewlibFrame->Close() ) // Can close component viewer? return; @@ -719,12 +718,10 @@ void SCH_EDIT_FRAME::OnFindDialogClose( wxFindDialogEvent& event ) void SCH_EDIT_FRAME::OnLoadFile( wxCommandEvent& event ) { - wxString fn; + wxString fn = GetFileFromHistory( event.GetId(), _( "Schematic" ) ); - fn = GetFileFromHistory( event.GetId(), _( "Schematic" ) ); - - if( fn != wxEmptyString ) - LoadOneEEProject( fn, false ); + if( fn.size() ) + OpenProjectFiles( std::vector( 1, fn ) ); } @@ -737,13 +734,29 @@ void SCH_EDIT_FRAME::OnLoadCmpToFootprintLinkFile( wxCommandEvent& event ) void SCH_EDIT_FRAME::OnNewProject( wxCommandEvent& event ) { - LoadOneEEProject( wxEmptyString, true ); + wxFileDialog dlg( this, _( "Open Schematic" ), wxGetCwd(), + wxEmptyString, SchematicFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() != wxID_CANCEL ) + { + OpenProjectFiles( std::vector( 1, dlg.GetPath() ) ); + } } void SCH_EDIT_FRAME::OnLoadProject( wxCommandEvent& event ) { - LoadOneEEProject( wxEmptyString, false ); + // LoadOneEEProject( wxEmptyString, false ); + + wxFileDialog dlg( this, _( "Open Schematic" ), wxGetCwd(), + wxEmptyString, SchematicFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + + if( dlg.ShowModal() != wxID_CANCEL ) + { + OpenProjectFiles( std::vector( 1, dlg.GetPath() ) ); + } } @@ -798,7 +811,7 @@ void SCH_EDIT_FRAME::OnOpenLibraryEditor( wxCommandEvent& event ) component = (SCH_COMPONENT*) item; } - LIB_EDIT_FRAME * libeditFrame = LIB_EDIT_FRAME::GetActiveLibraryEditor();; + LIB_EDIT_FRAME* libeditFrame = LIB_EDIT_FRAME::GetActiveLibraryEditor();; if( libeditFrame ) { if( libeditFrame->IsIconized() ) @@ -808,10 +821,8 @@ void SCH_EDIT_FRAME::OnOpenLibraryEditor( wxCommandEvent& event ) } else { - libeditFrame = new LIB_EDIT_FRAME( this, - wxT( "Library Editor" ), - wxPoint( -1, -1 ), - wxSize( 600, 400 ) ); + wxWindow* w = Kiface().CreateWindow( this, LIBEDITOR_FRAME_TYPE, &Kiway() ); + libeditFrame = dynamic_cast( w ); } if( component ) @@ -851,16 +862,19 @@ void SCH_EDIT_FRAME::OnPrint( wxCommandEvent& event ) fn = g_RootSheet->GetScreen()->GetFileName(); - wxString default_name = NAMELESS_PROJECT; - default_name += wxT( ".sch" ); + wxString default_name = NAMELESS_PROJECT wxT( ".sch" ); if( fn.GetFullName() != default_name ) { fn.SetExt( ProjectFileExtension ); - wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParametersList() ); + + // was: wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParametersList() ); + Prj().ConfigSave( Kiface().KifaceSearch(), + fn.GetFullPath(), GROUP, GetProjectFileParametersList() ); } } + void SCH_EDIT_FRAME::PrintPage( wxDC* aDC, LAYER_MSK aPrintMask, bool aPrintMirrorMode, void* aData ) { diff --git a/eeschema/selpart.cpp b/eeschema/selpart.cpp index 6368deedc8..22fa518c9b 100644 --- a/eeschema/selpart.cpp +++ b/eeschema/selpart.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/eeschema/sheet.cpp b/eeschema/sheet.cpp index ab9730b3ea..3dbb135fc1 100644 --- a/eeschema/sheet.cpp +++ b/eeschema/sheet.cpp @@ -50,10 +50,10 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, wxDC* aDC ) wxString units = GetUnitsLabel( g_UserUnit ); dlg.SetFileName( aSheet->GetFileName() ); - dlg.SetFileNameTextSize( ReturnStringFromValue( g_UserUnit, aSheet->GetFileNameSize() ) ); + dlg.SetFileNameTextSize( StringFromValue( g_UserUnit, aSheet->GetFileNameSize() ) ); dlg.SetFileNameTextSizeUnits( units ); dlg.SetSheetName( aSheet->GetName() ); - dlg.SetSheetNameTextSize( ReturnStringFromValue( g_UserUnit, aSheet->GetSheetNameSize() ) ); + dlg.SetSheetNameTextSize( StringFromValue( g_UserUnit, aSheet->GetSheetNameSize() ) ); dlg.SetSheetNameTextSizeUnits( units ); dlg.SetSheetTimeStamp( wxString::Format( wxT("%8.8lX"), (unsigned long) aSheet->GetTimeStamp() ) ); @@ -213,9 +213,9 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, wxDC* aDC ) else if( loadFromFile ) aSheet->Load( this ); - aSheet->SetFileNameSize( ReturnValueFromString( g_UserUnit, dlg.GetFileNameTextSize() ) ); + aSheet->SetFileNameSize( ValueFromString( g_UserUnit, dlg.GetFileNameTextSize() ) ); aSheet->SetName( dlg.GetSheetName() ); - aSheet->SetSheetNameSize( ReturnValueFromString( g_UserUnit, dlg.GetSheetNameTextSize() ) ); + aSheet->SetSheetNameSize( ValueFromString( g_UserUnit, dlg.GetSheetNameTextSize() ) ); if( aSheet->GetName().IsEmpty() ) aSheet->SetName( wxString::Format( wxT( "Sheet%8.8lX" ), aSheet->GetTimeStamp() ) ); diff --git a/eeschema/sheetlab.cpp b/eeschema/sheetlab.cpp index b644e76849..f9043a226d 100644 --- a/eeschema/sheetlab.cpp +++ b/eeschema/sheetlab.cpp @@ -56,9 +56,9 @@ int SCH_EDIT_FRAME::EditSheetPin( SCH_SHEET_PIN* aSheetPin, wxDC* aDC ) DIALOG_SCH_EDIT_SHEET_PIN dlg( this ); dlg.SetLabelName( aSheetPin->GetText() ); - dlg.SetTextHeight( ReturnStringFromValue( g_UserUnit, aSheetPin->GetSize().y ) ); + dlg.SetTextHeight( StringFromValue( g_UserUnit, aSheetPin->GetSize().y ) ); dlg.SetTextHeightUnits( GetUnitsLabel( g_UserUnit ) ); - dlg.SetTextWidth( ReturnStringFromValue( g_UserUnit, aSheetPin->GetSize().x ) ); + dlg.SetTextWidth( StringFromValue( g_UserUnit, aSheetPin->GetSize().x ) ); dlg.SetTextWidthUnits( GetUnitsLabel( g_UserUnit ) ); dlg.SetConnectionType( aSheetPin->GetShape() ); @@ -84,8 +84,8 @@ int SCH_EDIT_FRAME::EditSheetPin( SCH_SHEET_PIN* aSheetPin, wxDC* aDC ) } aSheetPin->SetText( dlg.GetLabelName() ); - aSheetPin->SetSize( wxSize( ReturnValueFromString( g_UserUnit, dlg.GetTextHeight() ), - ReturnValueFromString( g_UserUnit, dlg.GetTextWidth() ) ) ); + aSheetPin->SetSize( wxSize( ValueFromString( g_UserUnit, dlg.GetTextHeight() ), + ValueFromString( g_UserUnit, dlg.GetTextWidth() ) ) ); aSheetPin->SetShape( dlg.GetConnectionType() ); if( aDC ) diff --git a/eeschema/symbdraw.cpp b/eeschema/symbdraw.cpp index 619db5b46b..79d80f3491 100644 --- a/eeschema/symbdraw.cpp +++ b/eeschema/symbdraw.cpp @@ -69,7 +69,7 @@ void LIB_EDIT_FRAME::EditGraphicSymbol( wxDC* DC, LIB_ITEM* DrawItem ) dialog.SetWidthUnits( ReturnUnitSymbol( g_UserUnit ) ); - wxString val = ReturnStringFromValue( g_UserUnit, DrawItem->GetWidth() ); + wxString val = StringFromValue( g_UserUnit, DrawItem->GetWidth() ); dialog.SetWidth( val ); dialog.SetApplyToAllUnits( DrawItem->GetUnit() == 0 ); dialog.EnableApplyToAllUnits( component && component->GetPartCount() > 1 ); @@ -83,7 +83,7 @@ void LIB_EDIT_FRAME::EditGraphicSymbol( wxDC* DC, LIB_ITEM* DrawItem ) // Init default values (used to create a new draw item) val = dialog.GetWidth(); - m_drawLineWidth = ReturnValueFromString( g_UserUnit, val ); + m_drawLineWidth = ValueFromString( g_UserUnit, val ); m_drawSpecificConvert = !dialog.GetApplyToAllConversions(); m_drawSpecificUnit = !dialog.GetApplyToAllUnits(); diff --git a/eeschema/symbedit.cpp b/eeschema/symbedit.cpp index 95309e6757..a5dc98738d 100644 --- a/eeschema/symbedit.cpp +++ b/eeschema/symbedit.cpp @@ -29,7 +29,8 @@ */ #include -#include +#include +#include #include #include #include @@ -54,9 +55,12 @@ void LIB_EDIT_FRAME::LoadOneSymbol() if( m_component == NULL || ( m_drawItem && m_drawItem->GetFlags() ) ) return; + PROJECT& prj = Prj(); + SEARCH_STACK& search = prj.SchSearchS(); + m_canvas->SetIgnoreMouseEvents( true ); - wxString default_path = wxGetApp().ReturnLastVisitedLibraryPath(); + wxString default_path = prj.RPath(PROJECT::SCH_LIB).LastVisitedPath( search ); wxFileDialog dlg( this, _( "Import Symbol Drawings" ), default_path, wxEmptyString, SchematicSymbolFileWildcard, @@ -70,13 +74,14 @@ void LIB_EDIT_FRAME::LoadOneSymbol() m_canvas->SetIgnoreMouseEvents( false ); wxFileName fn = dlg.GetPath(); - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + + prj.RPath(PROJECT::SCH_LIB).SaveLastVisitedPath( fn.GetPath() ); Lib = new CMP_LIBRARY( LIBRARY_TYPE_SYMBOL, fn ); if( !Lib->Load( err ) ) { - msg.Printf( _( "Error <%s> occurred loading symbol library <%s>." ), + msg.Printf( _( "Error '%s' occurred loading symbol library '%s'." ), GetChars( err ), GetChars( fn.GetName() ) ); DisplayError( this, msg ); delete Lib; @@ -85,7 +90,7 @@ void LIB_EDIT_FRAME::LoadOneSymbol() if( Lib->IsEmpty() ) { - msg.Printf( _( "No components found in symbol library <%s>." ), + msg.Printf( _( "No components found in symbol library '%s'." ), GetChars( fn.GetName() ) ); delete Lib; return; @@ -93,7 +98,7 @@ void LIB_EDIT_FRAME::LoadOneSymbol() if( Lib->GetCount() > 1 ) { - msg.Printf( _( "More than one part in symbol file <%s>." ), + msg.Printf( _( "More than one part in symbol file '%s'." ), GetChars( fn.GetName() ) ); wxMessageBox( msg, _( "Warning" ), wxOK | wxICON_EXCLAMATION, this ); } @@ -131,12 +136,14 @@ void LIB_EDIT_FRAME::LoadOneSymbol() void LIB_EDIT_FRAME::SaveOneSymbol() { - wxString msg; + wxString msg; + PROJECT& prj = Prj(); + SEARCH_STACK& search = prj.SchSearchS(); if( m_component->GetDrawItemList().empty() ) return; - wxString default_path = wxGetApp().ReturnLastVisitedLibraryPath(); + wxString default_path = prj.RPath(PROJECT::SCH_LIB).LastVisitedPath( search ); wxFileDialog dlg( this, _( "Export Symbol Drawings" ), default_path, m_component->GetName(), SchematicSymbolFileWildcard, @@ -152,9 +159,9 @@ void LIB_EDIT_FRAME::SaveOneSymbol() if( fn.GetExt().IsEmpty() ) fn.SetExt( SchematicSymbolFileExtension ); - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + prj.RPath(PROJECT::SCH_LIB).SaveLastVisitedPath( fn.GetPath() ); - msg.Printf( _( "Saving symbol in <%s>" ), GetChars( fn.GetPath() ) ); + msg.Printf( _( "Saving symbol in '%s'" ), GetChars( fn.GetPath() ) ); SetStatusText( msg ); wxString line; @@ -220,7 +227,7 @@ void LIB_EDIT_FRAME::SaveOneSymbol() } catch( IO_ERROR ioe ) { - msg.Printf( _( "An error occurred attempting to save symbol file <%s>" ), + msg.Printf( _( "An error occurred attempting to save symbol file '%s'" ), GetChars( fn.GetFullPath() ) ); DisplayError( this, msg ); } diff --git a/eeschema/viewlib_frame.cpp b/eeschema/viewlib_frame.cpp index c1b421e76e..76de412c02 100644 --- a/eeschema/viewlib_frame.cpp +++ b/eeschema/viewlib_frame.cpp @@ -28,7 +28,8 @@ */ #include -#include +#include +#include #include #include #include @@ -94,10 +95,10 @@ static wxAcceleratorEntry accels[] = #define ACCEL_TABLE_CNT ( sizeof( accels ) / sizeof( wxAcceleratorEntry ) ) #define LIB_VIEW_FRAME_NAME wxT( "ViewlibFrame" ) -LIB_VIEW_FRAME::LIB_VIEW_FRAME( SCH_BASE_FRAME* aParent, CMP_LIBRARY* aLibrary, - wxSemaphore* aSemaphore, long aStyle ) : - SCH_BASE_FRAME( aParent, VIEWER_FRAME_TYPE, _( "Library Browser" ), - wxDefaultPosition, wxDefaultSize, aStyle, GetLibViewerFrameName() ) +LIB_VIEW_FRAME::LIB_VIEW_FRAME( KIWAY* aKiway, SCH_BASE_FRAME* aParent, + CMP_LIBRARY* aLibrary, wxSemaphore* aSemaphore, long aStyle ) : + SCH_BASE_FRAME( aKiway, aParent, VIEWER_FRAME_TYPE, _( "Library Browser" ), + wxDefaultPosition, wxDefaultSize, aStyle, GetLibViewerFrameName() ) { wxAcceleratorTable table( ACCEL_TABLE_CNT, accels ); @@ -122,7 +123,7 @@ LIB_VIEW_FRAME::LIB_VIEW_FRAME( SCH_BASE_FRAME* aParent, CMP_LIBRARY* aLibrary, SetScreen( new SCH_SCREEN() ); GetScreen()->m_Center = true; // Axis origin centered on screen. - LoadSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); @@ -242,9 +243,9 @@ const wxChar* LIB_VIEW_FRAME::GetLibViewerFrameName() } -LIB_VIEW_FRAME* LIB_VIEW_FRAME::GetActiveLibraryViewer() +LIB_VIEW_FRAME* LIB_VIEW_FRAME::GetActiveLibraryViewer( const wxWindow* aParent ) { - return (LIB_VIEW_FRAME*) wxWindow::FindWindowByName(GetLibViewerFrameName()); + return (LIB_VIEW_FRAME*) wxWindow::FindWindowByName( GetLibViewerFrameName(), aParent ); } @@ -467,17 +468,14 @@ void LIB_VIEW_FRAME::ExportToSchematicLibraryPart( wxCommandEvent& event ) #define CMPLIST_WIDTH_KEY wxT( "ViewCmplistWidth" ) -void LIB_VIEW_FRAME::LoadSettings( ) +void LIB_VIEW_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* cfg ; + EDA_DRAW_FRAME::LoadSettings( aCfg ); - EDA_DRAW_FRAME::LoadSettings(); + wxConfigPathChanger cpc( aCfg, m_configPath ); - wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - cfg = wxGetApp().GetSettings(); - - cfg->Read( LIBLIST_WIDTH_KEY, &m_libListWidth, 100 ); - cfg->Read( CMPLIST_WIDTH_KEY, &m_cmpListWidth, 100 ); + aCfg->Read( LIBLIST_WIDTH_KEY, &m_libListWidth, 100 ); + aCfg->Read( CMPLIST_WIDTH_KEY, &m_cmpListWidth, 100 ); // Set parameters to a reasonable value. if ( m_libListWidth > m_FrameSize.x/2 ) @@ -488,23 +486,20 @@ void LIB_VIEW_FRAME::LoadSettings( ) } -void LIB_VIEW_FRAME::SaveSettings() +void LIB_VIEW_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* cfg; + EDA_DRAW_FRAME::SaveSettings( aCfg ); - EDA_DRAW_FRAME::SaveSettings(); + wxConfigPathChanger cpc( aCfg, m_configPath ); - wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - cfg = wxGetApp().GetSettings(); - - if( m_libListWidth && m_libList) + if( m_libListWidth && m_libList ) { m_libListWidth = m_libList->GetSize().x; - cfg->Write( LIBLIST_WIDTH_KEY, m_libListWidth ); + aCfg->Write( LIBLIST_WIDTH_KEY, m_libListWidth ); } m_cmpListWidth = m_cmpList->GetSize().x; - cfg->Write( CMPLIST_WIDTH_KEY, m_cmpListWidth ); + aCfg->Write( CMPLIST_WIDTH_KEY, m_cmpListWidth ); } diff --git a/eeschema/viewlib_frame.h b/eeschema/viewlib_frame.h index 7449dbfd1a..4b5e6827a3 100644 --- a/eeschema/viewlib_frame.h +++ b/eeschema/viewlib_frame.h @@ -71,9 +71,9 @@ protected: static int m_convert; public: - LIB_VIEW_FRAME( SCH_BASE_FRAME* aParent, CMP_LIBRARY* aLibrary = NULL, - wxSemaphore* aSemaphore = NULL, - long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); + LIB_VIEW_FRAME( KIWAY* aKiway, SCH_BASE_FRAME* aParent, + CMP_LIBRARY* aLibrary = NULL, wxSemaphore* aSemaphore = NULL, + long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); ~LIB_VIEW_FRAME(); @@ -89,7 +89,7 @@ public: * @return a reference to the current opened Library viewer * or NULL if no Library viewer currently opened */ - static LIB_VIEW_FRAME* GetActiveLibraryViewer(); + static LIB_VIEW_FRAME* GetActiveLibraryViewer( const wxWindow* aParent ); void OnSize( wxSizeEvent& event ); @@ -116,23 +116,8 @@ public: void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); - /** - * Function LoadSettings - * loads the library viewer frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get loaded. - */ - void LoadSettings(); - - /** - * Function SaveSettings - * save library viewer frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get saved. - */ - void SaveSettings(); + void LoadSettings( wxConfigBase* aCfg ); + void SaveSettings( wxConfigBase* aCfg ); wxString& GetEntryName( void ) const { return m_entryName; } wxString& GetSelectedComponent( void ) const { return m_exportToEeschemaCmpName; } diff --git a/eeschema/viewlibs.cpp b/eeschema/viewlibs.cpp index 289b37a1d9..15e76c8941 100644 --- a/eeschema/viewlibs.cpp +++ b/eeschema/viewlibs.cpp @@ -3,8 +3,9 @@ */ #include +#include #include -#include +#include #include #include #include @@ -51,8 +52,11 @@ void LIB_VIEW_FRAME::Process_Special_Functions( wxCommandEvent& event ) LibEntry = CMP_LIBRARY::FindLibraryEntry( m_entryName, m_libraryName ); if( LibEntry && ( !LibEntry->GetDocFileName().IsEmpty() ) ) - GetAssociatedDocument( this, LibEntry->GetDocFileName(), - &wxGetApp().GetLibraryPathList() ); + { + SEARCH_STACK& lib_search = Prj().SchSearchS(); + + GetAssociatedDocument( this, LibEntry->GetDocFileName(), &lib_search ); + } break; case ID_LIBVIEW_DE_MORGAN_NORMAL_BUTT: diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index c34b979deb..124a8d0c56 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -1,10 +1,8 @@ +set( MAKE_LINK_MAPS true ) + add_definitions(-DGERBVIEW) -### -# Includes -### - -include_directories(BEFORE ${INC_BEFORE}) +include_directories( BEFORE ${INC_BEFORE} ) include_directories( ../pcbnew dialogs @@ -14,11 +12,7 @@ include_directories( ) -### -# Sources -### - -set(DIALOGS_SRCS +set( DIALOGS_SRCS dialogs/gerbview_dialog_display_options_frame_base.cpp dialogs/gerbview_dialog_display_options_frame.cpp dialogs/dialog_layers_select_to_pcb_base.cpp @@ -29,7 +23,7 @@ set(DIALOGS_SRCS dialogs/dialog_show_page_borders_base.cpp ) -set(GERBVIEW_SRCS +set( GERBVIEW_SRCS block.cpp class_am_param.cpp class_aperture_macro.cpp @@ -47,7 +41,6 @@ set(GERBVIEW_SRCS excellon_read_drill_file.cpp export_to_pcbnew.cpp files.cpp - gerbview.cpp gerbview_config.cpp gerbview_frame.cpp hotkeys.cpp @@ -65,10 +58,7 @@ set(GERBVIEW_SRCS toolbars_gerber.cpp ) -### -# We need some extra sources from common and pcbnew -### -set(GERBVIEW_EXTRA_SRCS +set( GERBVIEW_EXTRA_SRCS ../common/base_screen.cpp ../common/base_units.cpp ../common/eda_text.cpp @@ -78,58 +68,115 @@ set(GERBVIEW_EXTRA_SRCS ../pcbnew/printout_controler.cpp ) -### -# Windows resource file -### -if(WIN32) - if(MINGW) - # GERBVIEW_RESOURCES variable is set by the macro. - mingw_resource_compiler(gerbview) - else(MINGW) - set(GERBVIEW_RESOURCES gerbview.rc) - endif(MINGW) -endif(WIN32) +if( MINGW ) + # GERBVIEW_RESOURCES variable is set by the macro. + mingw_resource_compiler( gerbview ) +endif() -### -# Apple resource files -### -if(APPLE) + +if( APPLE ) set(GERBVIEW_RESOURCES gerbview.icns gerbview_doc.icns) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/gerbview.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/gerbview_doc.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - set(MACOSX_BUNDLE_ICON_FILE gerbview.icns) - set(MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.gerbview) -endif(APPLE) + set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/gerbview.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/gerbview_doc.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set( MACOSX_BUNDLE_ICON_FILE gerbview.icns ) + set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.gerbview ) +endif() -### -# Create the gerbview executable -### -add_executable(gerbview WIN32 MACOSX_BUNDLE - ${GERBVIEW_SRCS} - ${DIALOGS_SRCS} - ${GERBVIEW_EXTRA_SRCS} - ${GERBVIEW_RESOURCES}) +if( USE_KIWAY_DLLS ) -### -# Set properties for APPLE on gerbview target -### -if(APPLE) - set_target_properties(gerbview PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) -endif(APPLE) + add_executable( gerbview WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ../common/pgm_base.cpp + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=GERBER_FRAME_TYPE;BUILD_KIWAY_DLL" + ) + target_link_libraries( gerbview + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. + common + bitmaps + ${wxWidgets_LIBRARIES} + ) + if( MAKE_LINK_MAPS ) + set_target_properties( gerbview PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=gerbview.map" ) + endif() -### -# Link executable target gerbview with correct libraries -### -target_link_libraries(gerbview common polygon bitmaps - ${OPENGL_LIBRARIES} - ${wxWidgets_LIBRARIES} - ${GDI_PLUS_LIBRARIES}) + # the main gerbview program, in DSO form. + add_library( gerbview_kiface MODULE + gerbview.cpp + ${GERBVIEW_SRCS} + ${DIALOGS_SRCS} + ${GERBVIEW_EXTRA_SRCS} + ${GERBVIEW_RESOURCES} + ) + set_target_properties( gerbview_kiface PROPERTIES + OUTPUT_NAME gerbview + PREFIX ${KIFACE_PREFIX} + SUFFIX ${KIFACE_SUFFIX} + ) + target_link_libraries( gerbview_kiface + common + polygon + bitmaps + ${OPENGL_LIBRARIES} + ${wxWidgets_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ) + set_source_files_properties( gerbview.cpp PROPERTIES + # The KIFACE is in gerbview.cpp, export it: + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + if( MAKE_LINK_MAPS ) + set_target_properties( gerbview_kiface PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=_gerbview.kiface.map" ) + endif() -### -# Add gerbview as install target -### -install(TARGETS gerbview + # if building gerbview, then also build gerbview_kiface if out of date. + add_dependencies( gerbview gerbview_kiface ) + + # these 2 binaries are a matched set, keep them together + install( TARGETS gerbview DESTINATION ${KICAD_BIN} - COMPONENT binary) + COMPONENT binary + ) + install( TARGETS gerbview_kiface + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +else() + + add_executable( gerbview WIN32 MACOSX_BUNDLE + gerbview.cpp + ${GERBVIEW_SRCS} + ${DIALOGS_SRCS} + ${GERBVIEW_EXTRA_SRCS} + ${GERBVIEW_RESOURCES} + ) + target_link_libraries( gerbview + common + polygon + bitmaps + ${OPENGL_LIBRARIES} + ${wxWidgets_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ) + install( TARGETS gerbview + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +endif() + +if( APPLE ) + set_target_properties( gerbview PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) +endif() + + diff --git a/gerbview/block.cpp b/gerbview/block.cpp index d973ac9a03..912113538a 100644 --- a/gerbview/block.cpp +++ b/gerbview/block.cpp @@ -46,7 +46,7 @@ static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wx bool erase ); -int GERBVIEW_FRAME::ReturnBlockCommand( int key ) +int GERBVIEW_FRAME::BlockCommand( int key ) { int cmd = 0; diff --git a/gerbview/class_DCodeSelectionbox.cpp b/gerbview/class_DCodeSelectionbox.cpp index 32969313f6..84cf9cdc54 100644 --- a/gerbview/class_DCodeSelectionbox.cpp +++ b/gerbview/class_DCodeSelectionbox.cpp @@ -3,7 +3,7 @@ /*****************************************************************/ #include -#include +#include #include #include #include diff --git a/gerbview/class_GERBER.cpp b/gerbview/class_GERBER.cpp index 9d7b7302ea..5ae04d5083 100644 --- a/gerbview/class_GERBER.cpp +++ b/gerbview/class_GERBER.cpp @@ -225,7 +225,7 @@ bool GERBER_IMAGE::HasNegativeItems() return m_hasNegativeItems == 1; } -int GERBER_IMAGE::ReturnUsedDcodeNumber() +int GERBER_IMAGE::UsedDcodeNumber() { int count = 0; diff --git a/gerbview/class_GERBER.h b/gerbview/class_GERBER.h index 19fba78fd0..632ac6487c 100644 --- a/gerbview/class_GERBER.h +++ b/gerbview/class_GERBER.h @@ -141,7 +141,7 @@ public: GERBER_IMAGE( GERBVIEW_FRAME* aParent, int layer ); virtual ~GERBER_IMAGE(); void Clear_GERBER_IMAGE(); - int ReturnUsedDcodeNumber(); + int UsedDcodeNumber(); virtual void ResetDefaultValues(); /** @@ -211,8 +211,8 @@ public: wxPoint ReadIJCoord( char*& Text ); // functions to read G commands or D commands: - int ReturnGCodeNumber( char*& Text ); - int ReturnDCodeNumber( char*& Text ); + int GCodeNumber( char*& Text ); + int DCodeNumber( char*& Text ); // functions to execute G commands or D commands: bool Execute_G_Command( char*& text, int G_command ); diff --git a/gerbview/class_excellon.h b/gerbview/class_excellon.h index 86c9f356ca..07d2800b0d 100644 --- a/gerbview/class_excellon.h +++ b/gerbview/class_excellon.h @@ -101,9 +101,9 @@ private: bool Execute_EXCELLON_G_Command( char*& text ); bool Execute_Drill_Command( char*& text ); - int ReturnTCodeNumber( char*& Text ) + int TCodeNumber( char*& Text ) { - return ReturnDCodeNumber( Text ); + return DCodeNumber( Text ); } diff --git a/gerbview/dialogs/dialog_print_using_printer.cpp b/gerbview/dialogs/dialog_print_using_printer.cpp index da67c4989b..3f9f338416 100644 --- a/gerbview/dialogs/dialog_print_using_printer.cpp +++ b/gerbview/dialogs/dialog_print_using_printer.cpp @@ -6,7 +6,8 @@ #define wxTEST_POSTSCRIPT_IN_MSW 1 #include -#include +//#include +#include #include #include #include @@ -40,7 +41,7 @@ class DIALOG_PRINT_USING_PRINTER : public DIALOG_PRINT_USING_PRINTER_BASE { private: GERBVIEW_FRAME* m_Parent; - wxConfig* m_Config; + wxConfigBase* m_Config; wxCheckBox* m_BoxSelectLayer[32]; public: @@ -100,7 +101,7 @@ DIALOG_PRINT_USING_PRINTER::DIALOG_PRINT_USING_PRINTER( GERBVIEW_FRAME* parent ) /*************************************************************************************/ { m_Parent = parent; - m_Config = wxGetApp().GetSettings(); + m_Config = Kiface().KifaceSettings(); InitValues( ); GetSizer()->SetSizeHints( this ); diff --git a/gerbview/events_called_functions.cpp b/gerbview/events_called_functions.cpp index 6efd44786d..a1021c1fab 100644 --- a/gerbview/events_called_functions.cpp +++ b/gerbview/events_called_functions.cpp @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include #include @@ -256,7 +256,7 @@ void GERBVIEW_FRAME::OnShowGerberSourceFile( wxCommandEvent& event ) if( gerber_layer ) { - wxString editorname = wxGetApp().GetEditorName(); + wxString editorname = Pgm().GetEditorName(); if( !editorname.IsEmpty() ) { wxFileName fn( gerber_layer->m_FileName ); diff --git a/gerbview/excellon_read_drill_file.cpp b/gerbview/excellon_read_drill_file.cpp index a16843f1f0..952d89c8d3 100644 --- a/gerbview/excellon_read_drill_file.cpp +++ b/gerbview/excellon_read_drill_file.cpp @@ -543,7 +543,7 @@ bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text ) bool EXCELLON_IMAGE::Select_Tool( char*& text ) { - int tool_id = ReturnTCodeNumber( text ); + int tool_id = TCodeNumber( text ); if( tool_id >= 0 ) { diff --git a/gerbview/gerbview.cpp b/gerbview/gerbview.cpp index b1537bb0d1..4e52f3937a 100644 --- a/gerbview/gerbview.cpp +++ b/gerbview/gerbview.cpp @@ -27,7 +27,8 @@ */ #include -#include +#include +#include #include #include #include @@ -62,83 +63,103 @@ const wxChar* g_GerberPageSizeList[] = { GERBER_IMAGE* g_GERBER_List[32]; -IMPLEMENT_APP( EDA_APP ) +namespace GERBV { -/* MacOSX: Needed for file association - * http://wiki.wxwidgets.org/WxMac-specific_topics - */ -void EDA_APP::MacOpenFile( const wxString& aFileName ) +static struct IFACE : public KIFACE_I { - wxFileName filename = aFileName; - GERBVIEW_FRAME * frame = ((GERBVIEW_FRAME*)GetTopWindow()); + // Of course all are virtual overloads, implementations of the KIFACE. - if( !filename.FileExists() ) - return; + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} - frame->LoadGerberFiles( aFileName ); + bool OnKifaceStart( PGM_BASE* aProgram ); + + void OnKifaceEnd(); + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) + { + switch( aClassId ) + { + case GERBER_FRAME_TYPE: + { + GERBVIEW_FRAME* frame = new GERBVIEW_FRAME( aKiway, aParent ); + + /* Is this really needed since at this point there is no open file? + frame->Zoom_Automatique( true ); // Zoom fit in frame + + if so, why is the constructor not doing it? + */ + + return frame; + } + break; + + default: + ; + } + + return NULL; + } + + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) + { + return NULL; + } + +} kiface( "gerbview", KIWAY::FACE_GERBVIEW ); + +} // namespace + +using namespace GERBV; + +static PGM_BASE* process; + +KIFACE_I& Kiface() { return kiface; } + + +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram ) +{ + process = (PGM_BASE*) aProgram; + return &kiface; } -bool EDA_APP::OnInit() +PGM_BASE& Pgm() { - wxFileName fn; - GERBVIEW_FRAME* frame = NULL; + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} - InitEDA_Appl( wxT( "GerbView" ), APP_GERBVIEW_T ); - if( m_Checker && m_Checker->IsAnotherRunning() ) - { - if( !IsOK( NULL, _( "GerbView is already running. Continue?" ) ) ) - return false; - } +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) +{ + start_common(); - // read current setup and reopen last directory if no filename to open in - // command line - bool reopenLastUsedDirectory = argc == 1; - GetSettings( reopenLastUsedDirectory ); + // Must be called before creating the main frame in order to + // display the real hotkeys in menus or tool tips + ReadHotkeyConfig( wxT("GerberFrame"), s_Gerbview_Hokeys_Descr ); g_DrawBgColor = BLACK; - /* Must be called before creating the main frame in order to - * display the real hotkeys in menus or tool tips */ - ReadHotkeyConfig( wxT("GerberFrame"), s_Gerbview_Hokeys_Descr ); - - frame = new GERBVIEW_FRAME( NULL, wxT( "GerbView" ), wxPoint( 0, 0 ), wxSize( 600, 400 ) ); - - /* Gerbview mainframe title */ - frame->SetTitle( GetTitle() + wxT( " " ) + GetBuildVersion() ); - - SetTopWindow( frame ); // Set GerbView mainframe on top - frame->Show( true ); // Show GerbView mainframe - frame->Zoom_Automatique( true ); // Zoom fit in frame - frame->GetScreen()->m_FirstRedraw = false; - - - if( argc <= 1 ) - return true; - - fn = argv[1]; - - if( fn.IsOk() ) - { - if( fn.DirExists() ) - wxSetWorkingDirectory( fn.GetPath() ); - - // Load all files specified on the command line. - LAYER_NUM jj = FIRST_LAYER; - - for( LAYER_NUM ii = LAYER_N_2; ii < argc && ii <= NB_GERBER_LAYERS; ++ii ) - { - fn = wxFileName( argv[ii] ); - - if( fn.FileExists() ) - { - frame->setActiveLayer( jj ); - ++jj; - frame->LoadGerberFiles( fn.GetFullPath() ); - } - } - } - return true; } + + +void IFACE::OnKifaceEnd() +{ + end_common(); +} diff --git a/gerbview/gerbview_config.cpp b/gerbview/gerbview_config.cpp index f3a06de0b2..db1ed29f3e 100644 --- a/gerbview/gerbview_config.cpp +++ b/gerbview/gerbview_config.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp index 62fdf0c130..1e2b073e8d 100644 --- a/gerbview/gerbview_frame.cpp +++ b/gerbview/gerbview_frame.cpp @@ -27,7 +27,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -63,11 +64,9 @@ static const wxString cfgShowBorderAndTitleBlock( wxT( "ShowBorderAndTitleBloc #define GERBVIEW_FRAME_NAME wxT( "GerberFrame" ) -GERBVIEW_FRAME::GERBVIEW_FRAME( wxWindow* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle ) : - EDA_DRAW_FRAME( aParent, GERBER_FRAME_TYPE, aTitle, aPosition, aSize, - aStyle, GERBVIEW_FRAME_NAME ) +GERBVIEW_FRAME::GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent ): + EDA_DRAW_FRAME( aKiway, aParent, GERBER_FRAME_TYPE, wxT( "GerbView" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, GERBVIEW_FRAME_NAME ) { m_colorsSettings = &g_ColorsSettings; m_gerberLayout = NULL; @@ -109,7 +108,8 @@ GERBVIEW_FRAME::GERBVIEW_FRAME( wxWindow* aParent, const wxString& aTitle, // LoadSettings() *after* creating m_LayersManager, because LoadSettings() // initialize parameters in m_LayersManager - LoadSettings(); + LoadSettings( config() ); + SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); if( m_LastGridSizeId < 0 ) @@ -171,7 +171,6 @@ GERBVIEW_FRAME::GERBVIEW_FRAME( wxWindow* aParent, const wxString& aTitle, GERBVIEW_FRAME::~GERBVIEW_FRAME() { - wxGetApp().SaveCurrentSetupValues( m_configSettings ); } @@ -181,6 +180,26 @@ void GERBVIEW_FRAME::OnCloseWindow( wxCloseEvent& Event ) } +bool GERBVIEW_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) +{ + const unsigned limit = std::min( unsigned( aFileSet.size() ), unsigned( NB_GERBER_LAYERS ) ); + + LAYER_NUM layer = FIRST_LAYER; + + for( unsigned i=0; im_Drawings; @@ -202,26 +221,22 @@ double GERBVIEW_FRAME::BestZoom() } -void GERBVIEW_FRAME::LoadSettings() +void GERBVIEW_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); + EDA_DRAW_FRAME::LoadSettings( aCfg ); - if( config == NULL ) - return; - - EDA_DRAW_FRAME::LoadSettings(); - - wxGetApp().ReadCurrentSetupValues( GetConfigurationSettings() ); + // was: wxGetApp().ReadCurrentSetupValues( GetConfigurationSettings() ); + wxConfigLoadSetups( aCfg, GetConfigurationSettings() ); PAGE_INFO pageInfo( wxT( "GERBER" ) ); - config->Read( cfgShowBorderAndTitleBlock, &m_showBorderAndTitleBlock, false ); + aCfg->Read( cfgShowBorderAndTitleBlock, &m_showBorderAndTitleBlock, false ); if( m_showBorderAndTitleBlock ) { wxString pageType; - config->Read( cfgShowPageSizeOption, &pageType, wxT( "GERBER" ) ); + aCfg->Read( cfgShowPageSizeOption, &pageType, wxT( "GERBER" ) ); pageInfo.SetType( pageType ); } @@ -231,16 +246,16 @@ void GERBVIEW_FRAME::LoadSettings() GetScreen()->InitDataPoints( pageInfo.GetSizeIU() ); bool tmp; - config->Read( cfgShowDCodes, &tmp, true ); + aCfg->Read( cfgShowDCodes, &tmp, true ); SetElementVisibility( DCODES_VISIBLE, tmp ); - config->Read( cfgShowNegativeObjects, &tmp, false ); + aCfg->Read( cfgShowNegativeObjects, &tmp, false ); SetElementVisibility( NEGATIVE_OBJECTS_VISIBLE, tmp ); // because we have 2 file historues, we must read this one // using a specific path - config->SetPath( wxT( "drl_files" ) ); - m_drillFileHistory.Load( *config ); - config->SetPath( wxT( ".." ) ); + aCfg->SetPath( wxT( "drl_files" ) ); + m_drillFileHistory.Load( *aCfg ); + aCfg->SetPath( wxT( ".." ) ); // WxWidgets 2.9.1 seems call setlocale( LC_NUMERIC, "" ) // when reading doubles in config, @@ -249,29 +264,25 @@ void GERBVIEW_FRAME::LoadSettings() } -void GERBVIEW_FRAME::SaveSettings() +void GERBVIEW_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); + EDA_DRAW_FRAME::SaveSettings( aCfg ); - if( config == NULL ) - return; + // was: wxGetApp().SaveCurrentSetupValues( GetConfigurationSettings() ); + wxConfigSaveSetups( aCfg, GetConfigurationSettings() ); - EDA_DRAW_FRAME::SaveSettings(); - - wxGetApp().SaveCurrentSetupValues( GetConfigurationSettings() ); - - config->Write( cfgShowPageSizeOption, GetPageSettings().GetType() ); - config->Write( cfgShowBorderAndTitleBlock, m_showBorderAndTitleBlock ); - config->Write( cfgShowDCodes, IsElementVisible( DCODES_VISIBLE ) ); - config->Write( cfgShowNegativeObjects, + aCfg->Write( cfgShowPageSizeOption, GetPageSettings().GetType() ); + aCfg->Write( cfgShowBorderAndTitleBlock, m_showBorderAndTitleBlock ); + aCfg->Write( cfgShowDCodes, IsElementVisible( DCODES_VISIBLE ) ); + aCfg->Write( cfgShowNegativeObjects, IsElementVisible( NEGATIVE_OBJECTS_VISIBLE ) ); // Save the drill file history list. // Because we have 2 file histories, we must save this one // in a specific path - config->SetPath( wxT( "drl_files" ) ); - m_drillFileHistory.Save( *config ); - config->SetPath( wxT( ".." ) ); + aCfg->SetPath( wxT( "drl_files" ) ); + m_drillFileHistory.Save( *aCfg ); + aCfg->SetPath( wxT( ".." ) ); } @@ -394,7 +405,7 @@ void GERBVIEW_FRAME::Liste_D_Codes() if( gerber == NULL ) continue; - if( gerber->ReturnUsedDcodeNumber() == 0 ) + if( gerber->UsedDcodeNumber() == 0 ) continue; if( layer == curr_layer ) diff --git a/gerbview/gerbview_frame.h b/gerbview/gerbview_frame.h index 6a69191706..b97a90561f 100644 --- a/gerbview/gerbview_frame.h +++ b/gerbview/gerbview_frame.h @@ -31,8 +31,8 @@ #define WX_GERBER_STRUCT_H -#include -#include +#include +#include #include #include @@ -201,15 +201,15 @@ private: // An array sting to store warning messages when reaging a gerber file. wxArrayString m_Messages; -public: - GERBVIEW_FRAME( wxWindow* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); +public: + GERBVIEW_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~GERBVIEW_FRAME(); void OnCloseWindow( wxCloseEvent& Event ); + bool OpenProjectFiles( const std::vector& aFileSet, int aCtl ); // overload KIWAY_PLAYER + // Virtual basic functions: void RedrawActiveWindow( wxDC* DC, bool EraseBg ); void ReCreateHToolbar(); @@ -458,28 +458,9 @@ public: */ PARAM_CFG_ARRAY& GetConfigurationSettings( void ); - /** - * Load applications settings specific to the Pcbnew. - * - * This overrides the base class EDA_DRAW_FRAME::LoadSettings() to - * handle settings specific common to the PCB layout application. It - * calls down to the base class to load settings common to all - * EDA_DRAW_FRAME type drawing frames. - * Please put your application settings for Pcbnew here - * to avoid having application settings loaded all over the place. - */ - virtual void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual - /** - * Save applications settings common to PCB draw frame objects. - * - * This overrides the base class EDA_DRAW_FRAME::SaveSettings() to - * save settings specific to the gerbview application main window. It - * calls down to the base class to save settings common to all - * drawing frames. Please put your application settings for Gerbview here - * to avoid having application settings saved all over the place. - */ - virtual void SaveSettings(); + void SaveSettings( wxConfigBase* aCfg ); // override virtual /** * Function SetLanguage @@ -556,11 +537,11 @@ public: void OnUpdateLayerSelectBox( wxUpdateUIEvent& aEvent ); /** - * Function ReturnBlockCommand + * Function BlockCommand * returns the block command (BLOCK_MOVE, BLOCK_COPY...) corresponding to * the \a aKey (ALT, SHIFT ALT ..) */ - virtual int ReturnBlockCommand( int key ); + virtual int BlockCommand( int key ); /** * Function HandleBlockPlace diff --git a/gerbview/menubar.cpp b/gerbview/menubar.cpp index 6ea327a46b..fd2b6c0abf 100644 --- a/gerbview/menubar.cpp +++ b/gerbview/menubar.cpp @@ -29,15 +29,15 @@ */ #include -#include - +#include +#include #include #include #include #include -void GERBVIEW_FRAME::ReCreateMenuBar( void ) +void GERBVIEW_FRAME::ReCreateMenuBar() { // Create and try to get the current menubar wxMenuBar* menuBar = GetMenuBar(); @@ -77,11 +77,13 @@ void GERBVIEW_FRAME::ReCreateMenuBar( void ) // Add this menu to list menu managed by m_fileHistory // (the file history will be updated when adding/removing files in history if( openRecentGbrMenu ) - wxGetApp().GetFileHistory().RemoveMenu( openRecentGbrMenu ); + Kiface().GetFileHistory().RemoveMenu( openRecentGbrMenu ); openRecentGbrMenu = new wxMenu(); - wxGetApp().GetFileHistory().UseMenu( openRecentGbrMenu ); - wxGetApp().GetFileHistory().AddFilesToMenu(); + + Kiface().GetFileHistory().UseMenu( openRecentGbrMenu ); + Kiface().GetFileHistory().AddFilesToMenu(); + AddMenuItem( fileMenu, openRecentGbrMenu, wxID_ANY, _( "Open &Recent Gerber File" ), @@ -166,9 +168,8 @@ void GERBVIEW_FRAME::ReCreateMenuBar( void ) KiBitmap( preference_xpm ) ); #endif // __WXMAC__ - // Language submenu - wxGetApp().AddMenuLanguageList( configMenu ); + Pgm().AddMenuLanguageList( configMenu ); // Hotkey submenu AddHotkeyConfigMenu( configMenu ); diff --git a/gerbview/readgerb.cpp b/gerbview/readgerb.cpp index 01ae04cb4f..ac374bb5c7 100644 --- a/gerbview/readgerb.cpp +++ b/gerbview/readgerb.cpp @@ -97,13 +97,13 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName, break; case 'G': /* Line type Gxx : command */ - G_command = gerber->ReturnGCodeNumber( text ); + G_command = gerber->GCodeNumber( text ); gerber->Execute_G_Command( text, G_command ); break; case 'D': /* Line type Dxx : Tool selection (xx > 0) or * command if xx = 0..9 */ - D_commande = gerber->ReturnDCodeNumber( text ); + D_commande = gerber->DCodeNumber( text ); gerber->Execute_DCODE_Command( text, D_commande ); break; diff --git a/gerbview/rs274d.cpp b/gerbview/rs274d.cpp index 838f1a9b39..7023d63930 100644 --- a/gerbview/rs274d.cpp +++ b/gerbview/rs274d.cpp @@ -406,7 +406,7 @@ static void fillArcPOLY( GERBER_DRAW_ITEM* aGbrItem, /* Read the Gnn sequence and returns the value nn. */ -int GERBER_IMAGE::ReturnGCodeNumber( char*& Text ) +int GERBER_IMAGE::GCodeNumber( char*& Text ) { int ii = 0; char* text; @@ -429,7 +429,7 @@ int GERBER_IMAGE::ReturnGCodeNumber( char*& Text ) /* Get the sequence Dnn and returns the value nn */ -int GERBER_IMAGE::ReturnDCodeNumber( char*& Text ) +int GERBER_IMAGE::DCodeNumber( char*& Text ) { int ii = 0; char* text; @@ -491,7 +491,7 @@ bool GERBER_IMAGE::Execute_G_Command( char*& text, int G_command ) case GC_SELECT_TOOL: { - int D_commande = ReturnDCodeNumber( text ); + int D_commande = DCodeNumber( text ); if( D_commande < FIRST_DCODE ) return false; if( D_commande > (TOOLS_MAX_COUNT - 1) ) diff --git a/gerbview/select_layers_to_pcb.cpp b/gerbview/select_layers_to_pcb.cpp index 6583e578ae..058dfd5d54 100644 --- a/gerbview/select_layers_to_pcb.cpp +++ b/gerbview/select_layers_to_pcb.cpp @@ -27,7 +27,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -301,7 +302,7 @@ void LAYERS_MAP_DIALOG::OnResetClick( wxCommandEvent& event ) */ void LAYERS_MAP_DIALOG::OnStoreSetup( wxCommandEvent& event ) { - wxConfig* config = wxGetApp().GetSettings(); + wxConfigBase* config = Kiface().KifaceSettings(); config->Write( wxT("BrdLayersCount"), m_exportBoardCopperLayersCount ); wxString key; @@ -314,7 +315,7 @@ void LAYERS_MAP_DIALOG::OnStoreSetup( wxCommandEvent& event ) void LAYERS_MAP_DIALOG::OnGetSetup( wxCommandEvent& event ) { - wxConfig* config = wxGetApp().GetSettings(); + wxConfigBase* config = Kiface().KifaceSettings(); config->Read( wxT("BrdLayersCount"), &m_exportBoardCopperLayersCount ); normalizeBrdLayersCount(); diff --git a/include/appl_wxstruct.h b/include/appl_wxstruct.h deleted file mode 100644 index e58dd4f6be..0000000000 --- a/include/appl_wxstruct.h +++ /dev/null @@ -1,450 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com - * Copyright (C) 2008-2011 Wayne Stambaugh - * Copyright (C) 1992-2011 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 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file appl_wxstruct.h - * @brief Base class implementation for all KiCad applications. - */ - -#ifndef APPL_WXSTRUCT_H -#define APPL_WXSTRUCT_H - -/* Use wxFileHistory for most recently used file handling. */ -#include -#include -#include -#include - - -enum EDA_APP_T { - APP_UNKNOWN_T, - APP_EESCHEMA_T, - APP_PCBNEW_T, - APP_CVPCB_T, - APP_GERBVIEW_T, - APP_KICAD_T, - APP_PL_EDITOR_T -}; - -class wxConfigBase; -class wxFileConfig; -class wxSingleInstanceChecker; -class wxHtmlHelpController; - - -/** - * Class EDA_APP - * is the base class representing all of KiCad applications. - */ -class EDA_APP : public wxApp -{ -protected: - /// Used mainly to handle default paths libs m_Id = APP_EESCHEMA_T, APP_PCBNEW_T ... - EDA_APP_T m_Id; - - /// Used to prevent multiple instances of an application from being run at the same time. - wxSingleInstanceChecker* m_Checker; - - /// Used to prevent opening the same file multiple times. - wxSingleInstanceChecker* m_oneInstancePerFileChecker; - - wxString m_Project; - - /// The application specific configuration settings. - wxConfig* m_settings; - - /// The configuration settings common to all KiCad applications. - wxConfig* m_commonSettings; - - /// The current project specific settings. - wxFileConfig* m_projectSettings; - - /// KiCad executable path. - wxString m_BinDir; - - /// The KICAD system environment variable. - wxString m_KicadEnv; - - /// The current locale. - wxLocale* m_Locale; - - /// The current language setting. - int m_LanguageId; - - void setLanguageId( int aId ) { m_LanguageId = aId; } - - /// The file name of the the program selected for browsing pdf files. - wxString m_PdfBrowser; - wxPathList m_searchPaths; - wxFileHistory m_fileHistory; - wxString m_HelpFileName; - wxString m_EditorName; - wxString m_CurrentOptionFile; - wxString m_CurrentOptionFileDateAndTime; - wxPoint m_HelpPos; - wxSize m_HelpSize; - wxString m_Title; - wxPathList m_libSearchPaths; - wxFileName m_projectFileName; - wxString m_LastVisitedLibPath; - - /// last visited module library in the module editor or viewer - wxString m_module_nickname; - - wxHtmlHelpController* m_HtmlCtrl; - -public: - EDA_APP(); - ~EDA_APP(); - - /** - * Function OnInit - * this is the first executed function (like main() ) - * @return true if the application can be started. - */ - bool OnInit(); // should this be virtual - - wxHtmlHelpController* GetHtmlHelpController() { return m_HtmlCtrl; } - - void SetHtmlHelpController( wxHtmlHelpController* aController ); - - wxString GetHelpFileName() const { return m_HelpFileName; } - void SetHelpFileName( const wxString& aFileName ) { m_HelpFileName = aFileName; } - - wxConfig* GetSettings() { return m_settings; } - - wxConfig* GetCommonSettings() { return m_commonSettings; } - - wxString GetEditorName() const { return m_EditorName; } - void SetEditorName( const wxString& aFileName ) { m_EditorName = aFileName; } - - wxString GetCurrentOptionFile() const { return m_CurrentOptionFile; } - - bool IsKicadEnvVariableDefined() const { return !m_KicadEnv.IsEmpty(); } - - wxString GetKicadEnvVariable() const { return m_KicadEnv; } - - wxString GetExecutablePath() const { return m_BinDir; } - - wxLocale* GetLocale() { return m_Locale; } - - wxString GetPdfBrowserFileName() const { return m_PdfBrowser; } - - void SetPdfBrowserFileName( const wxString& aFileName ) { m_PdfBrowser = aFileName; } - - bool UseSystemPdfBrowser() const { return m_PdfBrowser.IsEmpty(); } - - wxFileHistory& GetFileHistory() { return m_fileHistory; } - - /** - * Function SetBinDir - * finds the path to the executable and store it in EDA_APP::m_BinDir - * - * @return TODO - */ - bool SetBinDir(); - - /** - * Function SetDefaultSearchPaths - * sets search paths for libraries, modules, internationalization files, etc. - */ - void SetDefaultSearchPaths( void ); - - /** - * Function MacOpenFile - * Specific to MacOSX. Not used under Linux or Windows - * MacOSX: Needed for file association - * http://wiki.wxwidgets.org/WxMac-specific_topics - */ - virtual void MacOpenFile( const wxString& aFileName ); - - /** - * Function InitEDA_Appl - * initialize some general parameters - * - Default paths (help, libs, bin)and configuration files names - * - Language and locale - * - fonts - * @param aName : used as paths in configuration files - * @param aId = flag : LIBRARY_TYPE_EESCHEMA or LIBRARY_TYPE_PCBNEW - * used to choose what default library path must be used - */ - void InitEDA_Appl( const wxString& aName, EDA_APP_T aId = APP_UNKNOWN_T ); - - /** - * Function SetLanguage - * sets the dictionary file name for internationalization. - *

- * The files are in kicad/internat/xx or kicad/internat/xx_XX and are named kicad.mo - *

- * @param first_time must be set to true the first time this funct is - * called, false otherwise - * @return true if the language can be set (i.e. if the locale is available) - */ - bool SetLanguage( bool first_time = false ); - - /** - * Function AddMenuLanguageList - * creates a menu list for language choice, and add it as submenu to \a MasterMenu. - * - * @param MasterMenu The main menu. The sub menu list will be accessible from the menu - * item with id ID_LANGUAGE_CHOICE - */ - void AddMenuLanguageList( wxMenu* MasterMenu ); - - /** - * Function SetLanguageIdentifier - * sets in .m_LanguageId member the wxWidgets language identifier Id from - * the KiCad menu id (internal menu identifier). - * - * @param menu_id The KiCad menuitem id (returned by Menu Event, when - * clicking on a menu item) - */ - void SetLanguageIdentifier( int menu_id ); - - void SetLanguagePath( void ); - - /** - * Function InitOnLineHelp - * initializes KiCad's online help. - */ - void InitOnLineHelp(); - - /** - * Function GetSettings - * gets the application settings. - * @param aReopenLastUsedDirectory True to switch to last opened directory, false - * to use current CWD - */ - void GetSettings( bool aReopenLastUsedDirectory ); - - /** - * Function SaveSettings - * saves the application settings. - */ - void SaveSettings(); - - /** - * Function WriteProjectConfig - * Save the current "project" parameters - * saved parameters are parameters that have the .m_Setup member set to false - * saving file is the .pro file project - */ - void WriteProjectConfig( const wxString& fileName, - const wxString& GroupName, - const PARAM_CFG_ARRAY& params ); - - /** - * Function SaveCurrentSetupValues - * saves the current setup values in m_settings. - * Saved parameters are parameters that have the .m_Setup member set to - * true. - * @param aList = array of PARAM_CFG_BASE pointers - */ - void SaveCurrentSetupValues( const PARAM_CFG_ARRAY& aList ); - - /** - * Function ReadCurrentSetupValues - * reads the current setup values previously saved, from m_settings. - * Saved parameters are parameters that have the .m_Setup member set to - * true. - * @param aList = array of PARAM_CFG_BASE pointers - */ - void ReadCurrentSetupValues( const PARAM_CFG_ARRAY& aList ); - - /** - * Function ReadProjectConfig - * Read the current "project" parameters - * Parameters are parameters that have the .m_Setup member set to false - * read file is the .pro file project - * - * if Load_Only_if_New == true, this file is read only if it differs from - * the current config (different dates ) - * - * @return true if read. - * Also set: - * wxGetApp().m_CurrentOptionFileDateAndTime - * wxGetApp().m_CurrentOptionFile - */ - bool ReadProjectConfig( const wxString& local_config_filename, - const wxString& GroupName, - PARAM_CFG_BASE** List, - bool Load_Only_if_New ); - bool ReadProjectConfig( const wxString& local_config_filename, - const wxString& GroupName, - const PARAM_CFG_ARRAY& List, - bool Load_Only_if_New ); - - /** - * Creates or recreates the KiCad project file. (filename.pro) - * Initialize: - * G_Prj_Config - * G_Prj_Config_LocalFilename - * G_Prj_Default_Config_FullFilename - * Return: - * True if local config - * False if default config - */ - bool ReCreatePrjConfig( const wxString& local_config_filename, - const wxString& GroupName, - bool ForceUseLocalConfig ); - - /** - * Function ReadPdfBrowserInfos - * read the PDF browser choice from the common configuration. - */ - void ReadPdfBrowserInfos(); - - /* Function WritePdfBrowserInfos - * save the PDF browser choice to the common configuration. - */ - void WritePdfBrowserInfos(); - - /** - * Function FindFileInSearchPaths - * looks in search paths for \a filename. - */ - wxString FindFileInSearchPaths( const wxString& filename, - const wxArrayString* subdirs = NULL ); - - /** - * Function GetHelpFile - * get the help file path. - *

- * Return the KiCad help file with path. The base paths defined in - * m_searchPaths are tested for a valid file. The path returned can - * be relative depending on the paths added to m_searchPaths. See the - * documentation for wxPathList for more information. If the help file - * for the current locale is not found, an attempt to find the English - * version of the help file is made. - * wxEmptyString is returned if help file not found. - * Help file is searched in directories in this order: - * help/\ like help/en_GB - * help/\ like help/en - * help/en - *

- */ - wxString GetHelpFile( void ); - - /** - * Return the preferred editor name. - */ - wxString& GetEditorName(); - - const wxString& GetTitle() { return m_Title; } - void SetTitle( const wxString& aTitle ) { m_Title = aTitle; } - - wxPathList& GetLibraryPathList() { return m_libSearchPaths; } - wxString FindLibraryPath( const wxString& fileName ); - - /** - * Function FindLibraryPath - * KiCad saves user defined library files that are not in the standard - * library search path list with the full file path. Calling the library - * search path list with a user library file will fail. This helper method - * solves that problem. - * @param fileName - * @return a wxEmptyString if library file is not found. - */ - wxString FindLibraryPath( const wxFileName& fileName ) - { - return FindLibraryPath( fileName.GetFullPath() ); - } - - - /** - * Function ReturnLastVisitedLibraryPath - * returns the last visited library directory, or (if void) the first - * path in lib path list ( but not the CWD ) - * - * @param aSubPathToSearch = Preferred sub path to search in path list - */ - wxString ReturnLastVisitedLibraryPath( const wxString& aSubPathToSearch = wxEmptyString ); - - void SaveLastVisitedLibraryPath( const wxString& aPath ); - - /** - * Function ReturnFilenameWithRelativePathInLibPath - * @return a short filename (with extension) with only a relative path if - * this filename can be found in library paths - * @param aFullFilename The filename with path and extension. - */ - wxString ReturnFilenameWithRelativePathInLibPath( const wxString& aFullFilename ); - - /** - * Function RemoveLibraryPath - * Removes the given path(s) from the library path list - * @param aPaths = path or path list to remove. paths must be separated by - * ";" - */ - void RemoveLibraryPath( const wxString& aPaths ); - - /** - * Function InsertLibraryPath - * insert path(s) int lib paths list. - * @param aPaths = path or path list to add. paths must be separated by ";" - * @param aIndex = insertion point - */ - void InsertLibraryPath( const wxString& aPaths, size_t aIndex ); - - /** - * Function LockFile - * Locks the access to a file. - * @param fileName = full path to the file. - * @return false if the file was already locked, true otherwise. - */ - bool LockFile( const wxString& fileName ); - - /** - * Function SetFootprintLibTableEnv - * attempts set the KISYSMOD environment variable to the best possible path. - * - * The path is determined by attempting to find the path with the most footprint library - * files. This may or may not be the best path but it provides the best solution for - * backwards compatibility with the previous library search path implementation. If the - * KISYSMOD environment variable is already set, then it left as is to respect the wishes - * of the user. - * - * @note This must be called after #SetDefaultSearchPaths() is called. Otherwise, the - * list of library search paths will be empty and KISYSMOD will be undefined making - * it impossible for the footprint libraries to be loaded from the footprint library - * table. - * - * @return false if the KISYSMOD path is not valid. - */ - bool SetFootprintLibTablePath(); - - const wxString& GetModuleLibraryNickname() { return m_module_nickname; } - void SetModuleLibraryNickname( const wxString& aNickname ) { m_module_nickname = aNickname; } -}; - - -/* - * Use wxGetApp() to access EDA_APP. It is not necessary to keep copies - * of the application pointer all over the place or worse yet in a global - * variable. - */ -DECLARE_APP( EDA_APP ) - -#endif // APPL_WXSTRUCT_H diff --git a/include/base_units.h b/include/base_units.h index b8492deafe..2858cc7388 100644 --- a/include/base_units.h +++ b/include/base_units.h @@ -108,7 +108,7 @@ wxString AngleToStringDegrees( double aAngle ); wxString LengthDoubleToString( double aValue, bool aConvertToMils = false ); /** - * Function ReturnStringFromValue + * Function StringFromValue * returns the string from \a aValue according to units (inch, mm ...) for display, * and the initial unit for value. * @@ -126,7 +126,7 @@ wxString LengthDoubleToString( double aValue, bool aConvertToMils = false ); * @param aAddUnitSymbol = true to add symbol unit to the string value * @return A wxString object containing value and optionally the symbol unit (like 2.000 mm) */ -wxString ReturnStringFromValue( EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol = false ); +wxString StringFromValue( EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol = false ); /** * Operator << overload @@ -153,17 +153,17 @@ void PutValueInLocalUnits( wxTextCtrl& aTextCtr, int aValue ); double From_User_Unit( EDA_UNITS_T aUnit, double aValue ); /** - * Function ReturnValueFromString + * Function ValueFromString * converts \a aTextValue in \a aUnits to internal units used by the application. * * @param aUnits The units of \a aTextValue. * @param aTextValue A reference to a wxString object containing the string to convert. * @return The string from Value, according to units (inch, mm ...) for display, */ -int ReturnValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue ); +int ValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue ); /** - * Function ReturnValueFromString + * Function ValueFromString * converts \a aTextValue in \a aUnits to internal units used by the application, * unit type will be obtained from g_UserUnit. @@ -172,12 +172,12 @@ int ReturnValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue ); * @return The string from Value, according to units (inch, mm ...) for display, */ -int ReturnValueFromString( const wxString& aTextValue ); +int ValueFromString( const wxString& aTextValue ); /** * Convert the number Value in a string according to the internal units * and the selected unit (g_UserUnit) and put it in the wxTextCtrl TextCtrl */ -int ReturnValueFromTextCtrl( const wxTextCtrl& aTextCtr ); +int ValueFromTextCtrl( const wxTextCtrl& aTextCtr ); #endif // _BASE_UNITS_H_ diff --git a/include/bin_mod.h b/include/bin_mod.h new file mode 100644 index 0000000000..c834f2cd7c --- /dev/null +++ b/include/bin_mod.h @@ -0,0 +1,64 @@ +#ifndef BIN_MOD_H_ +#define BIN_MOD_H_ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 + #include // wx 3.0: +#else + #include +#endif + +#include + +#include + +class wxConfigBase; + +/** + * Struct BIN_MOD + * pertains to a single program module, either an EXE or a DSO/DLL ("bin_mod"). + * It manages miscellaneous configuration file information pertinent to one bin_mod. + * Because it serves in both DSO/DLLs and in EXEs, its name is neutral. + *

+ * Accessors are in containing (wrapper) classes. + */ +struct BIN_MOD +{ + BIN_MOD( const char* aName ); + ~BIN_MOD(); + + void Init(); + void End(); + + const char* m_name; ///< name of this binary module, static C string. + + wxConfigBase* m_config; ///< maybe from $HOME/. + wxFileHistory m_history; + wxString m_help_file; + + SEARCH_STACK m_search; +}; + +#endif // BIN_MOD_H_ diff --git a/include/class_board_design_settings.h b/include/class_board_design_settings.h index 9b516308b2..826741b8f4 100644 --- a/include/class_board_design_settings.h +++ b/include/class_board_design_settings.h @@ -7,7 +7,7 @@ #include // NB_COLORS #include -#include +#include /** diff --git a/include/colors.h b/include/colors.h index a1bd0c8fdf..c7dfa1fd2d 100644 --- a/include/colors.h +++ b/include/colors.h @@ -2,8 +2,8 @@ /* colors.h */ /************/ -#ifndef _COLORS_H -#define _COLORS_H +#ifndef COLORS_H_ +#define COLORS_H_ #include @@ -195,4 +195,4 @@ inline wxColour MakeColour( EDA_COLOR_T aColor ) ); } -#endif /* ifndef _COLORS_H */ +#endif // COLORS_H_ diff --git a/include/common.h b/include/common.h index ca40fca2b5..a6b282df08 100644 --- a/include/common.h +++ b/include/common.h @@ -44,6 +44,8 @@ class wxAboutDialogInfo; +class SEARCH_STACK; + // Flag for special keys #define GR_KB_RIGHTSHIFT 0x10000000 /* Keybd states: right @@ -579,4 +581,12 @@ unsigned GetRunningMicroSecs(); */ wxString FormatDateLong( const wxDateTime &aDate ); +/** + * Function SystemDirsAppend + * appends system places to aSearchStack in a platform specific way, and pertinent + * to KiCad programs. It seems to be a place to collect bad ideas and keep them + * out of view. + */ +void SystemDirsAppend( SEARCH_STACK* aSearchStack ); + #endif // INCLUDE__COMMON_H_ diff --git a/include/param_config.h b/include/config_params.h similarity index 69% rename from include/param_config.h rename to include/config_params.h index fdb98fc18f..a8002e0a9e 100644 --- a/include/param_config.h +++ b/include/config_params.h @@ -1,10 +1,34 @@ -/** - * The common library - * @file param_config.h +#ifndef CONFIG_PARAMS_H_ +#define CONFIG_PARAMS_H_ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#ifndef PARAM_CONFIG_H_ -#define PARAM_CONFIG_H_ +/** + * The common library + * @file config_params.h + */ #include #include @@ -13,6 +37,9 @@ #include +#define CONFIG_VERSION 1 +#define FORCE_LOCAL_CONFIG true + /** * Function ConfigBaseWriteDouble @@ -258,6 +285,67 @@ public: /** A list of parameters type */ -typedef boost::ptr_vector PARAM_CFG_ARRAY; +//typedef boost::ptr_vector PARAM_CFG_ARRAY; +class PARAM_CFG_ARRAY : public boost::ptr_vector +{ +}; -#endif // PARAM_CONFIG_H_ + +/** + * Function wxConfigSaveSetups + * writes @a aList of PARAM_CFG_ARRAY elements to save configuration values + * to @a aCfg. Only elements with m_Setup set true will be saved, hence the + * function name. + * + * @param aCfg where to save + * @param aList holds some configuration parameters, not all of which will + * necessarily be saved. + */ +void wxConfigSaveSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList ); + +/** + * Function wxConfigSaveParams + * writes @a aList of PARAM_CFG_ARRAY elements to save configuration values + * to @a aCfg. Only elements with m_Setup set false will be saved, hence the + * function name. + * + * @param aCfg where to save + * @param aList holds some configuration parameters, not all of which will + * necessarily be saved. + * @param aGroup indicates in which group the value should be saved, + * unless the PARAM_CFG_ARRAY element provides its own group, in which case it will + * take precedence. aGroup may be empty. + */ +void wxConfigSaveParams( wxConfigBase* aCfg, + const PARAM_CFG_ARRAY& aList, const wxString& aGroup ); + +/** + * Function wxConfigLoadSetups + * uses @a aList of PARAM_CFG_ARRAY elements to load configuration values + * from @a aCfg. Only elements whose m_Setup field is true will be loaded. + * + * @param aCfg where to load from. + * @param aList holds some configuration parameters, not all of which will + * necessarily be loaded. + */ +void wxConfigLoadSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList ); + +/** + * Function wxConfigLoadParams + * uses @a aList of PARAM_CFG_ARRAY elements to load configuration values + * from @a aCfg. Only elements whose m_Setup field is false will be loaded. + * + * @param aCfg where to load from. + * + * @param aList holds some configuration parameters, not all of which will + * necessarily be loaded. + * + * @param aGroup indicates in which group the value should be saved, + * unless the PARAM_CFG_ARRAY element provides its own group, in which case it will + * take precedence. aGroup may be empty. + */ +void wxConfigLoadParams( wxConfigBase* aCfg, + const PARAM_CFG_ARRAY& aList, const wxString& aGroup ); + + +#endif // CONFIG_PARAMS_H_ diff --git a/include/dialog_hotkeys_editor.h b/include/dialog_hotkeys_editor.h index d8b671cd3d..81c523f935 100644 --- a/include/dialog_hotkeys_editor.h +++ b/include/dialog_hotkeys_editor.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include <../common/dialogs/dialog_hotkeys_editor_base.h> class HOTKEYS_EDITOR_DIALOG : public HOTKEYS_EDITOR_DIALOG_BASE diff --git a/include/dialog_shim.h b/include/dialog_shim.h index 56e30253fb..cab1d5f0f7 100644 --- a/include/dialog_shim.h +++ b/include/dialog_shim.h @@ -27,6 +27,7 @@ #include #include +#include #if wxMINOR_VERSION == 8 && defined(__WXGTK__) #define DLGSHIM_USE_SETFOCUS 1 @@ -44,7 +45,7 @@ *
* in the dialog window's properties. **/ -class DIALOG_SHIM : public wxDialog +class DIALOG_SHIM : public wxDialog, public KIWAY_HOLDER { public: @@ -57,6 +58,7 @@ public: bool Show( bool show ); // overload wxDialog::Show + protected: std::string m_hash_key; // alternate for class_map when classname re-used. @@ -64,8 +66,6 @@ protected: private: void onInit( wxInitDialogEvent& aEvent ); #endif - - }; #endif // DIALOG_SHIM_ diff --git a/include/draw_frame.h b/include/draw_frame.h new file mode 100644 index 0000000000..b533688e55 --- /dev/null +++ b/include/draw_frame.h @@ -0,0 +1,652 @@ +#ifndef EDA_DRAW_FRAME_H_ +#define EDA_DRAW_FRAME_H_ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + + +/** + * Class EDA_DRAW_FRAME + * is the base class for create windows for drawing purpose. The Eeschema, Pcbnew and + * GerbView main windows are just a few examples of classes derived from EDA_DRAW_FRAME. + */ +class EDA_DRAW_FRAME : public KIWAY_PLAYER +{ + /// Let the #EDA_DRAW_PANEL object have access to the protected data since + /// it is closely tied to the #EDA_DRAW_FRAME. + friend class EDA_DRAW_PANEL; + + ///< Id of active button on the vertical toolbar. + int m_toolId; + + BASE_SCREEN* m_currentScreen; ///< current used SCREEN + + bool m_snapToGrid; ///< Indicates if cursor should be snapped to grid. + bool m_galCanvasActive; ///< whether to use new GAL engine + + EDA_DRAW_PANEL_GAL* m_galCanvas; + +protected: + EDA_HOTKEY_CONFIG* m_HotkeysZoomAndGridList; + int m_LastGridSizeId; // the command id offset (>= 0) of the last selected grid + // 0 is for the grid corresponding to + // a wxCommand ID = ID_POPUP_GRID_LEVEL_1000. + bool m_DrawGrid; // hide/Show grid + EDA_COLOR_T m_GridColor; // Grid color + + /// The area to draw on. + EDA_DRAW_PANEL* m_canvas; + + /// Tool ID of previously active draw tool bar button. + int m_lastDrawToolId; + + /// The shape of the KiCad cursor. The default value (0) is the normal cross + /// hair cursor. Set to non-zero value to draw the full screen cursor. + /// @note This is not the system mouse cursor. + int m_cursorShape; + + /// True shows the X and Y axis indicators. + bool m_showAxis; + + /// True shows the grid axis indicators. + bool m_showGridAxis; + + /// True shows the origin axis used to indicate the coordinate offset for + /// drill, gerber, and component position files. + bool m_showOriginAxis; + + /// True shows the drawing border and title block. + bool m_showBorderAndTitleBlock; + + /// Choice box to choose the grid size. + wxComboBox* m_gridSelectBox; + + /// Choice box to choose the zoom value. + wxComboBox* m_zoomSelectBox; + + /// The tool bar that contains the buttons for quick access to the application draw + /// tools. It typically is located on the right side of the main window. + wxAuiToolBar* m_drawToolBar; + + /// The options tool bar typcially located on the left edge of the main window. + wxAuiToolBar* m_optionsToolBar; + + /// Panel used to display information at the bottom of the main window. + EDA_MSG_PANEL* m_messagePanel; + + int m_MsgFrameHeight; + +#ifdef USE_WX_OVERLAY + // MAC Uses overlay to workaround the wxINVERT and wxXOR miss + wxOverlay m_overlay; +#endif + + void SetScreen( BASE_SCREEN* aScreen ) { m_currentScreen = aScreen; } + + /** + * Function unitsChangeRefresh + * is called when when the units setting has changed to allow for any derived classes + * to handle refreshing and controls that have units based measurements in them. The + * default version only updates the status bar. Don't forget to call the default + * in your derived class or the status bar will not get updated properly. + */ + virtual void unitsChangeRefresh(); + +public: + EDA_DRAW_FRAME( KIWAY* aKiway, wxWindow* aParent, + ID_DRAWFRAME_TYPE aFrameType, + const wxString& aTitle, + const wxPoint& aPos, const wxSize& aSize, + long aStyle, + const wxString& aFrameName ); + + ~EDA_DRAW_FRAME(); + + virtual void SetPageSettings( const PAGE_INFO& aPageSettings ) = 0; + virtual const PAGE_INFO& GetPageSettings() const = 0; + + /** + * Function GetPageSizeIU + * works off of GetPageSettings() to return the size of the paper page in + * the internal units of this particular view. + */ + virtual const wxSize GetPageSizeIU() const = 0; + + /** + * Function GetAuxOrigin + * returns the origin of the axis used for plotting and various exports. + */ + virtual const wxPoint& GetAuxOrigin() const = 0; + virtual void SetAuxOrigin( const wxPoint& aPosition ) = 0; + + /** + * Function GetGridOrigin + * returns the absolute coordinates of the origin of the snap grid. This is + * treated as a relative offset, and snapping will occur at multiples of the grid + * size relative to this point. + */ + virtual const wxPoint& GetGridOrigin() const = 0; + virtual void SetGridOrigin( const wxPoint& aPosition ) = 0; + + //----------------------------------------------- + /** + * Function GetCrossHairPosition + * return the current cross hair position in logical (drawing) coordinates. + * @param aInvertY Inverts the Y axis position. + * @return The cross hair position in drawing coordinates. + */ + wxPoint GetCrossHairPosition( bool aInvertY = false ) const; + + /** + * Function SetCrossHairPosition + * sets the screen cross hair position to \a aPosition in logical (drawing) units. + * @param aPosition The new cross hair position. + * @param aSnapToGrid Sets the cross hair position to the nearest grid position to + * \a aPosition. + * + */ + void SetCrossHairPosition( const wxPoint& aPosition, bool aSnapToGrid = true ); + + /** + * Function GetCursorPosition + * returns the current cursor position in logical (drawing) units. + * @param aOnGrid Returns the nearest grid position at the current cursor position. + * @param aGridSize Custom grid size instead of the current grid size. Only valid + * if \a aOnGrid is true. + * @return The current cursor position. + */ + wxPoint GetCursorPosition( bool aOnGrid, wxRealPoint* aGridSize = NULL ) const; + + /** + * Function GetNearestGridPosition + * returns the nearest \a aGridSize location to \a aPosition. + * @param aPosition The position to check. + * @param aGridSize The grid size to locate to if provided. If NULL then the current + * grid size is used. + * @return The nearst grid position. + */ + wxPoint GetNearestGridPosition( const wxPoint& aPosition, wxRealPoint* aGridSize = NULL ) const; + + /** + * Function GetCursorScreenPosition + * returns the cross hair position in device (display) units.b + * @return The current cross hair position. + */ + wxPoint GetCrossHairScreenPosition() const; + + void SetMousePosition( const wxPoint& aPosition ); + + /** + * Function RefPos + * Return the reference position, coming from either the mouse position + * or the cursor position. + * + * @param useMouse If true, return mouse position, else cursor's. + * + * @return wxPoint - The reference point, either the mouse position or + * the cursor position. + */ + wxPoint RefPos( bool useMouse ) const; + + const wxPoint& GetScrollCenterPosition() const; + void SetScrollCenterPosition( const wxPoint& aPoint ); + + //---------------------------------------------- + + + virtual const TITLE_BLOCK& GetTitleBlock() const = 0; + virtual void SetTitleBlock( const TITLE_BLOCK& aTitleBlock ) = 0; + + int GetCursorShape() const { return m_cursorShape; } + + void SetCursorShape( int aCursorShape ) { m_cursorShape = aCursorShape; } + + bool GetShowBorderAndTitleBlock() const { return m_showBorderAndTitleBlock; } + + void SetShowBorderAndTitleBlock( bool aShow ) { m_showBorderAndTitleBlock = aShow; } + + EDA_DRAW_PANEL* GetCanvas() { return m_canvas; } + + virtual wxString GetScreenDesc() const; + + /** + * Function GetScreen + * returns a pointer to a BASE_SCREEN or one of its + * derivatives. It is overloaded by derived classes to return + * SCH_SCREEN or PCB_SCREEN. + */ + virtual BASE_SCREEN* GetScreen() const { return m_currentScreen; } + + /** + * Execute a remote command send via a socket to the application, + * port KICAD_PCB_PORT_SERVICE_NUMBER (currently 4242) + * It called by EDA_DRAW_FRAME::OnSockRequest(). + * this is a virtual function becuse the actual commands depends on the + * application. + * the basic function do nothing + * @param cmdline = received command from socket + */ + virtual void ExecuteRemoteCommand( const char* cmdline ){} + + void OnMenuOpen( wxMenuEvent& event ); + void OnMouseEvent( wxMouseEvent& event ); + + /** function SkipNextLeftButtonReleaseEvent + * after calling this function, if the left mouse button + * is down, the next left mouse button release event will be ignored. + * It is is usefull for instance when closing a dialog on a mouse click, + * to skip the next mouse left button release event + * by the parent window, because the mouse button + * clicked on the dialog is often released in the parent frame, + * and therefore creates a left button released mouse event + * which can be unwanted in some cases + */ + void SkipNextLeftButtonReleaseEvent(); + + virtual void OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, + EDA_ITEM* aItem = NULL ); + + /** + * Function AddMenuZoomAndGrid (virtual) + * Add standard zoom commands and submenu zoom and grid selection to a popup menu + * uses zoom hotkeys info base to add hotkeys info to menu commands + * @param aMasterMenu = the menu to populate. + */ + virtual void AddMenuZoomAndGrid( wxMenu* aMasterMenu ); + + void EraseMsgBox(); + void Process_PageSettings( wxCommandEvent& event ); + + /** + * Function SetLanguage + * called on a language menu selection + * when using a derived function, do not forget to call this one + */ + virtual void SetLanguage( wxCommandEvent& event ); + + virtual void ReCreateHToolbar() = 0; + virtual void ReCreateVToolbar() = 0; + virtual void ReCreateMenuBar(); + virtual void ReCreateAuxiliaryToolbar(); + + /** + * Function SetToolID + * sets the tool command ID to \a aId and sets the cursor to \a aCursor. The + * command ID must be greater or equal ::ID_NO_TOOL_SELECTED. If the command + * ID is less than ::ID_NO_TOOL_SELECTED, the tool command ID is set to + * ::ID_NO_TOOL_SELECTED. On debug builds, an assertion will be raised when + * \a aId is invalid. + * @param aId New tool command ID if greater than or equal to ::ID_NO_TOOL_SELECTED. + If less than zero, the current tool command ID is retained. + * @param aCursor Sets the cursor shape if greater than or equal to zero. + * @param aToolMsg The tool message to set in the status bar. + */ + virtual void SetToolID( int aId, int aCursor, const wxString& aToolMsg ); + + int GetToolId() const { return m_toolId; } + + /* These 4 functions provide a basic way to show/hide grid + * and /get/set grid color. + * These parameters are saved in KiCad config for each main frame + */ + /** + * Function IsGridVisible() , virtual + * @return true if the grid must be shown + */ + virtual bool IsGridVisible() const + { + return m_DrawGrid; + } + + /** + * Function SetGridVisibility() , virtual + * It may be overloaded by derived classes + * @param aVisible = true if the grid must be shown + */ + virtual void SetGridVisibility( bool aVisible ) + { + m_DrawGrid = aVisible; + } + + /** + * Function GetGridColor() , virtual + * @return the color of the grid + */ + virtual EDA_COLOR_T GetGridColor() const + { + return m_GridColor; + } + + /** + * Function SetGridColor() , virtual + * @param aColor = the new color of the grid + */ + virtual void SetGridColor( EDA_COLOR_T aColor ) + { + m_GridColor = aColor; + } + + /** + * Function GetGridPosition + * returns the nearest grid position to \a aPosition if a screen is defined and snap to + * grid is enabled. Otherwise, the original positions is returned. + * @see m_snapToGrid and m_BaseScreen members. + * @param aPosition The position to test. + * @return The wxPoint of the appropriate cursor position. + */ + wxPoint GetGridPosition( const wxPoint& aPosition ) const; + + /** + * Command event handler for selecting grid sizes. + * + * All commands that set the grid size should eventually end up here. + * This is where the application setting is saved. If you override + * this method, make sure you call down to the base class. + * + * @param event - Command event passed by selecting grid size from the + * grid size combobox on the toolbar. + */ + virtual void OnSelectGrid( wxCommandEvent& event ); + + /** + * Functions OnSelectZoom + * sets the zoom factor when selected by the zoom list box in the main tool bar. + * @note List position 0 is fit to page + * List position >= 1 = zoom (1 to zoom max) + * Last list position is custom zoom not in zoom list. + */ + virtual void OnSelectZoom( wxCommandEvent& event ); + + // Command event handlers shared by all applications derived from EDA_DRAW_FRAME. + void OnToggleGridState( wxCommandEvent& aEvent ); + void OnSelectUnits( wxCommandEvent& aEvent ); + void OnToggleCrossHairStyle( wxCommandEvent& aEvent ); + + // Update user interface event handlers shared by all applications derived from + // EDA_DRAW_FRAME. + void OnUpdateUndo( wxUpdateUIEvent& aEvent ); + void OnUpdateRedo( wxUpdateUIEvent& aEvent ); + void OnUpdateGrid( wxUpdateUIEvent& aEvent ); + void OnUpdateUnits( wxUpdateUIEvent& aEvent ); + void OnUpdateCrossHairStyle( wxUpdateUIEvent& aEvent ); + + /** + * Function GeneralControl + * performs application specific control using \a aDC at \a aPosition in logical units. + *

+ * Override this function for application specific control. This function gets + * called on every mouse and key event. + *

+ * @param aDC A device context. + * @param aPosition The current cursor position in logical (drawing) units. + * @param aHotKey A key event used for application specific control if not zero. + */ + virtual void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ) { } + + /** + * Function OnSize + * recalculates the size of toolbars and display panel when the frame size changes. + */ + virtual void OnSize( wxSizeEvent& event ); + + void OnEraseBackground( wxEraseEvent& SizeEvent ); + + virtual void OnZoom( wxCommandEvent& event ); + + /** + * Function RedrawScreen + * redraws the entire screen area by updating the scroll bars and mouse pointer in + * order to have \a aCenterPoint at the center of the screen. + * @param aCenterPoint The position in logical units to center the scroll bars. + * @param aWarpPointer Moves the mouse cursor to \a aCenterPoint if true. + */ + void RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer ); + + /** + * Function RedrawScreen2 + * puts the crosshair back to the screen position it had before zooming + * @param posBefore screen position of the crosshair before zooming + */ + void RedrawScreen2( const wxPoint& posBefore ); + + /** + * Function Zoom_Automatique + * redraws the screen with best zoom level and the best centering + * that shows all the page or the board + */ + void Zoom_Automatique( bool aWarpPointer ); + + /* Set the zoom level to show the area Rect */ + void Window_Zoom( EDA_RECT& Rect ); + + /** Return the zoom level which displays the full page on screen */ + virtual double BestZoom() = 0; + + /** + * Function GetZoom + * @return The current zoom level. + */ + double GetZoom(); + + /** + * Function DrawWorkSheet + * Draws on screen the page layout with the frame and the basic inscriptions. + * @param aDC The device context. + * @param aScreen screen to draw + * @param aLineWidth The pen width to use to draw the layout. + * @param aScale The mils to Iu conversion factor. + * @param aFilename The filename to display in basic inscriptions. + */ + void DrawWorkSheet( wxDC* aDC, BASE_SCREEN* aScreen, int aLineWidth, + double aScale, const wxString &aFilename ); + + void DisplayToolMsg( const wxString& msg ); + virtual void RedrawActiveWindow( wxDC* DC, bool EraseBg ) = 0; + virtual void OnLeftClick( wxDC* DC, const wxPoint& MousePos ) = 0; + virtual void OnLeftDClick( wxDC* DC, const wxPoint& MousePos ); + virtual bool OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu ) = 0; + virtual void ToolOnRightClick( wxCommandEvent& event ); + void AdjustScrollBars( const wxPoint& aCenterPosition ); + + /** + * Function OnActivate (virtual) + * is called when activating the frame. + * In derived classes with a overriding OnActivate function, + * do not forget to call this EDA_DRAW_FRAME::OnActivate( event ) basic function. + */ + virtual void OnActivate( wxActivateEvent& event ); + + /** + * Function UpdateStatusBar + * updates the status bar information. + * + * The base method updates the absolute and relative coordinates and the + * zoom information. If you override this virtual method, make sure to call + * this subclassed method. The status bar can draw itself. This is not + * a drawing function per se, but rather updates lines of text held by + * the components within the status bar which is owned by the wxFrame. + *

+ * On a MAC, be careful about calling this function when there is an + * existing wxDC in existence on a sibling window. + */ + virtual void UpdateStatusBar(); + + /** + * Function DisplayUnitsMsg + * displays current unit pane on the status bar. + */ + void DisplayUnitsMsg(); + + /* Handlers for block commands */ + virtual void InitBlockPasteInfos(); + + /** + * Function HandleBlockBegin + * initializes the block command including the command type, initial position, + * and other variables. + */ + virtual bool HandleBlockBegin( wxDC* aDC, int aKey, const wxPoint& aPosition ); + + /** + * Function BlockCommand + * Returns the block command code (BLOCK_MOVE, BLOCK_COPY...) corresponding to the + * keys pressed (ALT, SHIFT, SHIFT ALT ..) when block command is started by dragging + * the mouse. + * + * @param aKey = the key modifiers (Alt, Shift ...) + * @return the block command id (BLOCK_MOVE, BLOCK_COPY...) + */ + virtual int BlockCommand( int aKey ); + + /** + * Function HandleBlockPlace( ) + * Called after HandleBlockEnd, when a block command needs to be + * executed after the block is moved to its new place + * (bloc move, drag, copy .. ) + * Parameters must be initialized in GetScreen()->m_BlockLocate + */ + virtual void HandleBlockPlace( wxDC* DC ); + + /** + * Function HandleBlockEnd( ) + * Handle the "end" of a block command, + * i.e. is called at the end of the definition of the area of a block. + * depending on the current block command, this command is executed + * or parameters are initialized to prepare a call to HandleBlockPlace + * in GetScreen()->m_BlockLocate + * @return false if no item selected, or command finished, + * true if some items found and HandleBlockPlace must be called later + */ + virtual bool HandleBlockEnd( wxDC* DC ); + + /** + * Function CopyToClipboard + * copies the current page or the current block to the clipboard. + */ + void CopyToClipboard( wxCommandEvent& event ); + + /* interprocess communication */ + void OnSockRequest( wxSocketEvent& evt ); + void OnSockRequestServer( wxSocketEvent& evt ); + + void LoadSettings( wxConfigBase* aCfg ); // override virtual + + void SaveSettings( wxConfigBase* aCfg ); // override virtual + + /** + * Append a message to the message panel. + * + * This helper method checks to make sure the message panel exists in + * the frame and appends a message to it using the message panel + * AppendMessage() method. + * + * @param textUpper - The message upper text. + * @param textLower - The message lower text. + * @param color - A color ID from the KiCad color list (see colors.h). + * @param pad - Number of spaces to pad between messages (default = 4). + */ + void AppendMsgPanel( const wxString& textUpper, const wxString& textLower, + EDA_COLOR_T color, int pad = 6 ); + + /** + * Clear all messages from the message panel. + */ + void ClearMsgPanel( void ); + + /** + * Function SetMsgPanel + * clears the message panel and populates it with the contents of \a aList. + * + * @param aList is the list of #MSG_PANEL_ITEM objects to fill the message panel. + */ + void SetMsgPanel( const std::vector< MSG_PANEL_ITEM >& aList ); + + void SetMsgPanel( EDA_ITEM* aItem ); + + /** + * Function PrintPage + * used to print a page + * Print the page pointed by current screen, set by the calling print function + * @param aDC = wxDC given by the calling print function + * @param aPrintMask = not used here + * @param aPrintMirrorMode = not used here (Set when printing in mirror mode) + * @param aData = a pointer on an auxiliary data (not always used, NULL if not used) + */ + virtual void PrintPage( wxDC* aDC, LAYER_MSK aPrintMask, bool aPrintMirrorMode, void* aData = NULL ); + + /** + * Function CoordinateToString + * is a helper to convert the \a integer coordinate \a aValue to a string in inches or mm + * according to the current user units setting. + * @param aValue The coordinate to convert. + * @param aConvertToMils Convert inch values to mils if true. This setting has no effect if + * the current user unit is millimeters. + * @return The converted string for display in user interface elements. + */ + wxString CoordinateToString( int aValue, bool aConvertToMils = false ) const; + + /** + * Function LengthDoubleToString + * is a helper to convert the \a double value \a aValue to a string in inches or mm + * according to the current user units setting. + * @param aValue The coordinate to convert. + * @param aConvertToMils Convert inch values to mils if true. This setting has no effect if + * the current user unit is millimeters. + * @return The converted string for display in user interface elements. + */ + wxString LengthDoubleToString( double aValue, bool aConvertToMils = false ) const; + + /** + * Function UseGalCanvas + * used to switch between standard and GAL-based canvas. + * + * @param aEnable True for GAL-based canvas, false for standard canvas. + */ + virtual void UseGalCanvas( bool aEnable ); + + /** + * Function IsGalCanvasActive + * is used to check which canvas (GAL-based or standard) is currently in use. + * + * @return True for GAL-based canvas, false for standard canvas. + */ + bool IsGalCanvasActive() const { return m_galCanvasActive; } + void SetGalCanvasActive( bool aState ) { m_galCanvasActive = aState; } + + /** + * Function GetGalCanvas + * returns a pointer to GAL-based canvas of given EDA draw frame. + * + * @return Pointer to GAL-based canvas. + */ + EDA_DRAW_PANEL_GAL* GetGalCanvas() const { return m_galCanvas; } + void SetGalCanvas( EDA_DRAW_PANEL_GAL* aPanel ) { m_galCanvas = aPanel; } + + DECLARE_EVENT_TABLE() +}; + +#endif // EDA_DRAW_FRAME_H_ diff --git a/include/drawtxt.h b/include/drawtxt.h index b2d898e99a..d830f164c5 100644 --- a/include/drawtxt.h +++ b/include/drawtxt.h @@ -50,11 +50,11 @@ int Clamp_Text_PenSize( int aPenSize, wxSize aSize, bool aBold = true ); int GetPenSizeForBold( int aTextSize ); /** - * Function ReturnGraphicTextWidth + * Function GraphicTextWidth * @return the X size of the graphic text - * the full X size is ReturnGraphicTextWidth + the thickness of graphic lines + * the full X size is GraphicTextWidth + the thickness of graphic lines */ -int ReturnGraphicTextWidth( const wxString& aText, int size_h, bool italic, bool bold ); +int GraphicTextWidth( const wxString& aText, int size_h, bool italic, bool bold ); /** * Function NegableTextLength diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 5ce7d5236f..a4c7c020d7 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -30,11 +30,9 @@ #include #include #include - - +#include #define FP_LATE_ENVVAR 1 ///< late=1/early=0 environment variable expansion -#define KISYSMOD "KISYSMOD" class wxFileName; class OUTPUTFORMATTER; @@ -42,7 +40,7 @@ class MODULE; class FP_LIB_TABLE_LEXER; class NETLIST; class REPORTER; - +class SEARCH_STACK; /** * Class FP_LIB_TABLE @@ -85,7 +83,7 @@ class REPORTER; * * @author Wayne Stambaugh */ -class FP_LIB_TABLE +class FP_LIB_TABLE : public PROJECT::_ELEM { friend class DIALOG_FP_LIB_TABLE; @@ -271,6 +269,13 @@ public: */ FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable = NULL ); + /// Delete all rows. + void Clear() + { + rows.clear(); + nickIndex.clear(); + } + bool operator==( const FP_LIB_TABLE& r ) const { if( rows.size() == r.rows.size() ) @@ -496,27 +501,9 @@ public: */ bool IsEmpty( bool aIncludeFallback = true ); - /** - * Function MissingLegacyLibs - * tests the list of \a aLibNames by URI to determine if any of them are missing from - * the #FP_LIB_TABLE. - * - * @note The missing legacy footprint library test is performed by using old library - * file path lookup method. If the library is found, it is compared against all - * of the URIs in the table rather than the nickname. This was done because the - * user could change the nicknames from the default table. Using the full path - * is more reliable. - * - * @param aLibNames is the list of legacy library names. - * @param aErrorMsg is a pointer to a wxString object to store the URIs of any missing - * legacy library paths. Can be NULL. - * @return true if there are missing legacy libraries. Otherwise false. - */ - bool MissingLegacyLibs( const wxArrayString& aLibNames, wxString* aErrorMsg = NULL ); - /** * Function ConvertFromLegacy - * converts the footprint names in \a aNetList from the legacy fromat to the #FPID format. + * converts the footprint names in \a aNetList from the legacy format to the #FPID format. * * @param aNetList is the #NETLIST object to convert. * @param aLibNames is the list of legacy footprint library names from the currently loaded @@ -524,11 +511,11 @@ public: * @param aReporter is the #REPORTER object to dump messages into. * @return true if all footprint names were successfully converted to a valid FPID. */ - bool ConvertFromLegacy( NETLIST& aNetList, const wxArrayString& aLibNames, - REPORTER* aReporter = NULL ) throw( IO_ERROR ); + bool ConvertFromLegacy( SEARCH_STACK& aSStack, NETLIST& aNetList, + const wxArrayString& aLibNames, REPORTER* aReporter = NULL ) throw( IO_ERROR ); /** - * Function ExpandEnvSubsitutions + * Function ExpandSubstitutions * replaces any environment variable references with their values and is * here to fully embellish the ROW::uri in a platform independent way. * This enables (fp_lib_table)s to have platform dependent environment @@ -561,16 +548,7 @@ public: * Function GetFileName * @return the footprint library file name. */ - static const wxString& GetFileName(); - - static void SetProjectPathEnvVariable( const wxFileName& aPath ); - - /** - * Function ProjectPathEnvVarVariableName - * returns the name of the environment variable used to hold the directory of - * the current project on program startup. - */ - static const wxString ProjectPathEnvVariableName(); + static const wxString GetFileName(); /** * Function GlobalPathEnvVarVariableName @@ -582,7 +560,7 @@ public: */ static const wxString GlobalPathEnvVariableName(); - static wxString GetProjectFileName( const wxFileName& aPath ); + static wxString GetProjectTableFileName( const wxString& aProjectFullName ); /** * Function Load @@ -640,4 +618,7 @@ protected: FP_LIB_TABLE* fallBack; }; + +extern FP_LIB_TABLE GFootprintTable; // KIFACE scope. + #endif // FP_LIB_TABLE_H_ diff --git a/include/gestfich.h b/include/gestfich.h index 4d6403e29d..324a767eb0 100644 --- a/include/gestfich.h +++ b/include/gestfich.h @@ -112,7 +112,7 @@ void AddDelimiterString( wxString& string ); wxString FindKicadHelpPath(); /** - * Function ReturnKicadDatasPath + * Function KicadDatasPath * returns the data path common to KiCad. * If environment variable KICAD is defined (KICAD = path to kicad) * Returns \ /; @@ -122,7 +122,7 @@ wxString FindKicadHelpPath(); * Note: * The \\ are replaced by / (a la Unix) */ -wxString ReturnKicadDatasPath(); +wxString KicadDatasPath(); /** * Function FindKicadFile diff --git a/include/hotkey_grid_table.h b/include/hotkey_grid_table.h index 8856a18520..27fbbcfb9c 100644 --- a/include/hotkey_grid_table.h +++ b/include/hotkey_grid_table.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/include/hotkeys_basic.h b/include/hotkeys_basic.h index f070441de4..fe1715f448 100644 --- a/include/hotkeys_basic.h +++ b/include/hotkeys_basic.h @@ -113,7 +113,7 @@ void AddHotkeyConfigMenu( wxMenu* menu ); void HandleHotkeyConfigMenuSelection( EDA_DRAW_FRAME* frame, int id ); /** - * Function ReturnKeyNameFromKeyCode + * Function KeyNameFromKeyCode * return the key name from the key code * * Only some wxWidgets key values are handled for function key ( see * s_Hotkey_Name_List[] ) @@ -121,27 +121,27 @@ void HandleHotkeyConfigMenuSelection( EDA_DRAW_FRAME* frame, int id ); * @param aIsFound = a pointer to a bool to return true if found, or false. an be NULL default) * @return the key name in a wxString */ -wxString ReturnKeyNameFromKeyCode( int aKeycode, bool * aIsFound = NULL ); +wxString KeyNameFromKeyCode( int aKeycode, bool * aIsFound = NULL ); /** - * Function ReturnKeyNameFromCommandId + * Function KeyNameFromCommandId * return the key name from the Command id value ( m_Idcommand member value) * @param aList = pointer to a EDA_HOTKEY list of commands * @param aCommandId = Command Id value * @return the key name in a wxString */ -wxString ReturnKeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ); +wxString KeyNameFromCommandId( EDA_HOTKEY** aList, int aCommandId ); /** - * Function ReturnKeyCodeFromKeyName + * Function KeyCodeFromKeyName * return the key code from its key name * Only some wxWidgets key values are handled for function key * @param keyname = wxString key name to find in s_Hotkey_Name_List[], * like F2 or space or an usual (ascii) char. * @return the key code */ -int ReturnKeyCodeFromKeyName( const wxString& keyname ); +int KeyCodeFromKeyName( const wxString& keyname ); /* An helper enum for AddHotkeyName function * In menus we can an a hot key, or an accelerator , or sometimes just a comment diff --git a/include/import_export.h b/include/import_export.h index eed48fb797..57de9f9ef7 100644 --- a/include/import_export.h +++ b/include/import_export.h @@ -24,7 +24,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -// macros which export functions from a DLL/DSO. + +/// Macros which export functions from a DLL/DSO. +/// See: http://gcc.gnu.org/wiki/Visibility #if defined(__MINGW32__) #define APIEXPORT __declspec(dllexport) @@ -32,6 +34,7 @@ #define APILOCAL #elif defined(__GNUC__) && __GNUC__ >= 4 + // On ELF, we compile with hidden visibility, so unwrap that for specific symbols: #define APIEXPORT __attribute__ ((visibility("default"))) #define APIIMPORT __attribute__ ((visibility("default"))) #define APILOCAL __attribute__ ((visibility("hidden"))) @@ -44,8 +47,9 @@ #endif -#if defined(test_EXPORTS) || defined(COMPILING_DLL) - // above defined by CMake magically when compiling implementation. +#if defined(COMPILING_DLL) + // Be sure and define COMPILING_DLL when compiling implementation, and NOT when + // compiling the client. #define MY_API(rettype) APIEXPORT rettype #else #define MY_API(rettype) APIIMPORT rettype diff --git a/include/kiface_i.h b/include/kiface_i.h new file mode 100644 index 0000000000..b0b455f971 --- /dev/null +++ b/include/kiface_i.h @@ -0,0 +1,141 @@ +#ifndef KIFACE_I_H_ +#define KIFACE_I_H_ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 1992-2014 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include + + +/** + * Class KIFACE_I + * is a KIFACE (I)mplementation, + * with some features useful for DSOs which implement a KIFACE. + * It is abstract, a few functions must be implemented in derivations. + */ +class KIFACE_I : public KIFACE +{ +public: + + //--------------------------------------------------------------- + + // see base class KIFACE in kiway.h for doxygen docs + + VTBL_ENTRY bool OnKifaceStart( PGM_BASE* aProgram ) = 0; + /* + { + typically call start_common() in your overload + return start_common(); + } + */ + + VTBL_ENTRY void OnKifaceEnd() + { + // overload this if you want, end_common() may be handy. + end_common(); + } + + VTBL_ENTRY wxWindow* CreateWindow( wxWindow* aParent, + int aClassId, KIWAY* aKIWAY, int aCtlBits = 0 ) = 0; + + VTBL_ENTRY void* IfaceOrAddress( int aDataId ) = 0; + + //-------------------------------------------------------------- + + // The remainder are DSO specific helpers, not part of the KIFACE API + + /** + * Constructor + * + * @param aKifaceName should point to a C string in permanent storage, + * which contains the name of the DSO. Examples: "eeschema", "pcbnew", etc. + * This controls the name of the wxConfigBase established in m_kiway_settings, + * so it should be lowercase. + */ + KIFACE_I( const char* aKifaceName, KIWAY::FACE_T aId ) : + m_id( aId ), + m_bm( aKifaceName ) + { + } + + // ~KIFACE_I(); + +protected: + + /// Common things to do for a top program module, during OnKifaceStart(). + bool start_common(); + + /// Common things to do for a top program module, during OnKifaceEnd(); + void end_common(); + + // From here down should probably not be in a KIFACE, even though they + // are DSO specific, they have nothing to do with KIWAY's use of KIFACE, + // so its a questionable choice to put non KIWAY client code in this class. + +public: + + const wxString Name() { return wxString::FromUTF8( m_bm.m_name ); } + + wxConfigBase* KifaceSettings() const { return m_bm.m_config; } + + const wxString& GetHelpFileName() const { return m_bm.m_help_file; } + void SetHelpFileName( const wxString& aFileName ) { m_bm.m_help_file = aFileName; } + + /** + * Function GetHelpFile + * gets the help file path. + *

+ * Return the KiCad help file with path. The base paths defined in + * m_searchPaths are tested for a valid file. The path returned can + * be relative depending on the paths added to m_searchPaths. See the + * documentation for wxPathList for more information. If the help file + * for the current locale is not found, an attempt to find the English + * version of the help file is made. + * wxEmptyString is returned if help file not found. + * Help file is searched in directories in this order: + * help/\ like help/en_GB + * help/\ like help/en + * help/en + *

+ */ + wxString GetHelpFile(); + + wxFileHistory& GetFileHistory() { return m_bm.m_history; } + + /// Only for DSO specific 'non-library' files. + /// (The library search path is in the PROJECT class.) + SEARCH_STACK& KifaceSearch() { return m_bm.m_search; } + +private: + KIWAY::FACE_T m_id; + + BIN_MOD m_bm; +}; + + +/// Global KIFACE_I "get" accessor. +KIFACE_I& Kiface(); + +#endif // KIFACE_I_H_ diff --git a/include/kiway.h b/include/kiway.h index efef894340..dd83cc93f7 100644 --- a/include/kiway.h +++ b/include/kiway.h @@ -99,21 +99,18 @@ as such! As such, it is OK to use UTF8 characters: #include #include #include +#include +#include #define VTBL_ENTRY virtual -#define KIFACE_VERSION 1 -#define KIFACE_GETTER KIFACE_1 +#define KIFACE_VERSION 1 +#define KIFACE_GETTER KIFACE_1 // The KIFACE acquistion function is declared extern "C" so its name should not -// be mangled (much). Windows has leading underscore for our C function. -// Keep the trailing version number in sync with the KIFACE_GETTER define above. -#if defined(__MINGW32__) - #define KIFACE_INSTANCE_NAME_AND_VERSION "_KIFACE_1" -#else - #define KIFACE_INSTANCE_NAME_AND_VERSION "KIFACE_1" -#endif +// be mangled. +#define KIFACE_INSTANCE_NAME_AND_VERSION "KIFACE_1" #if defined(__linux__) @@ -127,40 +124,17 @@ as such! As such, it is OK to use UTF8 characters: #endif -/** - * Class PROJECT - * holds project specific data. Because it is in the neutral program top, which - * is not linked to by subsidiarly DSOs, any functions in this interface must - * be VTBL_ENTRYs. - */ -class PROJECT -{ - -public: - -#if 0 - /// Derive PROJECT elements from this, it has a virtual destructor, and - /// Elem*() functions can work with it. - class ELEM_BASE - { - public: - virtual ~ELEM_BASE() {} - }; - - VTBL_ENTRY int ElemAllocNdx(); - VTBL_ENTRY void ElemSet( int aIndex, ELEMENT_BASE* aBlock ); - VTBL_ENTRY ELEM_BASE* ElemGet( int aIndex ) -#endif -}; +class wxConfigBase; class KIWAY; class wxWindow; -class wxApp; +class PGM_BASE; +class wxConfigBase; /** - * Struct KIFACE + * Class KIFACE * is used by a participant in the KIWAY alchemy. KIWAY is a minimalistic * software bus for communications between various DLLs/DSOs (DSOs) within the same * KiCad process. It makes it possible to call between DSOs without having to link @@ -173,36 +147,72 @@ class wxApp; */ struct KIFACE { - // Do not change the order of functions in this listing, add new ones at - // the end, unless you recompile all of KiCad. + // The order of functions establishes the vtable sequence, do not change the + // order of functions in this listing unless you recompile all clients of + // this interface. + + /** + * Function OnKifaceStart + * is called just once shortly after the DSO is loaded. It is the second + * function called, immediately after the KIFACE_GETTER(). However before + * either of those, static C++ constructors are called. The DSO implementation + * should do process level initialization here, not project specific since there + * will be multiple projects open eventually. + * + * @param aProcess is the process block: PGM_BASE* + * + * @return bool - true if DSO initialized OK, false if not. When returning + * false, the loader may optionally decide to terminate the process or not, + * but will not put out any UI because that is the duty of this function to say + * why it is returning false. Never return false without having reported + * to the UI why. + */ + VTBL_ENTRY bool OnKifaceStart( PGM_BASE* aProgram ) = 0; + + /** + * Function OnKifaceEnd + * is called just once just before the DSO is to be unloaded. It is called + * before static C++ destructors are called. A default implementation is supplied. + * + * @param aProcess is the process block: PGM_BASE* + */ + VTBL_ENTRY void OnKifaceEnd() = 0; #define KFCTL_STANDALONE (1<<0) ///< Am running as a standalone Top. /** * Function CreateWindow - * creates a wxTopLevelWindow for the current project. The caller + * creates a wxWindow for the current project. The caller * must cast the return value into the known type. * - * @param aClassId identifies which wxFrame or wxDialog to retrieve. + * @param aParent may be NULL, or is otherwise the parent to connect under. If NULL + * then caller may want to connect the returned wxWindow into some hierarchy after + * this function returns. + * + * @param aClassId identifies which wxFrame or wxDialog to retrieve, using a value + * known to the implementing KIFACE. * * @param aKIWAY tells the window which KIWAY (and PROJECT) it is a participant in. * - * @param aCtlBits consists of bit flags from the set KFCTL_* #defined above. + * @param aCtlBits consists of bit flags from the set of KFCTL_* #defines above. * - * @return wxWindow* - and if not NULL, should be cast into the known type. + * @return wxWindow* - and if not NULL, should be cast into the known type using + * dynamic_cast<>(). */ - VTBL_ENTRY wxWindow* CreateWindow( int aClassId, KIWAY* aKIWAY, int aCtlBits = 0 ) = 0; + VTBL_ENTRY wxWindow* CreateWindow( wxWindow* aParent, int aClassId, + KIWAY* aKIWAY, int aCtlBits = 0 ) = 0; /** * Function IfaceOrAddress - * return a pointer to the requested object. The safest way to use this + * returns a pointer to the requested object. The safest way to use this * is to retrieve a pointer to a static instance of an interface, similar to * how the KIFACE interface is exported. But if you know what you are doing - * use it to retrieve anything you want. + * use it to retrieve anything you want. Segfaults are your fault. * - * @param aDataId identifies which object you want the address of. + * @param aDataId identifies which object you want the address of, and consists + * of choices known in advance by the implementing KIFACE. * - * @return void* - and must be cast into the know type. + * @return void* - and must be cast into the known type. */ VTBL_ENTRY void* IfaceOrAddress( int aDataId ) = 0; }; @@ -213,17 +223,23 @@ struct KIFACE * is a minimalistic software bus for communications between various * DLLs/DSOs (DSOs) within the same KiCad process. It makes it possible * to call between DSOs without having to link them together, and without - * having to link to the top process module which houses the KIWAY(s). It also - * makes it possible to send custom wxEvents between DSOs and from the top + * having to link to the top process module which houses the KIWAY(s). More importantly + * it makes it possible to send custom wxEvents between DSOs and from the top * process module down into the DSOs. The latter capability is thought useful * for driving the lower DSOs from a python test rig or for demo (automaton) purposes. *

- * Most all calls are via virtual functions which means C++ vtables + * Most all calls are via virtual functions, which means C++ vtables * are used to hold function pointers and eliminate the need to link to specific * object code libraries, speeding development and encouraging clearly defined - * interface design. There is one KIWAY in the launching portion of the process - * for each open KiCad project. Each project has its own KIWAY. Within a KIWAY - * is an actual PROJECT data structure. + * interface design. Unlike Microsoft COM, which is a multi-vendor design supporting + * DLL's built at various points in time. The KIWAY alchemy is single project, with + * all components being built at the same time. So one should expect solid compatibility + * between all KiCad components, as long at they are compiled at the same time. + *

+ * There is one KIWAY in the launching portion of the process + * for each open KiCad project. Each project has its own KIWAY. Available to + * each KIWAY is an actual PROJECT data structure. If you have a KIWAY, you + * can get to the PROJECT using KIWAY::Prj(). *

* In summary, a KIWAY facilitates communicating between DSOs, where the topic * of the communication is project specific. Here a "project" means a BOARD @@ -237,19 +253,38 @@ public: /// DSO players on *this* KIWAY enum FACE_T { - FACE_SCH, ///< _eeschema DSO + FACE_SCH, ///< eeschema DSO // FACE_LIB, - FACE_PCB, ///< _pcbnew DSO + FACE_PCB, ///< pcbnew DSO // FACE_MOD, + FACE_CVPCB, + FACE_BMP2CMP, + FACE_GERBVIEW, + FACE_PL_EDITOR, + FACE_PCB_CALCULATOR, - FACE_COUNT ///< how many KIWAY player types + FACE_COUNT, ///< how many KIWAY player types }; + /* from edaappl.h, now pgm_base.h, obsoleted by above FACE_T enum. + enum PGM_BASE_T + { + APP_UNKNOWN, + APP_EESCHEMA, + APP_PCBNEW, + APP_CVPCB, + APP_GERBVIEW, + APP_KICAD, + APP_PL_EDITOR, + APP_BM2CMP, + }; + */ + // Don't change the order of these VTBL_ENTRYs, add new ones at the end, // unless you recompile all of KiCad. VTBL_ENTRY KIFACE* KiFACE( FACE_T aFaceId, bool doLoad ); - VTBL_ENTRY PROJECT& Project(); + VTBL_ENTRY PROJECT& Prj() const; KIWAY(); @@ -261,11 +296,11 @@ private: // one for each FACE_T static wxDynamicLibrary s_sch_dso; static wxDynamicLibrary s_pcb_dso; - //static wxDynamicLibrary s_cvpcb_dso; // will get merged into pcbnew + //static wxDynamicLibrary s_cvpcb_dso; // will get merged into pcbnew KIFACE* m_dso_players[FACE_COUNT]; - PROJECT m_project; + PROJECT m_project; // do not assume this is here, use Prj(). }; @@ -280,12 +315,12 @@ private: * * @param aKIFACEversion is where to put the API version implemented by the KIFACE. * @param aKIWAYversion tells the KIFACE what KIWAY version will be available. - * @param aProcess is a pointer to the basic wxApp for this process. + * @param aProcess is a pointer to the PGM_BASE for this process. * @return KIFACE* - unconditionally. */ -typedef KIFACE* KIFACE_GETTER_FUNC( int* aKIFACEversion, int aKIWAYversion, wxApp* aProcess ); +typedef KIFACE* KIFACE_GETTER_FUNC( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram ); /// No name mangling. Each TOPMOD will implement this once. -extern "C" KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, wxApp* aProcess ); +extern "C" KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram ); #endif // KIWAY_H_ diff --git a/include/kiway_player.h b/include/kiway_player.h new file mode 100644 index 0000000000..1798b1ba56 --- /dev/null +++ b/include/kiway_player.h @@ -0,0 +1,160 @@ +#ifndef KIWAY_PLAYER_H_ +#define KIWAY_PLAYER_H_ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2014 KiCad Developers, see change_log.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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + + +class KIWAY; +class PROJECT; +struct KIFACE; +class KIFACE_I; + + +/** + * Class KIWAY_HOLDER + * is a mix in class which holds the location of a wxWindow's KIWAY. It allows + * calls to Kiway() and SetKiway(). + * + * Known to be used in at least DIALOG_SHIM and KIWAY_PLAYER classes. + */ +class KIWAY_HOLDER +{ +public: + KIWAY_HOLDER( KIWAY* aKiway ) : + m_kiway( aKiway ) + {} + + /** + * Function Kiway + * returns a reference to the KIWAY that this object has an opportunity + * to participate in. A KIWAY_HOLDER is not necessarily a KIWAY_PLAYER. + */ + KIWAY& Kiway() const + { + wxASSERT( m_kiway ); // smoke out bugs in Debug build, then Release runs fine. + return *m_kiway; + } + + /** + * Function Prj + * returns a reference to the PROJECT "associated with" this KIWAY. + */ + PROJECT& Prj() const; // coded in kiface_i.cpp for now + + /** + * Function SetKiway + * + * @param aDest is the recipient of aKiway pointer. + * It is only used for debugging, since "this" is not a wxWindow*. "this" is + * a KIWAY_HOLDER mix-in. + * + * @param aKiway is often from a parent window, or from KIFACE::CreateWindow(). + */ + void SetKiway( wxWindow* aDest, KIWAY* aKiway ); // in kiface_i.cpp for now + +private: + // private, all setting is done through SetKiway(). + KIWAY* m_kiway; // no ownership. +}; + + +/** + * Class KIWAY_PLAYER + * is a wxFrame capable of the OpenProjectFiles function, meaning it can load + * a portion of a KiCad project. Because this class provides a dummy implementation, + * it is not a certainty that all classes which inherit from this clas intend to + * participate in a KIWAY. Those that do must actually interact with the provided + * KIWAY*. + *

+ * EDA_BASE_FRAME would not have sufficed because BM2CMP_FRAME_BASE is not + * derived from it. + */ +class KIWAY_PLAYER : public EDA_BASE_FRAME, public KIWAY_HOLDER +{ +public: + KIWAY_PLAYER( KIWAY* aKiway, wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, + const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, + long aStyle, const wxString& aWdoName = wxFrameNameStr ) : + EDA_BASE_FRAME( aParent, aFrameType, aTitle, aPos, aSize, aStyle, aWdoName ), + KIWAY_HOLDER( aKiway ) + {} + + /// Don't use this one, only wxformbuilder uses it, and it must be augmented with + /// a SetKiway() early in derived constructor. + KIWAY_PLAYER( wxWindow* aParent, wxWindowID aId, const wxString& aTitle, + const wxPoint& aPos, const wxSize& aSize, long aStyle, + const wxString& aWdoName = wxFrameNameStr ) : + EDA_BASE_FRAME( aParent, (ID_DRAWFRAME_TYPE) aId, aTitle, aPos, aSize, aStyle, aWdoName ), + KIWAY_HOLDER( 0 ) + {} + + + // For the aCtl argument of OpenProjectFiles() +#define KICTL_OPEN_APPEND (1<<0) ///< append the data file, rather than replace +#define KICTL_EAGLE_BRD (1<<1) ///< chosen *.brd file is Eagle according to user. + + /** + * Function OpenProjectFiles + * is abstract, and opens a project or set of files given by @a aFileList. + * This is generalized in the direction of worst case. In a typical case + * @a aFileList will only hold a single file, like "myboard.kicad_pcb", + * because any KIWAY_PLAYER is only in one KIWAY and the KIWAY owns the + * PROJECT. Therefore opening files from multiple projects into the same + * KIWAY_PLAYER is precluded. + *

+ * Each derived class should handle this in a way specific to its needs. + * No prompting is done inside here for any file or project. There is no + * need to call this with aFileList which is empty. + *

+ * After loading the window should update its Title as part of this operation. + * If the KIWAY_PLAYER needs to, it can load the *.pro file as part of this operation. + *

+ * If the KIWAY_PLAYER cannot load any of the file(s) in the list, then it + * should say why through some GUI interface, and return false. + * + * @param aFileList includes files that this frame should open + * according to the knowledge in the derived wxFrame. In almost every case, + * the list will have only a single file in it. + * + * @return bool - true if all requested files were opened OK, else false. + */ + virtual bool OpenProjectFiles( const std::vector& aFileList, int aCtl = 0 ) + { + // overload me for your wxFrame type. + + // Any overload should probably do this also: + // Prj().MaybeLoadProjectSettings(); + + // Then update the window title. + + return false; + } +}; + +#endif // KIWAY_PLAYER_H_ diff --git a/include/layers_id_colors_and_visibility.h b/include/layers_id_colors_and_visibility.h index d421e6cf4e..196cb54cd1 100644 --- a/include/layers_id_colors_and_visibility.h +++ b/include/layers_id_colors_and_visibility.h @@ -358,7 +358,7 @@ inline bool IsBackLayer( LAYER_NUM aLayer ) } /** - * Function ReturnFlippedLayerNumber + * Function FlippedLayerNumber * @return the layer number after flipping an item * some (not all) layers: external copper, Mask, Paste, and solder * are swapped between front and back sides diff --git a/include/pgm_base.h b/include/pgm_base.h new file mode 100644 index 0000000000..096ff2e3ee --- /dev/null +++ b/include/pgm_base.h @@ -0,0 +1,270 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com + * Copyright (C) 2008-2011 Wayne Stambaugh + * Copyright (C) 1992-2011 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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file pgm_base.h + * @brief see class PGM_BASE + */ + +#ifndef PGM_BASE_H_ +#define PGM_BASE_H_ + +#include +#include +#include + + +class wxConfigBase; +class wxSingleInstanceChecker; +class wxHtmlHelpController; +class wxApp; +class wxMenu; + +// inter program module calling +#define VTBL_ENTRY virtual + + +/** + * Class PGM_BASE + * keeps program (whole process) data for KiCad programs. + * The VTBL_ENTRY functions are VTBL_ENTRY so we can do cross module calls + * without linking to them. This used to be a wxApp derivative, but that + * is difficult under wxPython which shapes the wxApp. So now this is a "side-car" + * (like a motorcycle side-car) object with a back pointer into the wxApp + * which initializes it. + *

+ * OnPgmStart() is virtual, may be overridden, and parallels + * wxApp::OnInit(), from where it should called. + *

+ * OnPgmEnd() is virtual, may be overridden, and parallels wxApp::OnExit(), + * from where it should be called. + */ +class PGM_BASE +{ +public: + PGM_BASE(); + ~PGM_BASE(); + + /** + * Function OnPgmInit + * this is the first executed function (like main() ) + * @return true if the application can be started. + */ + virtual bool OnPgmInit( wxApp* aWxApp ) = 0; // call this from wxApp::OnInit() + + virtual void OnPgmExit() = 0; // call this from wxApp::OnExit() + + /** + * Function MacOpenFile + * is specific to MacOSX (not used under Linux or Windows). + * MacOSX requires it for file association. + * @see http://wiki.wxwidgets.org/WxMac-specific_topics + */ + virtual void MacOpenFile( const wxString& aFileName ) = 0; + + //--------------------------------------------------------- + + VTBL_ENTRY wxHtmlHelpController* GetHtmlHelpController() { return m_html_ctrl; } + + VTBL_ENTRY void SetHtmlHelpController( wxHtmlHelpController* aController ); + + VTBL_ENTRY wxConfigBase* CommonSettings() const { return m_common_settings; } + + VTBL_ENTRY void SetEditorName( const wxString& aFileName ); + + /** + * Return the preferred editor name. + */ + VTBL_ENTRY const wxString& GetEditorName(); + + VTBL_ENTRY bool IsKicadEnvVariableDefined() const { return !m_kicad_env.IsEmpty(); } + + VTBL_ENTRY const wxString& GetKicadEnvVariable() const { return m_kicad_env; } + + VTBL_ENTRY const wxString& GetExecutablePath() const { return m_bin_dir; } + + VTBL_ENTRY wxLocale* GetLocale() { return m_locale; } + + VTBL_ENTRY const wxString& GetPdfBrowserName() const { return m_pdf_browser; } + + VTBL_ENTRY void SetPdfBrowserName( const wxString& aFileName ) { m_pdf_browser = aFileName; } + + VTBL_ENTRY bool UseSystemPdfBrowser() const { return m_pdf_browser.IsEmpty(); } + + /** + * Function SetLanguage + * sets the dictionary file name for internationalization. + *

+ * The files are in kicad/internat/xx or kicad/internat/xx_XX and are named kicad.mo + *

+ * @param first_time must be set to true the first time this funct is + * called, false otherwise + * @return true if the language can be set (i.e. if the locale is available) + */ + VTBL_ENTRY bool SetLanguage( bool first_time = false ); + + /** + * Function AddMenuLanguageList + * creates a menu list for language choice, and add it as submenu to \a MasterMenu. + * + * @param MasterMenu The main menu. The sub menu list will be accessible from the menu + * item with id ID_LANGUAGE_CHOICE + */ + VTBL_ENTRY void AddMenuLanguageList( wxMenu* MasterMenu ); + + /** + * Function SetLanguageIdentifier + * sets in .m_language_id member the wxWidgets language identifier Id from + * the KiCad menu id (internal menu identifier). + * + * @param menu_id The KiCad menuitem id (returned by Menu Event, when + * clicking on a menu item) + */ + VTBL_ENTRY void SetLanguageIdentifier( int menu_id ); + + VTBL_ENTRY void SetLanguagePath(); + + /** + * Function InitOnLineHelp + * initializes KiCad's online help. + */ + VTBL_ENTRY void InitOnLineHelp(); + + /** + * Function ReadPdfBrowserInfos + * reads the PDF browser choice from the common configuration. + */ + VTBL_ENTRY void ReadPdfBrowserInfos(); + + /** + * Function WritePdfBrowserInfos + * saves the PDF browser choice to the common configuration. + */ + VTBL_ENTRY void WritePdfBrowserInfos(); + + /** + * Function LockFile + * marks a file as being in use. + * @param aFileName = full path to the file. + * @return false if the file was already locked, true otherwise. + */ + VTBL_ENTRY bool LockFile( const wxString& aFileName ); + + /** + * Function App + * returns a bare naked wxApp, which may come from wxPython, SINGLE_TOP, or kicad.exe. + * Use this function instead of wxGetApp(). + */ + VTBL_ENTRY wxApp& App() + { + wxASSERT( m_wx_app ); + return *m_wx_app; + } + + //-------------------------------------------------------- + + static const wxChar workingDirKey[]; + +protected: + + /** + * Function initPgm + * initializes this program (process) in a KiCad standard way, + * using some generalized techniques. + * - Default paths (help, libs, bin) and configuration file names + * - Language and locale + * - fonts + *

+ * But nothing relating to DSOs or projects. + * @return bool - true if success, false if failure and program is to terminate. + */ + bool initPgm(); + + /** + * Function loadCommonSettings + * loads the program (process) settings subset which are stored in .kicad_common + */ + void loadCommonSettings(); + + /** + * Function saveCommonSettings + * saves the program (process) settings subset which are stored .kicad_common + */ + void saveCommonSettings(); + + /// prevents multiple instances of a program from being run at the same time. + wxSingleInstanceChecker* m_pgm_checker; + + /// prevents opening the same file multiple times. + wxSingleInstanceChecker* m_file_checker; + + /// Configuration settings common to all KiCad program modules, + /// like as in $HOME/.kicad_common + wxConfigBase* m_common_settings; + + /// full path to this program + wxString m_bin_dir; + + /// The KICAD system environment variable. + wxString m_kicad_env; + + /// The current locale. + wxLocale* m_locale; + + /// The current language setting. + int m_language_id; + + /// Trap all changes in here, simplifies debugging + void setLanguageId( int aId ) { m_language_id = aId; } + + /** + * Function setExecutablePath + * finds the path to the executable and stores it in PGM_BASE::m_bin_dir + * @return bool - true if success, else false. + */ + bool setExecutablePath(); + + /// The file name of the the program selected for browsing pdf files. + wxString m_pdf_browser; + wxString m_editor_name; + wxSize m_help_size; + + wxHtmlHelpController* m_html_ctrl; + + wxApp* m_wx_app; + + // The PGM_* classes can have difficulties at termination if they + // are not destroyed soon enough. Relying on a static destructor can be + // too late for contained objects like wxSingleInstanceChecker. + void destroy(); +}; + + +#if !defined(PGM_KICAD_H_) // PGM_KICAD has an alternate +/// The global Program "get" accessor. +extern PGM_BASE& Pgm(); +#endif + +#endif // PGM_BASE_H_ diff --git a/include/project.h b/include/project.h new file mode 100644 index 0000000000..a187aa5491 --- /dev/null +++ b/include/project.h @@ -0,0 +1,255 @@ +#ifndef PROJECT_H_ +#define PROJECT_H_ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +/// A variable name whose value holds the current project directory. +/// Currently an environment variable, eventually a project variable. +#define PROJECT_VAR_NAME wxT( "KIPRJMOD" ) + + +class wxConfigBase; +class PARAM_CFG_ARRAY; + + +#define VTBL_ENTRY virtual + +/** + * Class PROJECT + * holds project specific data. Because it is in the neutral program top, which + * is not linked to by subsidiarly DSOs, any functions in this interface must + * be VTBL_ENTRYs. + */ +class PROJECT +{ +public: + + /// Derive PROJECT elements from this, it has a virtual destructor, and + /// Elem*() functions can work with it. Implementation is opaque in + /// class PROJECT. If find you have to include derived class headers in this + /// file, you are doing something wrong. Keep knowledge of derived classes + /// opaque to class PROJECT please. + class _ELEM + { + public: + virtual ~_ELEM() {} + }; + + PROJECT(); + ~PROJECT(); + + // VTBL_ENTRY bool MaybeLoadProjectSettings( const std::vector& aFileSet ); + + /** + * Function SetProjectFullName + * sets the: + * 1) full directory, 2) basename, and 3) extension of the project. This is + * the name of the *.pro file with full absolute path and it also defines + * the name of the project. The project name and the *.pro file names are + * exactly the same, providing the *.pro filename is absolute. + */ + VTBL_ENTRY void SetProjectFullName( const wxString& aFullPathAndName ); + + /** + * Function GetProjectFullName + * returns the full path and name of the project. This is the same as the + * name of the *.pro file and will always be an absolute path. + */ + VTBL_ENTRY const wxString GetProjectFullName() const; + + /** + * Function ConfigSave + * saves the current "project" parameters into the wxConfigBase* derivative. + * Then the wxConfigBase derivative is written to the *.pro file for the project. + * + * @param aSearchS a SEARCH_STACK + * @param aFileName is where to save the *.pro file. + * @param aGroupName + * @param aParams is a ptr vector of PARAM_CFG_BASE derivatives. + * Saved parameters are the subset in this array having the .m_Setup member + * set to false. + */ + VTBL_ENTRY void ConfigSave( const SEARCH_STACK& aSearchS, const wxString& aFileName, + const wxString& aGroupName, const PARAM_CFG_ARRAY& aParams ); + + /** + * Function ConfigLoad + * reads a subset of parameters from the "project" file. Parameters are the + * subset of variables given in @a aParams array which have the .m_Setup member + * set to false. The file which is read in and then extracted from is the + * '*.pro' file for the project. + *

+ * set: + * m_pro_date_and_time + * m_pro_name + * + * @param aSearchS a SEARCH_STACK where a kicad.pro template file may be found. + * @param aLocalConfigFileName + * @param aGroupName + * @param aParams is ptr vector of PARAM_CFG_BASE derivatives. + * @param doLoadOnlyIfNew if true, then this file is read only if it differs from + * the current config on date (different dates), else the *.pro file is read and + * extracted from unconditionally. + * + * @return bool - true if loaded OK. + */ + VTBL_ENTRY bool ConfigLoad( const SEARCH_STACK& aSearchS, const wxString& aLocalConfigFileName, + const wxString& aGroupName, const PARAM_CFG_ARRAY& aParams, bool doLoadOnlyIfNew ); + + /// Accessor for Eeschema search stack. + VTBL_ENTRY SEARCH_STACK& SchSearchS() { return m_sch_search; } + + /** + * Function PcbSearchS + * returns the obsolete footprint library search stack. + * Projects created before the FP_LIB_TABLE support will have footprint + * search paths in the *.pro files. Projects created after the FP_LIB_TABLE + * support will not. This stack is used for conversion from old to new only. + */ + VTBL_ENTRY SEARCH_STACK& PcbSearchS() { return m_pcb_search; } + + VTBL_ENTRY wxString GetModuleLibraryNickname() { return m_module_library_nickname; } + VTBL_ENTRY void SetModuleLibraryNickname( const wxString& aNickName ) { m_module_library_nickname = aNickName; } + + /// Retain a number of paths for user convienience, enumerated here: + enum RETPATH_T + { + DOC, + SCH_LIB, + PCB_LIB, + VIEWER_3D, + + RPATH_COUNT + }; + + /// Give acess to a RETAINED_PATH using enum RETPATH_T + VTBL_ENTRY RETAINED_PATH& RPath( RETPATH_T aPath ); + + /** + * Enum ELEM_T + * is the set of _ELEMs that a PROJECT can hold. + */ + enum ELEM_T + { + FPTBL, + + ELEM_COUNT + }; + + /** + * A PROJECT can hold stuff it knows nothing about, in the form of + * _ELEM derivatives. This function gives access to a PROJECT::_ELEM using + * enum ELEM_T as an index. + *

+ * Acts as setter iff aElem is not NULL, else getter. + *

+ * Typically wrapped somewhere else in a more meaningful function wrapper. + * This is a cross module API, therefore the _ELEM destructor is virtual and + * can point to a destructor function in another link image. Be careful that + * that program module is resident at time of destruction. + *

+ * Summary: 1) cross module API, 2) PROJECT knows nothing about _ELEM objects, + * except how to delete them and set and get pointers to them. + */ + VTBL_ENTRY _ELEM* Elem( ELEM_T aIndex, _ELEM* aElem = NULL ); + +private: + + /** + * Function configCreate + * creates or recreates the KiCad project file and wxConfigBase: + * + * .pro + * + * @param aFilename is a local configuration file path and basename. + * + * Initializes ? + * G_Prj_Config + * G_Prj_Config_LocalFilename + * G_Prj_Default_Config_FullFilename + * : + */ + wxConfigBase* configCreate( const SEARCH_STACK& aSearchS, + const wxString& aFilename, const wxString& aGroupName, + bool aForceUseLocalConfig ); + + SEARCH_STACK m_sch_search; ///< Eeschema's search paths + SEARCH_STACK m_pcb_search; ///< Pcbnew's obsolete footprint search paths, see comment above. + + wxFileName m_project_name; ///< /.pro + wxString m_pro_date_and_time; + + wxString m_module_library_nickname; ///< @todo move this into m_rpaths[] + + /// @see this::RPath() and enum RETPATH_T. + RETAINED_PATH m_rpaths[RPATH_COUNT]; + + /// @see this::Elem() and enum ELEM_T. + _ELEM* m_elems[ELEM_COUNT]; +}; + + +//-------------------------------------------------------------- + +#if 0 + VTBL_ENTRY int ElemAllocNdx(); + VTBL_ENTRY void ElemSet( int aIndex, ELEMENT_BASE* aBlock ); + VTBL_ENTRY ELEM_BASE* ElemGet( int aIndex ) + + /** + * Function Value + * fetches a project variable @a aVariable and returns true if that variable was + * found, else false. If not found, aFetchedValue is not touched. Any environment + * variable is also a project variable. + * + * @param aVariable is the property or option to look for. + * @param aFetchedValue is where to put the value of the property if it exists + * and aFetchedValue is not NULL. + * @return bool - true if variable was found, else false. + */ + VTBL_ENTRY bool Value( const wxString& aVariable, wxString* aFetchedValue = NULL ); + + /** + * Function Substitute + * replaces any project variable references found within @a aString with their + * values. Any referenced variable is first sought in the PROJECT space, and if + * not found, then sought in the environment. + */ + VTBL_ENTRY const wxString Substitute( const wxString& aString ); + + /** + * Function SubstituteAndEvaluate + * replaces any project variable references found within @a aString with their + * values, and evaluates aString as an expression. + * Any referenced variable is first sought in the PROJECT space, and if + * not found, then sought in the environment. + */ + VTBL_ENTRY const wxString SubstituteAndEvaluate( const wxString& aString ); +#endif + +#endif // PROJECT_H_ diff --git a/include/sch_base_frame.h b/include/sch_base_frame.h index e53634a28d..c0b2c32824 100644 --- a/include/sch_base_frame.h +++ b/include/sch_base_frame.h @@ -24,7 +24,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#include #include class PAGE_INFO; @@ -46,7 +46,7 @@ class LIB_EDIT_FRAME; class SCH_BASE_FRAME : public EDA_DRAW_FRAME { public: - SCH_BASE_FRAME( wxWindow* aParent, + SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, ID_DRAWFRAME_TYPE aWindowType, const wxString& aTitle, const wxPoint& aPosition, const wxSize& aSize, diff --git a/include/search_stack.h b/include/search_stack.h new file mode 100644 index 0000000000..29cf8af7b5 --- /dev/null +++ b/include/search_stack.h @@ -0,0 +1,118 @@ +#ifndef SEARCH_STACK_H_ +#define SEARCH_STACK_H_ + +#include +#include + + +/** + * Class SEARCH_STACK + * looks for files in a number of places. Augments wxPathList. + * I chose the name because it sounded like a stack of work, as a reminder + * that anything you put in here means searching work at some point in time. + * (An alternative is to simply know where something is.) + */ +class SEARCH_STACK : public wxPathList +{ +public: + +#if defined(DEBUG) + void Show( const char* aPrefix ) const; +#endif + + /** + * Function FilenameWithRelativePathInSearchList + * @return a short filename (with extension) with only a relative path if + * this filename can be found in library paths + * @param aFullFilename The filename with path and extension. + */ + wxString FilenameWithRelativePathInSearchList( const wxString& aFullFilename ); + + wxString FindValidPath( const wxString& aFileName ) const + { +#if 1 // might not be needed + + if( wxFileName::FileExists( aFileName ) ) + return aFileName; + else +#endif + return wxPathList::FindValidPath( aFileName ); + } + + /** + * Function FindValidPath + * KiCad saves user defined library files that are not in the standard + * library search path list with the full file path. Calling the library + * search path list with a user library file will fail. This helper method + * solves that problem. + * @param fileName + * @return a wxEmptyString if library file is not found. + */ + wxString FindValidPath( const wxFileName& aFileName ) const + { + // call wxPathList::FindValidPath( const wxString& ); + return wxPathList::FindValidPath( aFileName.GetFullPath() ); + } + + /** + * Function AddPaths + * insert or append path(s) + * + * @param aPaths = path or path list to add. paths must be + * separated by ";" on windows, or ":" | ";" on unix. + * + * @param aIndex = insertion point, -1 for append. + */ + void AddPaths( const wxString& aPaths, int aIndex = -1 ); + + /** + * Function RemovePaths + * removes the given path(s) from the library path list + * @param aPaths = path or list of paths to remove. If list, paths must be separated by + * ";" on windows, or ":" | ";" on unix. + */ + void RemovePaths( const wxString& aPaths ); + + /** + * Function FindFileInSearchPaths + * looks in "this" for \a aFilename, but first modifies every search + * path by appending a list of path fragments from aSubdirs. That modification + * is not rentative. + */ + wxString FindFileInSearchPaths( const wxString& aFilename, + const wxArrayString* aSubdirs = NULL ); +}; + + +/** + * Class RETAINED_PATH + * is a glamorous way to save a path you might need in the future. + * It is simply a container for the two functions, if you can figure them out. + * This whole concept is awkward, and the two function might have better been + * non-member functions, simply globals. + */ +class RETAINED_PATH +{ +public: + + /** + * Function LastVisitedPath + * returns the last visited directory, or aSubPathToSearch is empty, the first + * path in lib path list ( but not the CWD ). + * @todo add more here if you can figure it out. + * + * @param aSearchStack gives the set of directories to consider. + * @param aSubPathToSearch is the preferred sub path to search in path list + */ + wxString LastVisitedPath( const SEARCH_STACK& aSStack, + const wxString& aSubPathToSearch = wxEmptyString ); + + void SaveLastVisitedPath( const wxString& aPath ); + + void Clear(); + +private: + wxString m_retained_path; +}; + +#endif // SEARCH_STACK_H_ diff --git a/include/wxBasePcbFrame.h b/include/wxBasePcbFrame.h index 23935428c8..5ec611b025 100644 --- a/include/wxBasePcbFrame.h +++ b/include/wxBasePcbFrame.h @@ -34,7 +34,7 @@ #include -#include +#include #include #include // EDA_DRAW_MODE_T #include @@ -86,11 +86,6 @@ protected: BOARD* m_Pcb; GENERAL_COLLECTOR* m_Collector; - /// The project footprint library table. This is a combination of the project - /// footprint library table and the global footprint table. This is the one to - /// use when finding a #MODULE. - FP_LIB_TABLE* m_footprintLibTable; - /// Auxiliary tool bar typically shown below the main tool bar at the top of the /// main window. wxAuiToolBar* m_auxiliaryToolBar; @@ -108,7 +103,7 @@ protected: * * @param aFootprintId is the #FPID of component footprint to load. * @return the #MODULE if found or NULL if \a aFootprintId not found in any of the - * libraries in #m_footprintLibTable. + * libraries in the table returned from #FootprintLibs(). * @throw IO_ERROR if an I/O error occurs or a #PARSE_ERROR if a file parsing error * occurs while reading footprint library files. */ @@ -120,10 +115,9 @@ protected: static const LAYER_NUM GAL_LAYER_ORDER[]; public: - PCB_BASE_FRAME( wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, - const wxString& aTitle, - const wxPoint& aPos, const wxSize& aSize, - long aStyle, const wxString & aFrameName ); + PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, + const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, + long aStyle, const wxString& aFrameName ); ~PCB_BASE_FRAME(); @@ -133,7 +127,7 @@ public: * * @param aFootprintId is the #FPID of component footprint to load. * @return the #MODULE if found or NULL if \a aFootprintId not found in any of the - * libraries in #m_footprintLibTable. + * libraries in table returned from #FootprintLibs(). */ MODULE* LoadFootprint( const FPID& aFootprintId ); @@ -191,17 +185,6 @@ public: return m_Pcb; } - /** - * Function SetFootprintLibTable - * set the footprint library table to \a aFootprintLibTable. - * - * @param aFootprintLibTable is a pointer to the #FP_LIB_TABLE object. - */ - void SetFootprintLibTable( FP_LIB_TABLE* aFootprintLibTable ) - { - m_footprintLibTable = aFootprintLibTable; - } - // General virtual void OnCloseWindow( wxCloseEvent& Event ) = 0; virtual void RedrawActiveWindow( wxDC* DC, bool EraseBg ) { } @@ -484,12 +467,10 @@ public: wxString SelectFootprintFromLibBrowser(); /** - * Function GetFootprintLibraryTable - * @return the project #FP_LIB_TABLE so programs can find footprints. + * Function FootprintLibs + * @return the project #FP_LIB_TABLE. */ - FP_LIB_TABLE* GetFootprintLibraryTable() { return m_footprintLibTable; } - - void SetFootprintLibraryTable( FP_LIB_TABLE* aTable ) { m_footprintLibTable = aTable; } + FP_LIB_TABLE* FootprintLibs() const; // ratsnest functions /** @@ -645,36 +626,15 @@ public: virtual void SwitchLayer( wxDC* DC, LAYER_NUM layer ); - /** - * Load applications settings common to PCB draw frame objects. - * - * This overrides the base class EDA_DRAW_FRAME::LoadSettings() to - * handle settings common to the PCB layout application and footprint - * editor main windows. It calls down to the base class to load - * settings common to all drawing frames. Please put your application - * settings common to all pcb drawing frames here to avoid having - * application settings loaded all over the place. - */ - virtual void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual + void SaveSettings( wxConfigBase* aCfg ); // override virtual bool InvokeDialogGrid(); - /** - * Save applications settings common to PCB draw frame objects. - * - * This overrides the base class EDA_DRAW_FRAME::SaveSettings() to - * save settings common to the PCB layout application and footprint - * editor main windows. It calls down to the base class to save - * settings common to all drawing frames. Please put your application - * settings common to all pcb drawing frames here to avoid having - * application settings saved all over the place. - */ - virtual void SaveSettings(); - void OnTogglePolarCoords( wxCommandEvent& aEvent ); void OnTogglePadDrawMode( wxCommandEvent& aEvent ); - /* User interface update event handlers. */ + // User interface update event handlers. void OnUpdateCoordType( wxUpdateUIEvent& aEvent ); void OnUpdatePadDrawMode( wxUpdateUIEvent& aEvent ); void OnUpdateSelectGrid( wxUpdateUIEvent& aEvent ); diff --git a/include/wxEeschemaStruct.h b/include/wxEeschemaStruct.h index badc7d0150..16b0f0a338 100644 --- a/include/wxEeschemaStruct.h +++ b/include/wxEeschemaStruct.h @@ -31,7 +31,7 @@ #define WX_EESCHEMA_STRUCT_H #include -#include +#include #include #include #include @@ -66,7 +66,7 @@ class wxFindDialogEvent; class wxFindReplaceData; -/* enum used in RotationMiroir() */ +/// enum used in RotationMiroir() enum COMPONENT_ORIENTATION_T { CMP_NORMAL, // Normal orientation, no rotation or mirror CMP_ROTATE_CLOCKWISE, // Rotate -90 @@ -115,6 +115,7 @@ enum SCH_SEARCH_T { class SCH_EDIT_FRAME : public SCH_BASE_FRAME { private: + SCH_SHEET_PATH* m_CurrentSheet; ///< which sheet we are presently working on. wxString m_DefaultSchematicFileName; int m_TextFieldSize; @@ -197,10 +198,7 @@ protected: void updateFindReplaceView( wxFindDialogEvent& aEvent ); public: - SCH_EDIT_FRAME( wxWindow* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); - + SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~SCH_EDIT_FRAME(); SCH_SCREEN* GetScreen() const; // overload SCH_BASE_FRAME @@ -338,8 +336,8 @@ public: */ PARAM_CFG_ARRAY& GetConfigurationSettings( void ); - void LoadSettings(); - void SaveSettings(); + void LoadSettings( wxConfigBase* aCfg ); + void SaveSettings( wxConfigBase* aCfg ); void RedrawActiveWindow( wxDC* DC, bool EraseBg ); @@ -639,23 +637,23 @@ public: void OnSaveProject( wxCommandEvent& aEvent ); /** - * Function LoadOneEEProject - * load an entire project into the schematic editor. + * Function OpenProjectFiles + * loads an entire project into the schematic editor. * * This function loads schematic root file and it's subhierarchies, the project * configuration, and the component libraries which are not already loaded. * - * @param aFileName The full path an file name to load. - * @param aIsNew True indicates that this is a new project and the default project - * template is loaded. - * @return True if the project loaded properly. + * @param aFileSet is a list of one file, the top level schematic. + * + * @return bool - true if the project loaded properly, else false. */ - bool LoadOneEEProject( const wxString& aFileName, bool aIsNew ); + //bool LoadOneEEProject( const wxString& aFileName, bool aIsNew ); + bool OpenProjectFiles( const std::vector& aFileSet, int aCtl = 0 ); // virtual from KIWAY_PLAYER /** * Function AppendOneEEProject - * read an entire project and loads it into the schematic editor *whitout* replacing the - * existing contents. + * read an entire project and loads it into the schematic editor *without* + * replacing the existing contents. * @return True if the project was imported properly. */ bool AppendOneEEProject(); @@ -1146,14 +1144,14 @@ public: void InitBlockPasteInfos(); /** - * Function ReturnBlockCommand + * Function BlockCommand * Returns the block command internat code (BLOCK_MOVE, BLOCK_COPY...) * corresponding to the keys pressed (ALT, SHIFT, SHIFT ALT ..) when * block command is started by dragging the mouse. * @param aKey = the key modifiers (Alt, Shift ...) * @return the block command id (BLOCK_MOVE, BLOCK_COPY...) */ - virtual int ReturnBlockCommand( int aKey ); + virtual int BlockCommand( int aKey ); /** * Function HandleBlockPlace diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 394698aa4f..a7f7ac3e11 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -31,7 +31,7 @@ #include -#include +#include #include #include #include @@ -65,14 +65,17 @@ class PARSE_ERROR; class IO_ERROR; class FP_LIB_TABLE; +namespace PCB { struct IFACE; } // KIFACE_I is in pcbnew.cpp + /** - * class PCB_EDIT_FRAME - * the main frame for Pcbnew + * Class PCB_EDIT_FRAME + * is the main frame for Pcbnew. * * See also class PCB_BASE_FRAME(): Basic class for Pcbnew and GerbView. */ class PCB_EDIT_FRAME : public PCB_BASE_FRAME { + friend class PCB::IFACE; friend class PCB_LAYER_WIDGET; void updateTraceWidthSelectBox(); @@ -84,9 +87,6 @@ class PCB_EDIT_FRAME : public PCB_BASE_FRAME /// The auxiliary right vertical tool bar used to access the microwave tools. wxAuiToolBar* m_microWaveToolBar; - /// The global footprint library table. - FP_LIB_TABLE* m_globalFootprintTable; - /// User defined rotation angle (in tenths of a degree). int m_rotationAngle; @@ -214,6 +214,9 @@ protected: */ void duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ); + // protected so that PCB::IFACE::CreateWindow() is the only factory. + PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ); + public: PCB_LAYER_BOX_SELECTOR* m_SelLayerBox; // a combo box to display and select active layer wxComboBox* m_SelTrackWidthBox; // a combo box to display and select current track width @@ -224,10 +227,6 @@ public: public: - PCB_EDIT_FRAME( wxWindow* father, const wxString& title, - const wxPoint& pos, const wxSize& size, - long style = KICAD_DEFAULT_DRAWFRAME_STYLE ); - virtual ~PCB_EDIT_FRAME(); void OnQuit( wxCommandEvent& event ); @@ -397,29 +396,9 @@ public: */ PARAM_CFG_ARRAY& GetConfigurationSettings(); - /** - * Function LoadSettings - * loads applications settings specific to Pcbnew. - * - * This overrides the base class PCB_BASE_FRAME::LoadSettings() to - * handle settings specific common to the PCB layout application. It - * calls down to the base class to load settings common to all PCB type - * drawing frames. Please put your application settings for Pcbnew here - * to avoid having application settings loaded all over the place. - */ - virtual void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual - /** - * Function SaveSettings - * saves applications settings common to Pcbnew. - * - * This overrides the base class PCB_BASE_FRAME::SaveSettings() to - * save settings specific to the PCB layout application main window. It - * calls down to the base class to save settings common to all PCB type - * drawing frames. Please put your application settings for Pcbnew here - * to avoid having application settings saved all over the place. - */ - virtual void SaveSettings(); + void SaveSettings( wxConfigBase* aCfg ); // override virtual /** * Get the last net list read with the net list dialog box. @@ -718,14 +697,14 @@ public: /* Block operations: */ /** - * Function ReturnBlockCommand + * Function BlockCommand * Returns the block command internat code (BLOCK_MOVE, BLOCK_COPY...) * corresponding to the keys pressed (ALT, SHIFT, SHIFT ALT ..) when * block command is started by dragging the mouse. * @param aKey = the key modifiers (Alt, Shift ...) * @return the block command id (BLOCK_MOVE, BLOCK_COPY...) */ - virtual int ReturnBlockCommand( int aKey ); + virtual int BlockCommand( int aKey ); /** * Function HandleBlockPlace() @@ -858,20 +837,20 @@ public: void Files_io( wxCommandEvent& event ); /** - * Function LoadOnePcbFile - * loads a KiCad board (.brd) from \a aFileName. + * Function OpenProjectFiles (was LoadOnePcbFile) + * loads a KiCad board (.kicad_pcb) from \a aFileName. * - * @param aFileName - File name including path. If empty, a file dialog will - * be displayed. - * @param aAppend - Append board file aFileName to the currently loaded file if true. - * Default = false. - * @param aForceFileDialog - Display the file open dialog even if aFullFileName is - * valid if true; Default = false. + * @param aFileSet - hold the BOARD file to load, a vector of one element. * - * @return False if file load fails or is canceled by the user, otherwise true. - */ + * @param aCtl - KICTL_ bits, one to indicate that an append of the board file + * aFileName to the currently loaded file is desired. + * @see #KIWAY_PLAYER for bit defines. + * + * @return bool - false if file load fails, otherwise true. bool LoadOnePcbFile( const wxString& aFileName, bool aAppend = false, bool aForceFileDialog = false ); + */ + bool OpenProjectFiles( const std::vector& aFileSet, int aCtl = 0 ); /** * Function ReadPcbFile @@ -1704,4 +1683,18 @@ public: }; +/** + * Function AskBoardFileName + * puts up a wxFileDialog asking for a BOARD filename to open. + * + * @param aParent is a wxFrame passed to wxFileDialog. + * @param aCtl is where to put the OpenProjectFiles() control bits. + * + * @param aFileName on entry is a probable choice, on return is the chosen filename. + * + * @return bool - true if chosen, else false if user aborted. + */ +bool AskBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName ); + + #endif // WXPCB_STRUCT_H_ diff --git a/include/wxstruct.h b/include/wxstruct.h index 69a24fa7a0..fb79aae9a7 100644 --- a/include/wxstruct.h +++ b/include/wxstruct.h @@ -80,6 +80,7 @@ enum id_librarytype { LIBRARY_TYPE_SYMBOL }; + enum ID_DRAWFRAME_TYPE { NOT_INIT_FRAME_TYPE = 0, @@ -108,9 +109,12 @@ extern const wxChar traceAutoSave[]; * Class EDA_BASE_FRAME * is the base frame for deriving all KiCad main window classes. This class is not * intended to be used directly. It provides support for automatic calls to - * a virtual SaveSettings() function. SaveSettings() for a derived class can choose + * a SaveSettings() function. SaveSettings() for a derived class can choose * to do nothing, or rely on basic SaveSettings() support in this base class to do * most of the work by calling it from the derived class's SaveSettings(). + *

+ * This class is not a KIWAY_PLAYER because KICAD_MANAGER_FRAME is derived from it + * and that class is not a player. */ class EDA_BASE_FRAME : public wxFrame { @@ -175,12 +179,17 @@ protected: */ virtual bool doAutoSave(); + /** + * Function config + * returns the wxConfigBase used in SaveSettings(), and is overloaded in + * KICAD_MANAGER_FRAME + */ + virtual wxConfigBase* config(); + public: EDA_BASE_FRAME( wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, - const wxString& aTitle, - const wxPoint& aPos, const wxSize& aSize, - long aStyle, - const wxString & aFrameName ); + const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, + long aStyle, const wxString& aFrameName ); ~EDA_BASE_FRAME(); @@ -223,24 +232,23 @@ public: void AddHelpVersionInfoMenuEntry( wxMenu* aMenu ); /** - * Load common frame parameters from configuration. + * Function LoadSettings + * loads common frame parameters from a configuration file. * - * The method is virtual so you can override it to load frame specific - * parameters. Don't forget to call the base method or your frames won't + * Don't forget to call the base method or your frames won't * remember their positions and sizes. */ - virtual void LoadSettings(); + virtual void LoadSettings( wxConfigBase* aCfg ); /** - * Save common frame parameters to configuration data file. + * Function SaveSettings + * saves common frame parameters to a configuration data file. * - * The method is virtual so you can override it to save frame specific - * parameters. Don't forget to call the base class's SaveSettings() from + * Don't forget to call the base class's SaveSettings() from * your derived SaveSettings() otherwise the frames won't remember their - * positions and sizes. The virtual call to SaveSettings is done safely - * only in EDA_BASE_FRAME::Show( bool ). + * positions and sizes. */ - virtual void SaveSettings(); + virtual void SaveSettings( wxConfigBase* aCfg ); /** * Function SaveProjectSettings @@ -396,641 +404,6 @@ public: }; -/** - * Class EDA_DRAW_FRAME - * is the base class for create windows for drawing purpose. The Eeschema, Pcbnew and - * GerbView main windows are just a few examples of classes derived from EDA_DRAW_FRAME. - */ -class EDA_DRAW_FRAME : public EDA_BASE_FRAME -{ - /// Let the #EDA_DRAW_PANEL object have access to the protected data since - /// it is closely tied to the #EDA_DRAW_FRAME. - friend class EDA_DRAW_PANEL; - - ///< Id of active button on the vertical toolbar. - int m_toolId; - - BASE_SCREEN* m_currentScreen; ///< current used SCREEN - - bool m_snapToGrid; ///< Indicates if cursor should be snapped to grid. - bool m_galCanvasActive; ///< whether to use new GAL engine - - EDA_DRAW_PANEL_GAL* m_galCanvas; - -protected: - EDA_HOTKEY_CONFIG* m_HotkeysZoomAndGridList; - int m_LastGridSizeId; // the command id offset (>= 0) of the last selected grid - // 0 is for the grid corresponding to - // a wxCommand ID = ID_POPUP_GRID_LEVEL_1000. - bool m_DrawGrid; // hide/Show grid - EDA_COLOR_T m_GridColor; // Grid color - - /// The area to draw on. - EDA_DRAW_PANEL* m_canvas; - - /// Tool ID of previously active draw tool bar button. - int m_lastDrawToolId; - - /// The shape of the KiCad cursor. The default value (0) is the normal cross - /// hair cursor. Set to non-zero value to draw the full screen cursor. - /// @note This is not the system mouse cursor. - int m_cursorShape; - - /// True shows the X and Y axis indicators. - bool m_showAxis; - - /// True shows the grid axis indicators. - bool m_showGridAxis; - - /// True shows the origin axis used to indicate the coordinate offset for - /// drill, gerber, and component position files. - bool m_showOriginAxis; - - /// True shows the drawing border and title block. - bool m_showBorderAndTitleBlock; - - /// Choice box to choose the grid size. - wxComboBox* m_gridSelectBox; - - /// Choice box to choose the zoom value. - wxComboBox* m_zoomSelectBox; - - /// The tool bar that contains the buttons for quick access to the application draw - /// tools. It typically is located on the right side of the main window. - wxAuiToolBar* m_drawToolBar; - - /// The options tool bar typcially located on the left edge of the main window. - wxAuiToolBar* m_optionsToolBar; - - /// Panel used to display information at the bottom of the main window. - EDA_MSG_PANEL* m_messagePanel; - - int m_MsgFrameHeight; - -#ifdef USE_WX_OVERLAY - // MAC Uses overlay to workaround the wxINVERT and wxXOR miss - wxOverlay m_overlay; -#endif - - void SetScreen( BASE_SCREEN* aScreen ) { m_currentScreen = aScreen; } - - /** - * Function unitsChangeRefresh - * is called when when the units setting has changed to allow for any derived classes - * to handle refreshing and controls that have units based measurements in them. The - * default version only updates the status bar. Don't forget to call the default - * in your derived class or the status bar will not get updated properly. - */ - virtual void unitsChangeRefresh(); - -public: - EDA_DRAW_FRAME( wxWindow* aParent, - ID_DRAWFRAME_TYPE aFrameType, - const wxString& aTitle, - const wxPoint& aPos, const wxSize& aSize, - long aStyle, - const wxString & aFrameName ); - - ~EDA_DRAW_FRAME(); - - virtual void SetPageSettings( const PAGE_INFO& aPageSettings ) = 0; - virtual const PAGE_INFO& GetPageSettings() const = 0; - - /** - * Function GetPageSizeIU - * works off of GetPageSettings() to return the size of the paper page in - * the internal units of this particular view. - */ - virtual const wxSize GetPageSizeIU() const = 0; - - /** - * Function GetAuxOrigin - * returns the origin of the axis used for plotting and various exports. - */ - virtual const wxPoint& GetAuxOrigin() const = 0; - virtual void SetAuxOrigin( const wxPoint& aPosition ) = 0; - - /** - * Function GetGridOrigin - * returns the absolute coordinates of the origin of the snap grid. This is - * treated as a relative offset, and snapping will occur at multiples of the grid - * size relative to this point. - */ - virtual const wxPoint& GetGridOrigin() const = 0; - virtual void SetGridOrigin( const wxPoint& aPosition ) = 0; - - //----------------------------------------------- - /** - * Function GetCrossHairPosition - * return the current cross hair position in logical (drawing) coordinates. - * @param aInvertY Inverts the Y axis position. - * @return The cross hair position in drawing coordinates. - */ - wxPoint GetCrossHairPosition( bool aInvertY = false ) const; - - /** - * Function SetCrossHairPosition - * sets the screen cross hair position to \a aPosition in logical (drawing) units. - * @param aPosition The new cross hair position. - * @param aSnapToGrid Sets the cross hair position to the nearest grid position to - * \a aPosition. - * - */ - void SetCrossHairPosition( const wxPoint& aPosition, bool aSnapToGrid = true ); - - /** - * Function GetCursorPosition - * returns the current cursor position in logical (drawing) units. - * @param aOnGrid Returns the nearest grid position at the current cursor position. - * @param aGridSize Custom grid size instead of the current grid size. Only valid - * if \a aOnGrid is true. - * @return The current cursor position. - */ - wxPoint GetCursorPosition( bool aOnGrid, wxRealPoint* aGridSize = NULL ) const; - - /** - * Function GetNearestGridPosition - * returns the nearest \a aGridSize location to \a aPosition. - * @param aPosition The position to check. - * @param aGridSize The grid size to locate to if provided. If NULL then the current - * grid size is used. - * @return The nearst grid position. - */ - wxPoint GetNearestGridPosition( const wxPoint& aPosition, wxRealPoint* aGridSize = NULL ) const; - - /** - * Function GetCursorScreenPosition - * returns the cross hair position in device (display) units.b - * @return The current cross hair position. - */ - wxPoint GetCrossHairScreenPosition() const; - - void SetMousePosition( const wxPoint& aPosition ); - - /** - * Function RefPos - * Return the reference position, coming from either the mouse position - * or the cursor position. - * - * @param useMouse If true, return mouse position, else cursor's. - * - * @return wxPoint - The reference point, either the mouse position or - * the cursor position. - */ - wxPoint RefPos( bool useMouse ) const; - - const wxPoint& GetScrollCenterPosition() const; - void SetScrollCenterPosition( const wxPoint& aPoint ); - - //---------------------------------------------- - - - virtual const TITLE_BLOCK& GetTitleBlock() const = 0; - virtual void SetTitleBlock( const TITLE_BLOCK& aTitleBlock ) = 0; - - int GetCursorShape() const { return m_cursorShape; } - - void SetCursorShape( int aCursorShape ) { m_cursorShape = aCursorShape; } - - bool GetShowBorderAndTitleBlock() const { return m_showBorderAndTitleBlock; } - - void SetShowBorderAndTitleBlock( bool aShow ) { m_showBorderAndTitleBlock = aShow; } - - EDA_DRAW_PANEL* GetCanvas() { return m_canvas; } - - virtual wxString GetScreenDesc() const; - - /** - * Function GetScreen - * returns a pointer to a BASE_SCREEN or one of its - * derivatives. It is overloaded by derived classes to return - * SCH_SCREEN or PCB_SCREEN. - */ - virtual BASE_SCREEN* GetScreen() const { return m_currentScreen; } - - /** - * Execute a remote command send via a socket to the application, - * port KICAD_PCB_PORT_SERVICE_NUMBER (currently 4242) - * It called by EDA_DRAW_FRAME::OnSockRequest(). - * this is a virtual function becuse the actual commands depends on the - * application. - * the basic function do nothing - * @param cmdline = received command from socket - */ - virtual void ExecuteRemoteCommand( const char* cmdline ){} - - void OnMenuOpen( wxMenuEvent& event ); - void OnMouseEvent( wxMouseEvent& event ); - - /** function SkipNextLeftButtonReleaseEvent - * after calling this function, if the left mouse button - * is down, the next left mouse button release event will be ignored. - * It is is usefull for instance when closing a dialog on a mouse click, - * to skip the next mouse left button release event - * by the parent window, because the mouse button - * clicked on the dialog is often released in the parent frame, - * and therefore creates a left button released mouse event - * which can be unwanted in some cases - */ - void SkipNextLeftButtonReleaseEvent(); - - virtual void OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, - EDA_ITEM* aItem = NULL ); - - /** - * Function AddMenuZoomAndGrid (virtual) - * Add standard zoom commands and submenu zoom and grid selection to a popup menu - * uses zoom hotkeys info base to add hotkeys info to menu commands - * @param aMasterMenu = the menu to populate. - */ - virtual void AddMenuZoomAndGrid( wxMenu* aMasterMenu ); - - void EraseMsgBox(); - void Process_PageSettings( wxCommandEvent& event ); - - /** - * Function SetLanguage - * called on a language menu selection - * when using a derived function, do not forget to call this one - */ - virtual void SetLanguage( wxCommandEvent& event ); - - virtual void ReCreateHToolbar() = 0; - virtual void ReCreateVToolbar() = 0; - virtual void ReCreateMenuBar(); - virtual void ReCreateAuxiliaryToolbar(); - - /** - * Function SetToolID - * sets the tool command ID to \a aId and sets the cursor to \a aCursor. The - * command ID must be greater or equal ::ID_NO_TOOL_SELECTED. If the command - * ID is less than ::ID_NO_TOOL_SELECTED, the tool command ID is set to - * ::ID_NO_TOOL_SELECTED. On debug builds, an assertion will be raised when - * \a aId is invalid. - * @param aId New tool command ID if greater than or equal to ::ID_NO_TOOL_SELECTED. - If less than zero, the current tool command ID is retained. - * @param aCursor Sets the cursor shape if greater than or equal to zero. - * @param aToolMsg The tool message to set in the status bar. - */ - virtual void SetToolID( int aId, int aCursor, const wxString& aToolMsg ); - - int GetToolId() const { return m_toolId; } - - /* These 4 functions provide a basic way to show/hide grid - * and /get/set grid color. - * These parameters are saved in KiCad config for each main frame - */ - /** - * Function IsGridVisible() , virtual - * @return true if the grid must be shown - */ - virtual bool IsGridVisible() const - { - return m_DrawGrid; - } - - /** - * Function SetGridVisibility() , virtual - * It may be overloaded by derived classes - * @param aVisible = true if the grid must be shown - */ - virtual void SetGridVisibility( bool aVisible ) - { - m_DrawGrid = aVisible; - } - - /** - * Function GetGridColor() , virtual - * @return the color of the grid - */ - virtual EDA_COLOR_T GetGridColor() const - { - return m_GridColor; - } - - /** - * Function SetGridColor() , virtual - * @param aColor = the new color of the grid - */ - virtual void SetGridColor( EDA_COLOR_T aColor ) - { - m_GridColor = aColor; - } - - /** - * Function GetGridPosition - * returns the nearest grid position to \a aPosition if a screen is defined and snap to - * grid is enabled. Otherwise, the original positions is returned. - * @see m_snapToGrid and m_BaseScreen members. - * @param aPosition The position to test. - * @return The wxPoint of the appropriate cursor position. - */ - wxPoint GetGridPosition( const wxPoint& aPosition ) const; - - /** - * Command event handler for selecting grid sizes. - * - * All commands that set the grid size should eventually end up here. - * This is where the application setting is saved. If you override - * this method, make sure you call down to the base class. - * - * @param event - Command event passed by selecting grid size from the - * grid size combobox on the toolbar. - */ - virtual void OnSelectGrid( wxCommandEvent& event ); - - /** - * Functions OnSelectZoom - * sets the zoom factor when selected by the zoom list box in the main tool bar. - * @note List position 0 is fit to page - * List position >= 1 = zoom (1 to zoom max) - * Last list position is custom zoom not in zoom list. - */ - virtual void OnSelectZoom( wxCommandEvent& event ); - - // Command event handlers shared by all applications derived from EDA_DRAW_FRAME. - void OnToggleGridState( wxCommandEvent& aEvent ); - void OnSelectUnits( wxCommandEvent& aEvent ); - void OnToggleCrossHairStyle( wxCommandEvent& aEvent ); - - // Update user interface event handlers shared by all applications derived from - // EDA_DRAW_FRAME. - void OnUpdateUndo( wxUpdateUIEvent& aEvent ); - void OnUpdateRedo( wxUpdateUIEvent& aEvent ); - void OnUpdateGrid( wxUpdateUIEvent& aEvent ); - void OnUpdateUnits( wxUpdateUIEvent& aEvent ); - void OnUpdateCrossHairStyle( wxUpdateUIEvent& aEvent ); - - /** - * Function GeneralControl - * performs application specific control using \a aDC at \a aPosition in logical units. - *

- * Override this function for application specific control. This function gets - * called on every mouse and key event. - *

- * @param aDC A device context. - * @param aPosition The current cursor position in logical (drawing) units. - * @param aHotKey A key event used for application specific control if not zero. - */ - virtual void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ) { } - - /** - * Function OnSize - * recalculates the size of toolbars and display panel when the frame size changes. - */ - virtual void OnSize( wxSizeEvent& event ); - - void OnEraseBackground( wxEraseEvent& SizeEvent ); - - virtual void OnZoom( wxCommandEvent& event ); - - /** - * Function RedrawScreen - * redraws the entire screen area by updating the scroll bars and mouse pointer in - * order to have \a aCenterPoint at the center of the screen. - * @param aCenterPoint The position in logical units to center the scroll bars. - * @param aWarpPointer Moves the mouse cursor to \a aCenterPoint if true. - */ - void RedrawScreen( const wxPoint& aCenterPoint, bool aWarpPointer ); - - /** - * Function RedrawScreen2 - * puts the crosshair back to the screen position it had before zooming - * @param posBefore screen position of the crosshair before zooming - */ - void RedrawScreen2( const wxPoint& posBefore ); - - /** - * Function Zoom_Automatique - * redraws the screen with best zoom level and the best centering - * that shows all the page or the board - */ - void Zoom_Automatique( bool aWarpPointer ); - - /* Set the zoom level to show the area Rect */ - void Window_Zoom( EDA_RECT& Rect ); - - /** Return the zoom level which displays the full page on screen */ - virtual double BestZoom() = 0; - - /** - * Function GetZoom - * @return The current zoom level. - */ - double GetZoom(); - - /** - * Function DrawWorkSheet - * Draws on screen the page layout with the frame and the basic inscriptions. - * @param aDC The device context. - * @param aScreen screen to draw - * @param aLineWidth The pen width to use to draw the layout. - * @param aScale The mils to Iu conversion factor. - * @param aFilename The filename to display in basic inscriptions. - */ - void DrawWorkSheet( wxDC* aDC, BASE_SCREEN* aScreen, int aLineWidth, - double aScale, const wxString &aFilename ); - - void DisplayToolMsg( const wxString& msg ); - virtual void RedrawActiveWindow( wxDC* DC, bool EraseBg ) = 0; - virtual void OnLeftClick( wxDC* DC, const wxPoint& MousePos ) = 0; - virtual void OnLeftDClick( wxDC* DC, const wxPoint& MousePos ); - virtual bool OnRightClick( const wxPoint& MousePos, wxMenu* PopMenu ) = 0; - virtual void ToolOnRightClick( wxCommandEvent& event ); - void AdjustScrollBars( const wxPoint& aCenterPosition ); - - /** - * Function OnActivate (virtual) - * is called when activating the frame. - * In derived classes with a overriding OnActivate function, - * do not forget to call this EDA_DRAW_FRAME::OnActivate( event ) basic function. - */ - virtual void OnActivate( wxActivateEvent& event ); - - /** - * Function UpdateStatusBar - * updates the status bar information. - * - * The base method updates the absolute and relative coordinates and the - * zoom information. If you override this virtual method, make sure to call - * this subclassed method. The status bar can draw itself. This is not - * a drawing function per se, but rather updates lines of text held by - * the components within the status bar which is owned by the wxFrame. - *

- * On a MAC, be careful about calling this function when there is an - * existing wxDC in existence on a sibling window. - */ - virtual void UpdateStatusBar(); - - /** - * Function DisplayUnitsMsg - * displays current unit pane on the status bar. - */ - void DisplayUnitsMsg(); - - /* Handlers for block commands */ - virtual void InitBlockPasteInfos(); - - /** - * Function HandleBlockBegin - * initializes the block command including the command type, initial position, - * and other variables. - */ - virtual bool HandleBlockBegin( wxDC* aDC, int aKey, const wxPoint& aPosition ); - - /** - * Function ReturnBlockCommand - * Returns the block command code (BLOCK_MOVE, BLOCK_COPY...) corresponding to the - * keys pressed (ALT, SHIFT, SHIFT ALT ..) when block command is started by dragging - * the mouse. - * - * @param aKey = the key modifiers (Alt, Shift ...) - * @return the block command id (BLOCK_MOVE, BLOCK_COPY...) - */ - virtual int ReturnBlockCommand( int aKey ); - - /** - * Function HandleBlockPlace( ) - * Called after HandleBlockEnd, when a block command needs to be - * executed after the block is moved to its new place - * (bloc move, drag, copy .. ) - * Parameters must be initialized in GetScreen()->m_BlockLocate - */ - virtual void HandleBlockPlace( wxDC* DC ); - - /** - * Function HandleBlockEnd( ) - * Handle the "end" of a block command, - * i.e. is called at the end of the definition of the area of a block. - * depending on the current block command, this command is executed - * or parameters are initialized to prepare a call to HandleBlockPlace - * in GetScreen()->m_BlockLocate - * @return false if no item selected, or command finished, - * true if some items found and HandleBlockPlace must be called later - */ - virtual bool HandleBlockEnd( wxDC* DC ); - - /** - * Function CopyToClipboard - * copies the current page or the current block to the clipboard. - */ - void CopyToClipboard( wxCommandEvent& event ); - - /* interprocess communication */ - void OnSockRequest( wxSocketEvent& evt ); - void OnSockRequestServer( wxSocketEvent& evt ); - - /** - * Function LoadSettings - * loads the draw frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings common to the draw frame will not get loaded. - */ - virtual void LoadSettings(); - - /** - * Funxtion SaveSettings - * saves the draw frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings common to the draw frame will not get saved. - */ - virtual void SaveSettings(); - - /** - * Append a message to the message panel. - * - * This helper method checks to make sure the message panel exists in - * the frame and appends a message to it using the message panel - * AppendMessage() method. - * - * @param textUpper - The message upper text. - * @param textLower - The message lower text. - * @param color - A color ID from the KiCad color list (see colors.h). - * @param pad - Number of spaces to pad between messages (default = 4). - */ - void AppendMsgPanel( const wxString& textUpper, const wxString& textLower, - EDA_COLOR_T color, int pad = 6 ); - - /** - * Clear all messages from the message panel. - */ - void ClearMsgPanel( void ); - - /** - * Function SetMsgPanel - * clears the message panel and populates it with the contents of \a aList. - * - * @param aList is the list of #MSG_PANEL_ITEM objects to fill the message panel. - */ - void SetMsgPanel( const std::vector< MSG_PANEL_ITEM >& aList ); - - void SetMsgPanel( EDA_ITEM* aItem ); - - /** - * Function PrintPage - * used to print a page - * Print the page pointed by current screen, set by the calling print function - * @param aDC = wxDC given by the calling print function - * @param aPrintMask = not used here - * @param aPrintMirrorMode = not used here (Set when printing in mirror mode) - * @param aData = a pointer on an auxiliary data (not always used, NULL if not used) - */ - virtual void PrintPage( wxDC* aDC, LAYER_MSK aPrintMask, bool aPrintMirrorMode, void* aData = NULL ); - - /** - * Function CoordinateToString - * is a helper to convert the \a integer coordinate \a aValue to a string in inches or mm - * according to the current user units setting. - * @param aValue The coordinate to convert. - * @param aConvertToMils Convert inch values to mils if true. This setting has no effect if - * the current user unit is millimeters. - * @return The converted string for display in user interface elements. - */ - wxString CoordinateToString( int aValue, bool aConvertToMils = false ) const; - - /** - * Function LengthDoubleToString - * is a helper to convert the \a double value \a aValue to a string in inches or mm - * according to the current user units setting. - * @param aValue The coordinate to convert. - * @param aConvertToMils Convert inch values to mils if true. This setting has no effect if - * the current user unit is millimeters. - * @return The converted string for display in user interface elements. - */ - wxString LengthDoubleToString( double aValue, bool aConvertToMils = false ) const; - - /** - * Function UseGalCanvas - * used to switch between standard and GAL-based canvas. - * - * @param aEnable True for GAL-based canvas, false for standard canvas. - */ - virtual void UseGalCanvas( bool aEnable ); - - /** - * Function IsGalCanvasActive - * is used to check which canvas (GAL-based or standard) is currently in use. - * - * @return True for GAL-based canvas, false for standard canvas. - */ - bool IsGalCanvasActive() const { return m_galCanvasActive; } - void SetGalCanvasActive( bool aState ) { m_galCanvasActive = aState; } - - /** - * Function GetGalCanvas - * returns a pointer to GAL-based canvas of given EDA draw frame. - * - * @return Pointer to GAL-based canvas. - */ - EDA_DRAW_PANEL_GAL* GetGalCanvas() const { return m_galCanvas; } - void SetGalCanvas( EDA_DRAW_PANEL_GAL* aPanel ) { m_galCanvas = aPanel; } - - DECLARE_EVENT_TABLE() -}; - - /** * Specialization of the wxAuiPaneInfo class for KiCad panels. * diff --git a/kicad/CMakeLists.txt b/kicad/CMakeLists.txt index b86d4b5035..2647e93792 100644 --- a/kicad/CMakeLists.txt +++ b/kicad/CMakeLists.txt @@ -21,14 +21,10 @@ set(KICAD_SRCS project_template.cpp tree_project_frame.cpp) -if(WIN32) - if(MINGW) - # KICAD_RESOURCES variable is set by the macro. - mingw_resource_compiler(kicad) - else(MINGW) - set(KICAD_RESOURCES kicad.rc) - endif(MINGW) -endif(WIN32) +if(MINGW) + # KICAD_RESOURCES variable is set by the macro. + mingw_resource_compiler(kicad) +endif() if(APPLE) set(KICAD_RESOURCES kicad.icns kicad_doc.icns) diff --git a/kicad/class_treeproject_item.cpp b/kicad/class_treeproject_item.cpp index 01b31af817..b43c93bc18 100644 --- a/kicad/class_treeproject_item.cpp +++ b/kicad/class_treeproject_item.cpp @@ -34,7 +34,8 @@ #include #include -#include +#include +#include #include #include #include @@ -189,7 +190,8 @@ void TREEPROJECT_ITEM::Activate( TREE_PROJECT_FRAME* prjframe ) wxString sep = wxFileName().GetPathSeparator(); wxString FullFileName = GetFileName(); wxTreeItemId id = GetId(); - KICAD_MANAGER_FRAME* mainFrame = (KICAD_MANAGER_FRAME*) wxGetApp().GetTopWindow(); + + KICAD_MANAGER_FRAME* mainFrame = (KICAD_MANAGER_FRAME*) Pgm().App().GetTopWindow(); AddDelimiterString( FullFileName ); @@ -225,7 +227,7 @@ void TREEPROJECT_ITEM::Activate( TREE_PROJECT_FRAME* prjframe ) case TREE_TXT: { - wxString editorname = wxGetApp().GetEditorName(); + wxString editorname = Pgm().GetEditorName(); if( !editorname.IsEmpty() ) mainFrame->Execute( m_parent, editorname, FullFileName ); diff --git a/kicad/files-io.cpp b/kicad/files-io.cpp index 41803864dc..4943e359f3 100644 --- a/kicad/files-io.cpp +++ b/kicad/files-io.cpp @@ -27,7 +27,7 @@ */ #include -#include +#include #include #include #include @@ -47,9 +47,8 @@ static const wxString ZipFileWildcard( wxT( "Zip file (*.zip) | *.zip" ) ); void KICAD_MANAGER_FRAME::OnFileHistory( wxCommandEvent& event ) { - wxString fn; - - fn = GetFileFromHistory( event.GetId(), _( "KiCad project file" ) ); + wxString fn = GetFileFromHistory( event.GetId(), + _( "KiCad project file" ), &Pgm().GetFileHistory() ); if( fn != wxEmptyString ) { diff --git a/kicad/kicad.cpp b/kicad/kicad.cpp index b603c06432..4fc1831a5f 100644 --- a/kicad/kicad.cpp +++ b/kicad/kicad.cpp @@ -29,28 +29,131 @@ #include -#include #include +#include +#include #include +#include #include +#include #include -const wxString g_KicadPrjFilenameExtension( wxT( ".pro" ) ); - -/************************************/ -/* Called to initialize the program */ -/************************************/ - -// Create a new application object -IMPLEMENT_APP( EDA_APP ) - -/* MacOSX: Needed for file association - * http://wiki.wxwidgets.org/WxMac-specific_topics - */ -void EDA_APP::MacOpenFile( const wxString& aFileName ) +// a dummy to quiet linking with EDA_BASE_FRAME::config(); +#include +KIFACE_I& Kiface() { + wxASSERT( 0 ); // should never be called, only reference is from EDA_BASE_FRAME::config(); + return (KIFACE_I&) *(KIFACE_I*) 0; +} + +static PGM_KICAD program; + +PGM_KICAD& Pgm() +{ + return program; +} + + +bool PGM_KICAD::OnPgmInit( wxApp* aWxApp ) +{ + m_wx_app = aWxApp; // first thing. + + m_bm.Init(); + +#if 0 // copied from single_top.c, possibly for milestone B) + wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath(); + + if( !wxIsAbsolutePath( absoluteArgv0 ) ) + { + wxLogSysError( wxT( "No meaningful argv[0]" ) ); + return false; + } + + // Set LIB_ENV_VAR *before* loading the DSO, in case the top-level DSO holding the + // KIFACE has hard dependencies on subsidiary DSOs below it. + SetLibEnvVar( absoluteArgv0 ); +#endif + + if( !initPgm() ) + return false; + + // Read current setup and reopen last directory if no filename to open on + // command line. + if( App().argc == 1 ) + { + wxString dir; + + if( PgmSettings()->Read( workingDirKey, &dir ) && wxDirExists( dir ) ) + { + wxSetWorkingDirectory( dir ); + } + } + + KICAD_MANAGER_FRAME* frame = new KICAD_MANAGER_FRAME( NULL, wxT( "KiCad" ), + wxDefaultPosition, wxDefaultSize ); + App().SetTopWindow( frame ); + + bool prjloaded = false; // true when the project is loaded + + if( App().argc > 1 ) + frame->m_ProjectFileName = App().argv[1]; + + else if( GetFileHistory().GetCount() ) + { + // Try to open the last opened project, + // if a project name is not given when starting Kicad + frame->m_ProjectFileName = GetFileHistory().GetHistoryFile( 0 ); + + if( !frame->m_ProjectFileName.FileExists() ) + GetFileHistory().RemoveFileFromHistory( 0 ); + else + { + wxCommandEvent cmd( 0, wxID_FILE1 ); + + frame->OnFileHistory( cmd ); + prjloaded = true; // OnFileHistory() loads the project + } + } + + if( !frame->m_ProjectFileName.FileExists() ) + { + wxFileName namelessProject( wxGetCwd(), NAMELESS_PROJECT, + ProjectFileExtension ); + + frame->m_ProjectFileName = namelessProject; + } + + if( !prjloaded ) + { + wxCommandEvent cmd( 0, wxID_ANY ); + + frame->OnLoadProject( cmd ); + } + + frame->Show( true ); + frame->Raise(); + + return true; +} + + +void PGM_KICAD::OnPgmExit() +{ + saveCommonSettings(); + + // write common settings to disk, and destroy everything in PGM_KICAD, + // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier + // than static destruction would. + destroy(); +} + + +void PGM_KICAD::MacOpenFile( const wxString& aFileName ) +{ +#if 0 // I'm tired, need a rest. + KICAD_MANAGER_FRAME* frame = (KICAD_MANAGER_FRAME*) GetTopWindow(); wxFileName fn = aFileName; @@ -79,58 +182,192 @@ void EDA_APP::MacOpenFile( const wxString& aFileName ) frame->m_LeftWin->ReCreateTreePrj(); frame->PrintPrjInfo(); +#endif } -bool EDA_APP::OnInit() +void PGM_KICAD::destroy() { - KICAD_MANAGER_FRAME* frame; + // unlike a normal destructor, this is designed to be called more + // than once safely: - InitEDA_Appl( wxT( "KiCad" ), APP_KICAD_T ); + m_bm.End(); - // read current setup and reopen last directory if no filename to open in command line - bool reopenLastUsedDirectory = argc == 1; - GetSettings( reopenLastUsedDirectory ); + PGM_BASE::destroy(); +} - frame = new KICAD_MANAGER_FRAME( NULL, wxT( "KiCad" ), - wxDefaultPosition, wxDefaultSize ); - SetTopWindow( frame ); - bool prjloaded = false; // true when the project is loaded +/** + * Class KIWAY_MGR + * is container for all (KIWAYS and PROJECTS). This class needs to work both for a C++ + * project manager and an a wxPython one (after being moved into a header later). + */ +class KIWAY_MGR +{ +public: + //KIWAY_MGR(); + // ~KIWAY_MGR(); - if( argc > 1 ) - frame->m_ProjectFileName = argv[1]; - else if( m_fileHistory.GetCount() ) + bool OnStart( wxApp* aProcess ); + + void OnEnd(); + + KIWAY& operator[]( int aIndex ) { - // Try to open the last opened project, - // if a project name is not given when starting Kicad - frame->m_ProjectFileName = m_fileHistory.GetHistoryFile( 0 ); + wxASSERT( m_kiways.size() ); // stuffed in OnStart() + return m_kiways[aIndex]; + } - if( !frame->m_ProjectFileName.FileExists() ) - m_fileHistory.RemoveFileFromHistory( 0 ); - else +private: + + // KIWAYs may not be moved once doled out. + // boost_ptr::vector however never moves the object pointed to. + typedef boost::ptr_vector KIWAYS; + + KIWAYS m_kiways; +}; + +static KIWAY_MGR kiways; + + +/** + * Struct APP_KICAD + * is not publicly visible because most of the action is in PGM_KICAD these days. + */ +struct APP_KICAD : public wxApp +{ + bool OnInit() // overload wxApp virtual + { + if( kiways.OnStart( this ) ) { - wxCommandEvent cmd( 0, wxID_FILE1 ); - frame->OnFileHistory( cmd ); - prjloaded = true; // OnFileHistory() loads the project + return Pgm().OnPgmInit( this ); } + return false; } - if( !frame->m_ProjectFileName.FileExists() ) + int OnExit() // overload wxApp virtual { - wxFileName namelessProject( wxGetCwd(), NAMELESS_PROJECT, - ProjectFileExtension ); - frame->m_ProjectFileName = namelessProject; + kiways.OnEnd(); + + Pgm().OnPgmExit(); + + return wxApp::OnExit(); } - if( ! prjloaded ) + /** + * Function MacOpenFile + * is specific to MacOSX (not used under Linux or Windows). + * MacOSX requires it for file association. + * @see http://wiki.wxwidgets.org/WxMac-specific_topics + */ + void MacOpenFile( const wxString& aFileName ) // overload wxApp virtual { - wxCommandEvent cmd( 0, wxID_ANY ); - frame->OnLoadProject( cmd ); + Pgm().MacOpenFile( aFileName ); } +}; - frame->Show( true ); - frame->Raise(); +IMPLEMENT_APP( APP_KICAD ); + + +// The C++ project manager supports one open PROJECT, so Prj() calls within +// this link image need this function. +PROJECT& Prj() +{ + return kiways[0].Prj(); +} + + +bool KIWAY_MGR::OnStart( wxApp* aProcess ) +{ + // The C++ project manager supports only one open PROJECT + m_kiways.push_back( new KIWAY() ); return true; } + + +void KIWAY_MGR::OnEnd() +{ +} + + +/* +static bool init( KICAD_PGM* aProcess, const wxString& aName ) +{ + m_Id = aId; + m_Checker = new wxSingleInstanceChecker( aName.Lower() + wxT( "-" ) + wxGetUserId() ); + + // Init KiCad environment + // the environment variable KICAD (if exists) gives the kicad path: + // something like set KICAD=d:\kicad + bool isDefined = wxGetEnv( wxT( "KICAD" ), &m_KicadEnv ); + + if( isDefined ) // ensure m_KicadEnv ends by "/" + { + m_KicadEnv.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); + + if( !m_KicadEnv.IsEmpty() && m_KicadEnv.Last() != '/' ) + m_KicadEnv += UNIX_STRING_DIR_SEP; + } + + // Prepare On Line Help. Use only lower case for help file names, in order to + // avoid problems with upper/lower case file names under windows and unix. +#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML + m_HelpFileName = aName.Lower() + wxT( ".html" ); +#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF + m_HelpFileName = aName.Lower() + wxT( ".pdf" ); +#else + #error Help files format not defined +#endif + + // Init parameters for configuration + SetVendorName( wxT( "KiCad" ) ); + SetAppName( aName.Lower() ); + SetTitle( aName ); + + m_settings = new wxConfig(); + + wxASSERT( m_settings != NULL ); + + m_commonSettings = new wxConfig( CommonConfigPath ); + wxASSERT( m_commonSettings != NULL ); + + // Install some image handlers, mainly for help + wxImage::AddHandler( new wxPNGHandler ); + wxImage::AddHandler( new wxGIFHandler ); + wxImage::AddHandler( new wxJPEGHandler ); + wxFileSystem::AddHandler( new wxZipFSHandler ); + + // Analyze the command line & init binary path + SetBinDir(); + SetDefaultSearchPaths(); + SetLanguagePath(); + ReadPdfBrowserInfos(); + + // Internationalization: loading the kicad suitable Dictionary + wxString languageSel; + m_commonSettings->Read( languageCfgKey, &languageSel); + + setLanguageId( wxLANGUAGE_DEFAULT ); + + // Search for the current selection + for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) + { + if( s_Languages[ii].m_Lang_Label == languageSel ) + { + setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); + break; + } + } + + bool succes = SetLanguage( true ); + + if( !succes ) + { + } + + // Set locale option for separator used in float numbers + SetLocaleTo_Default(); +} +*/ + diff --git a/kicad/kicad.h b/kicad/kicad.h index 73ffbe8ebe..129d29dc82 100644 --- a/kicad/kicad.h +++ b/kicad/kicad.h @@ -39,7 +39,7 @@ #include #include -#include +//#include // With a recent wxWidget, we can use the wxFileSystemWatcherEvent // to monitor files add/remove/rename in tree project @@ -47,8 +47,6 @@ #define KICAD_USE_FILES_WATCHER #endif -extern const wxString g_KicadPrjFilenameExtension; - class LAUNCHER_PANEL; class TREEPROJECTFILES; class TREE_PROJECT_FRAME; @@ -116,11 +114,15 @@ enum id_kicad_frm { }; -/* class KICAD_MANAGER_FRAME - * This is the main KiCad frame +/** + * Class KICAD_MANAGER_FRAME + * is the main KiCad project manager frame. It is not a KIWAY_PLAYER. */ class KICAD_MANAGER_FRAME : public EDA_BASE_FRAME { +protected: + wxConfigBase* config(); // override EDA_BASE_FRAME virtual + public: TREE_PROJECT_FRAME* m_LeftWin; LAUNCHER_PANEL* m_Launcher; @@ -133,7 +135,8 @@ public: private: int m_leftWinWidth; -public: KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& title, +public: + KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& title, const wxPoint& pos, const wxSize& size ); ~KICAD_MANAGER_FRAME(); @@ -204,23 +207,9 @@ public: KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& title, void CreateNewProject( const wxString aPrjFullFileName, bool aTemplateSelector ); - /** - * Function LoadSettings - * loads the KiCad main frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get loaded. - */ - void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); - /** - * Function SaveSettings - * saves the KiCad main frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get saved. - */ - void SaveSettings(); + void SaveSettings( wxConfigBase* aCfg ); /** * Function Execute @@ -232,13 +221,13 @@ public: KICAD_MANAGER_FRAME( wxWindow* parent, const wxString& title, void Execute( wxWindow* frame, const wxString& execFile, const wxString& param = wxEmptyString ); - class PROCESS_TERMINATE_EVENT_HANDLER : public wxProcess + class TERMINATE_HANDLER : public wxProcess { private: wxString appName; public: - PROCESS_TERMINATE_EVENT_HANDLER( const wxString& appName ) : + TERMINATE_HANDLER( const wxString& appName ) : appName(appName) { } @@ -287,4 +276,8 @@ private: wxBitmapButton* AddBitmapButton( wxWindowID aId, const wxBitmap& aBitmap ); }; +// The C++ project manager includes a single PROJECT in its link image. +class PROJECT; +extern PROJECT& Prj(); + #endif diff --git a/kicad/mainframe.cpp b/kicad/mainframe.cpp index 1dc1e0cade..55f5f1ba0b 100644 --- a/kicad/mainframe.cpp +++ b/kicad/mainframe.cpp @@ -29,7 +29,7 @@ */ #include -#include +#include #include #include #include @@ -40,12 +40,11 @@ #include -static const wxString TreeFrameWidthEntry( wxT( "LeftWinWidth" ) ); +#define TreeFrameWidthEntry wxT( "LeftWinWidth" ) -KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, - const wxString& title, - const wxPoint& pos, - const wxSize& size ) : + +KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, + const wxString& title, const wxPoint& pos, const wxSize& size ) : EDA_BASE_FRAME( parent, KICAD_MAIN_FRAME_TYPE, title, pos, size, KICAD_DEFAULT_DRAWFRAME_STYLE, wxT( "KicadFrame" ) ) { @@ -63,7 +62,7 @@ KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, SetIcon( icon ); // Give the last sise and pos to main window - LoadSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); // Left window: is the box which display tree project @@ -71,6 +70,7 @@ KICAD_MANAGER_FRAME::KICAD_MANAGER_FRAME( wxWindow* parent, // Right top Window: buttons to launch applications m_Launcher = new LAUNCHER_PANEL( this ); + // Add the wxTextCtrl showing all messages from KiCad: m_MessagesBox = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, @@ -115,6 +115,14 @@ KICAD_MANAGER_FRAME::~KICAD_MANAGER_FRAME() } +wxConfigBase* KICAD_MANAGER_FRAME::config() +{ + wxConfigBase* ret = Pgm().PgmSettings(); + wxASSERT( ret ); + return ret; +} + + void KICAD_MANAGER_FRAME::PrintMsg( const wxString& aText ) { m_MessagesBox->AppendText( aText ); @@ -134,7 +142,7 @@ void KICAD_MANAGER_FRAME::OnCloseWindow( wxCloseEvent& Event ) { int px, py; - UpdateFileHistory( m_ProjectFileName.GetFullPath() ); + UpdateFileHistory( m_ProjectFileName.GetFullPath(), &Pgm().GetFileHistory() ); if( !IsIconized() ) // save main frame position and size { @@ -150,12 +158,12 @@ void KICAD_MANAGER_FRAME::OnCloseWindow( wxCloseEvent& Event ) Event.SetCanVeto( true ); // Close the help frame - if( wxGetApp().GetHtmlHelpController() ) + if( Pgm().GetHtmlHelpController() ) { - if( wxGetApp().GetHtmlHelpController()->GetFrame() ) // returns NULL if no help frame active - wxGetApp().GetHtmlHelpController()->GetFrame()->Close( true ); + if( Pgm().GetHtmlHelpController()->GetFrame() ) // returns NULL if no help frame active + Pgm().GetHtmlHelpController()->GetFrame()->Close( true ); - wxGetApp().SetHtmlHelpController( NULL ); + Pgm().SetHtmlHelpController( NULL ); } m_LeftWin->Show( false ); @@ -170,14 +178,12 @@ void KICAD_MANAGER_FRAME::OnExit( wxCommandEvent& event ) } -void KICAD_MANAGER_FRAME::PROCESS_TERMINATE_EVENT_HANDLER:: - OnTerminate( int pid, int status ) +void KICAD_MANAGER_FRAME::TERMINATE_HANDLER::OnTerminate( int pid, int status ) { + wxString msg = wxString::Format( _( "%s closed [pid=%d]\n" ), + GetChars( appName ), pid ); - wxString msg; - - msg.Printf( appName + _( " closed [pid=%d]\n" ), pid ); - ( (KICAD_MANAGER_FRAME*) wxGetApp().GetTopWindow() )->PrintMsg( msg ); + ( (KICAD_MANAGER_FRAME*) Pgm().App().GetTopWindow() )->PrintMsg( msg ); delete this; } @@ -186,17 +192,15 @@ void KICAD_MANAGER_FRAME::PROCESS_TERMINATE_EVENT_HANDLER:: void KICAD_MANAGER_FRAME::Execute( wxWindow* frame, const wxString& execFile, const wxString& param ) { + TERMINATE_HANDLER* callback = new TERMINATE_HANDLER( execFile ); - PROCESS_TERMINATE_EVENT_HANDLER* callback; - long pid; - wxString msg; - - callback = new PROCESS_TERMINATE_EVENT_HANDLER( execFile ); - pid = ExecuteFile( frame, execFile, param, callback ); + long pid = ExecuteFile( frame, execFile, param, callback ); if( pid > 0 ) { - msg.Printf( execFile + _( " opened [pid=%ld]\n" ), pid ); + wxString msg = wxString::Format( _( "%s opened [pid=%ld]\n" ), + GetChars( execFile ), pid ); + PrintMsg( msg ); } else @@ -267,7 +271,7 @@ void KICAD_MANAGER_FRAME::OnRunGerbview( wxCommandEvent& event ) void KICAD_MANAGER_FRAME::OnOpenTextEditor( wxCommandEvent& event ) { - wxString editorname = wxGetApp().GetEditorName(); + wxString editorname = Pgm().GetEditorName(); if( !editorname.IsEmpty() ) Execute( this, editorname, wxEmptyString ); @@ -294,8 +298,8 @@ void KICAD_MANAGER_FRAME::OnOpenFileInTextEditor( wxCommandEvent& event ) wxString filename = wxT( "\"" ); filename += dlg.GetPath() + wxT( "\"" ); - if( !dlg.GetPath().IsEmpty() && !wxGetApp().GetEditorName().IsEmpty() ) - Execute( this, wxGetApp().GetEditorName(), filename ); + if( !dlg.GetPath().IsEmpty() && !Pgm().GetEditorName().IsEmpty() ) + Execute( this, Pgm().GetEditorName(), filename ); } @@ -311,29 +315,20 @@ void KICAD_MANAGER_FRAME::ClearMsg() } -void KICAD_MANAGER_FRAME::LoadSettings() +void KICAD_MANAGER_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* cfg = wxGetApp().GetSettings(); - - if( cfg ) - { - EDA_BASE_FRAME::LoadSettings(); - cfg->Read( TreeFrameWidthEntry, &m_leftWinWidth ); - } + EDA_BASE_FRAME::LoadSettings( aCfg ); + aCfg->Read( TreeFrameWidthEntry, &m_leftWinWidth ); } -void KICAD_MANAGER_FRAME::SaveSettings() +void KICAD_MANAGER_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* cfg = wxGetApp().GetSettings(); - - if( cfg ) - { - EDA_BASE_FRAME::SaveSettings(); - cfg->Write( TreeFrameWidthEntry, m_LeftWin->GetSize().x ); - } + EDA_BASE_FRAME::SaveSettings( aCfg ); + aCfg->Write( TreeFrameWidthEntry, m_LeftWin->GetSize().x ); } + /** * a minor helper function: * Prints the Current Working Dir name and the projet name on the text panel. @@ -346,3 +341,4 @@ void KICAD_MANAGER_FRAME::PrintPrjInfo() GetChars( m_ProjectFileName.GetFullPath() ) ); PrintMsg( msg ); } + diff --git a/kicad/menubar.cpp b/kicad/menubar.cpp index 90af49c3ff..4c18881bd3 100644 --- a/kicad/menubar.cpp +++ b/kicad/menubar.cpp @@ -28,7 +28,7 @@ * @brief (Re)Create the project manager menubar for KiCad */ #include -#include +#include #include #include #include @@ -110,7 +110,7 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar() // Before deleting, remove the menus managed by m_fileHistory // (the file history will be updated when adding/removing files in history) if( openRecentMenu ) - wxGetApp().GetFileHistory().RemoveMenu( openRecentMenu ); + Pgm().GetFileHistory().RemoveMenu( openRecentMenu ); // Delete all existing menus while( menuBar->GetMenuCount() ) @@ -130,8 +130,8 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar() // File history openRecentMenu = new wxMenu(); - wxGetApp().GetFileHistory().UseMenu( openRecentMenu ); - wxGetApp().GetFileHistory().AddFilesToMenu( ); + Pgm().GetFileHistory().UseMenu( openRecentMenu ); + Pgm().GetFileHistory().AddFilesToMenu( ); AddMenuItem( fileMenu, openRecentMenu, wxID_ANY, _( "Open &Recent" ), @@ -229,7 +229,7 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar() SubMenuPdfBrowserChoice->Append( item ); SubMenuPdfBrowserChoice->Check( ID_SELECT_DEFAULT_PDF_BROWSER, - wxGetApp().UseSystemPdfBrowser() ); + Pgm().UseSystemPdfBrowser() ); // Favourite item = new wxMenuItem( SubMenuPdfBrowserChoice, @@ -243,7 +243,7 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar() SubMenuPdfBrowserChoice->Append( item ); SubMenuPdfBrowserChoice->AppendSeparator(); SubMenuPdfBrowserChoice->Check( ID_SELECT_PREFERED_PDF_BROWSER, - !wxGetApp().UseSystemPdfBrowser() ); + !Pgm().UseSystemPdfBrowser() ); // Append PDF Viewer submenu to preferences AddMenuItem( SubMenuPdfBrowserChoice, @@ -261,7 +261,7 @@ void KICAD_MANAGER_FRAME::ReCreateMenuBar() // Language submenu preferencesMenu->AppendSeparator(); - wxGetApp().AddMenuLanguageList( preferencesMenu ); + Pgm().AddMenuLanguageList( preferencesMenu ); // Menu Help: wxMenu* helpMenu = new wxMenu; diff --git a/kicad/pgm_kicad.h b/kicad/pgm_kicad.h new file mode 100644 index 0000000000..5de4cebbb7 --- /dev/null +++ b/kicad/pgm_kicad.h @@ -0,0 +1,74 @@ +#ifndef PGM_KICAD_H_ +#define PGM_KICAD_H_ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include + + +/** + * Class PGM_KICAD + * extends PGM_BASE to bring in FileHistory() and PdfBrowser() which were moved + * from EDA_APP into KIFACE_I. KIFACE_I is not applicable in the project manager + * since it is not a KIFACE. This header is in the kicad directory since nobody + * else needs to know about it. + */ +class PGM_KICAD : public PGM_BASE +{ +public: + PGM_KICAD() : + m_bm( "kicad" ) // indicates a "$HOME/.kicad wxConfig like" config file. + {} + + ~PGM_KICAD() + { + destroy(); + } + + bool OnPgmInit( wxApp* aWxApp ); // overload PGM_BASE virtual + void OnPgmExit(); // overload PGM_BASE virtual + void MacOpenFile( const wxString& aFileName ); // overload PGM_BASE virtual + + wxFileHistory& GetFileHistory() { return m_bm.m_history; } + + wxConfigBase* PgmSettings() { return m_bm.m_config; } + + SEARCH_STACK& SysSearch() { return m_bm.m_search; } + +protected: + + // The PGM_* classes can have difficulties at termination if they + // are not destroyed soon enough. Relying on a static destructor can be + // too late for contained objects like wxSingleInstanceChecker. + void destroy(); + + BIN_MOD m_bm; +}; + + +extern PGM_KICAD& Pgm(); + +#endif // PGM_KICAD_H_ diff --git a/kicad/preferences.cpp b/kicad/preferences.cpp index b7e046c878..cd9ca87223 100644 --- a/kicad/preferences.cpp +++ b/kicad/preferences.cpp @@ -32,7 +32,7 @@ #endif #include -#include +#include #include #include @@ -43,19 +43,19 @@ void KICAD_MANAGER_FRAME::OnUpdateDefaultPdfBrowser( wxUpdateUIEvent& event ) { - event.Check( wxGetApp().UseSystemPdfBrowser() ); + event.Check( Pgm().UseSystemPdfBrowser() ); } void KICAD_MANAGER_FRAME::OnSelectDefaultPdfBrowser( wxCommandEvent& event ) { - wxGetApp().WritePdfBrowserInfos(); + Pgm().WritePdfBrowserInfos(); } void KICAD_MANAGER_FRAME::OnUpdatePreferredPdfBrowser( wxUpdateUIEvent& event ) { - event.Check( !wxGetApp().UseSystemPdfBrowser() ); + event.Check( !Pgm().UseSystemPdfBrowser() ); } @@ -63,7 +63,7 @@ void KICAD_MANAGER_FRAME::OnSelectPreferredPdfBrowser( wxCommandEvent& event ) { bool select = event.GetId() == ID_SELECT_PREFERED_PDF_BROWSER_NAME; - if( !wxGetApp().GetPdfBrowserFileName() && !select ) + if( !Pgm().GetPdfBrowserName() && !select ) { DisplayError( this, _( "You must choose a PDF viewer before using this option." ) ); @@ -77,8 +77,8 @@ void KICAD_MANAGER_FRAME::OnSelectPreferredPdfBrowser( wxCommandEvent& event ) wildcard = _( "Executable files (" ) + wildcard + wxT( ")|" ) + wildcard; - wxGetApp().ReadPdfBrowserInfos(); - wxFileName fn = wxGetApp().GetPdfBrowserFileName(); + Pgm().ReadPdfBrowserInfos(); + wxFileName fn = Pgm().GetPdfBrowserName(); wxFileDialog dlg( this, _( "Select Preferred Pdf Browser" ), fn.GetPath(), fn.GetFullName(), wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST ); @@ -86,8 +86,8 @@ void KICAD_MANAGER_FRAME::OnSelectPreferredPdfBrowser( wxCommandEvent& event ) if( dlg.ShowModal() == wxID_CANCEL ) return; - wxGetApp().SetPdfBrowserFileName( dlg.GetPath() ); - wxGetApp().WritePdfBrowserInfos(); + Pgm().SetPdfBrowserName( dlg.GetPath() ); + Pgm().WritePdfBrowserInfos(); } diff --git a/kicad/prjconfig.cpp b/kicad/prjconfig.cpp index 8d19791e24..2f5c67ba2c 100644 --- a/kicad/prjconfig.cpp +++ b/kicad/prjconfig.cpp @@ -28,11 +28,12 @@ */ #include -#include +#include +#include #include #include #include -#include +#include #include #include #include @@ -52,9 +53,9 @@ // (Add them in s_KicadManagerParams if any) // Used also to create new .pro files from the kicad.pro template file // for new projects -static const wxString GeneralGroupName( wxT( "/general" ) ); -PARAM_CFG_ARRAY s_KicadManagerParams; +#define GeneralGroupName wxT( "/general" ) +PARAM_CFG_ARRAY s_KicadManagerParams; void KICAD_MANAGER_FRAME::CreateNewProject( const wxString aPrjFullFileName, bool aTemplateSelector = false ) @@ -65,8 +66,8 @@ void KICAD_MANAGER_FRAME::CreateNewProject( const wxString aPrjFullFileName, ClearMsg(); - // Init default config filename - filename = wxGetApp().FindLibraryPath( wxT( "kicad" ) + g_KicadPrjFilenameExtension ); + // default config filename + filename = Pgm().SysSearch().FindValidPath( wxT( "kicad.pro" ) ); // If we are creating a project from a template, make sure the template directory is sane if( aTemplateSelector ) @@ -85,11 +86,11 @@ void KICAD_MANAGER_FRAME::CreateNewProject( const wxString aPrjFullFileName, if( !envStr.EndsWith( sep ) ) envStr += sep; - templatePath = envStr + wxT("template") + sep; + templatePath = envStr + wxT( "template" ) + sep; } else { - templatePath = wxPathOnly(wxStandardPaths::Get().GetExecutablePath()) + + templatePath = wxPathOnly( wxStandardPaths::Get().GetExecutablePath() ) + sep + wxT( ".." ) + sep + wxT( "share" ) + sep + wxT( "template" ) + sep; } @@ -168,8 +169,8 @@ void KICAD_MANAGER_FRAME::CreateNewProject( const wxString aPrjFullFileName, m_ProjectFileName = newProjectName; // Write settings to project file - wxGetApp().WriteProjectConfig( aPrjFullFileName, - GeneralGroupName, s_KicadManagerParams ); + // was: wxGetApp().WriteProjectConfig( aPrjFullFileName, GeneralGroupName, s_KicadManagerParams ); + Prj().ConfigSave( Pgm().SysSearch(), aPrjFullFileName, GeneralGroupName, s_KicadManagerParams ); } @@ -246,31 +247,33 @@ void KICAD_MANAGER_FRAME::OnLoadProject( wxCommandEvent& event ) /* Check if project file exists and if it is not noname.pro */ wxString filename = m_ProjectFileName.GetFullName(); - wxString nameless_prj = NAMELESS_PROJECT; - nameless_prj += g_KicadPrjFilenameExtension; + wxString nameless_prj = NAMELESS_PROJECT wxT( ".pro" ); if( !m_ProjectFileName.FileExists() && !filename.IsSameAs( nameless_prj ) ) { - wxString msg; - msg.Printf( _( "KiCad project file <%s> not found" ), - GetChars( m_ProjectFileName.GetFullPath() ) ); + wxString msg = wxString::Format( + _( "KiCad project file '%s' not found" ), + GetChars( m_ProjectFileName.GetFullPath() ) ); DisplayError( this, msg ); return; } wxSetWorkingDirectory( m_ProjectFileName.GetPath() ); - wxGetApp().ReadProjectConfig( m_ProjectFileName.GetFullPath(), - GeneralGroupName, s_KicadManagerParams, false ); - title = wxGetApp().GetTitle() + wxT( " " ) + GetBuildVersion() + - wxT( " " ) + m_ProjectFileName.GetFullPath(); + // was wxGetApp().ReadProjectConfig( m_ProjectFileName.GetFullPath(), + // GeneralGroupName, s_KicadManagerParams, false ); + Prj().ConfigLoad( Pgm().SysSearch(), m_ProjectFileName.GetFullPath(), + GeneralGroupName, s_KicadManagerParams, false ); + + title = wxT( "KiCad " ) + GetBuildVersion() + wxT( ' ' ) + m_ProjectFileName.GetFullPath(); if( !m_ProjectFileName.IsDirWritable() ) title += _( " [Read Only]" ); SetTitle( title ); - UpdateFileHistory( m_ProjectFileName.GetFullPath() ); + UpdateFileHistory( m_ProjectFileName.GetFullPath(), &Pgm().GetFileHistory() ); + m_LeftWin->ReCreateTreePrj(); #ifdef KICAD_USE_FILES_WATCHER @@ -290,6 +293,9 @@ void KICAD_MANAGER_FRAME::OnSaveProject( wxCommandEvent& event ) if( !IsWritable( m_ProjectFileName ) ) return; - wxGetApp().WriteProjectConfig( m_ProjectFileName.GetFullPath(), - GeneralGroupName, s_KicadManagerParams ); + // was: wxGetApp().WriteProjectConfig( m_ProjectFileName.GetFullPath(), + // GeneralGroupName, s_KicadManagerParams ); + Prj().ConfigSave( Pgm().SysSearch(), m_ProjectFileName.GetFullPath(), + GeneralGroupName, s_KicadManagerParams ); } + diff --git a/kicad/tree_project_frame.cpp b/kicad/tree_project_frame.cpp index bc7134af42..6e6c706371 100644 --- a/kicad/tree_project_frame.cpp +++ b/kicad/tree_project_frame.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include @@ -713,7 +713,7 @@ void TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor( wxCommandEvent& event wxString FullFileName = tree_data->GetFileName(); AddDelimiterString( FullFileName ); - wxString editorname = wxGetApp().GetEditorName(); + wxString editorname = Pgm().GetEditorName(); if( !editorname.IsEmpty() ) ExecuteFile( this, editorname, FullFileName ); diff --git a/new/toolchain-mingw32.cmake b/new/toolchain-mingw32.cmake index cbfb7af14e..3e902ac2d1 100644 --- a/new/toolchain-mingw32.cmake +++ b/new/toolchain-mingw32.cmake @@ -13,15 +13,26 @@ set( CMAKE_SYSTEM_PROCESSOR i686 ) # configure only the lines within this block, typically set( TC_PATH /usr/bin ) -set( CROSS_COMPILE i686-w64-mingw32- ) +set( CROSS_COMPILE x86_64-w64-mingw32- ) # specify the cross compiler set( CMAKE_C_COMPILER ${TC_PATH}/${CROSS_COMPILE}gcc ) set( CMAKE_CXX_COMPILER ${TC_PATH}/${CROSS_COMPILE}g++ ) set( CMAKE_RC_COMPILER ${TC_PATH}/${CROSS_COMPILE}windres ) +# One compiler generates either 32 bit or 64 bit code, -m32 says generate 32 bit: +set( CMAKE_CXX_FLAGS_INIT "-m32" CACHE STRING "C++ flag which generates 32 bit code." ) +set( CMAKE_C_FLAGS_INIT "-m32" CACHE STRING "C flag which generates 32 bit code." ) +set( CMAKE_SHARED_LINKER_FLAGS "-m32" CACHE STRING "Linker flag which finds 32 bit code." ) +set( CMAKE_MODULE_LINKER_FLAGS "-m32" CACHE STRING "Linker flag which finds 32 bit code." ) +set( CMAKE_EXE_LINKER_FLAGS "-m32" CACHE STRING "Linker flag which finds 32 bit code." ) + +# Tell the 64 bit toolchain to generate a PE32 object file when running windres: +set( CMAKE_RC_FLAGS "-F pe-i386" CACHE STRING "windres flag which generates 32 bit code." ) + + # where is the target environment -set( CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 ) +set( CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 ) #---------------------------------------------------- diff --git a/pagelayout_editor/CMakeLists.txt b/pagelayout_editor/CMakeLists.txt index eecc08abd6..3d25ce7ac3 100644 --- a/pagelayout_editor/CMakeLists.txt +++ b/pagelayout_editor/CMakeLists.txt @@ -1,8 +1,6 @@ -add_definitions(-DPL_EDITOR) +set( MAKE_LINK_MAPS true ) -### -# Includes -### +add_definitions(-DPL_EDITOR) include_directories(BEFORE ${INC_BEFORE}) include_directories( @@ -11,12 +9,7 @@ include_directories( ${INC_AFTER} ) - -### -# Sources -### - -set(PL_EDITOR_SRCS +set( PL_EDITOR_SRCS dialogs/properties_frame_base.cpp dialogs/dialogs_for_printing.cpp dialogs/dialog_new_dataitem_base.cpp @@ -30,7 +23,6 @@ set(PL_EDITOR_SRCS onleftclick.cpp onrightclick.cpp page_layout_writer.cpp - pl_editor.cpp pl_editor_config.cpp pl_editor_frame.cpp pl_editor_undo_redo.cpp @@ -40,10 +32,7 @@ set(PL_EDITOR_SRCS toolbars_pl_editor.cpp ) -### -# We need some extra sources from common -### -set(PL_EDITOR_EXTRA_SRCS +set( PL_EDITOR_EXTRA_SRCS ../common/base_screen.cpp ../common/base_units.cpp ../common/eda_text.cpp @@ -51,58 +40,125 @@ set(PL_EDITOR_EXTRA_SRCS ../common/dialogs/dialog_page_settings.cpp ) -### -# Windows resource file -### -if(WIN32) - if(MINGW) - # PL_EDITOR_RESOURCES variable is set by the macro. - mingw_resource_compiler(pl_editor) - else(MINGW) - set(PL_EDITOR_RESOURCES pl_editor.rc) - endif(MINGW) -endif(WIN32) -### -# Apple resource files -### -if(APPLE) - set(PL_EDITOR_RESOURCES pl_editor.icns pl_editor_doc.icns) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/pl_editor.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/pl_editor_doc.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - set(MACOSX_BUNDLE_ICON_FILE pl_editor.icns) - set(MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.pl_editor) -endif(APPLE) +if( MINGW ) + # PL_EDITOR_RESOURCES variable is set by the macro. + mingw_resource_compiler(pl_editor) +endif() -### -# Create the pl_editor executable -### -add_executable(pl_editor WIN32 MACOSX_BUNDLE - ${PL_EDITOR_SRCS} - ${DIALOGS_SRCS} - ${PL_EDITOR_EXTRA_SRCS} - ${PL_EDITOR_RESOURCES}) -### -# Set properties for APPLE on pl_editor target -### -if(APPLE) - set_target_properties(pl_editor PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) -endif(APPLE) +if( USE_KIWAY_DLLS ) -### -# Link executable target pl_editor with correct libraries -### -target_link_libraries(pl_editor common polygon bitmaps - ${OPENGL_LIBRARIES} - ${wxWidgets_LIBRARIES} - ${GDI_PLUS_LIBRARIES}) + # a very small program launcher for pcbnew_kiface + add_executable( pl_editor WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ../common/pgm_base.cpp + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=PL_EDITOR_FRAME_TYPE;PGM_DATA_FILE_EXT=\"kicad_wks\";BUILD_KIWAY_DLL" + ) + target_link_libraries( pl_editor + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. + common + bitmaps + ${wxWidgets_LIBRARIES} + ) + if( MAKE_LINK_MAPS ) + set_target_properties( pl_editor PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=pl_editor.map" ) + endif() -### -# Add pl_editor as install target -### -install(TARGETS pl_editor + # the main pcbnew program, in DSO form. + add_library( pl_editor_kiface MODULE + pl_editor.cpp + ${PL_EDITOR_SRCS} + ${DIALOGS_SRCS} + ${PL_EDITOR_EXTRA_SRCS} + ${PL_EDITOR_RESOURCES} + ) + target_link_libraries( pl_editor_kiface + common + polygon + bitmaps + ${OPENGL_LIBRARIES} + ${wxWidgets_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ) + set_target_properties( pl_editor_kiface PROPERTIES + OUTPUT_NAME pl_editor + PREFIX ${KIFACE_PREFIX} + SUFFIX ${KIFACE_SUFFIX} + ) + set_source_files_properties( pl_editor.cpp PROPERTIES + # The KIFACE is in pcbnew.cpp, export it: + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + if( MAKE_LINK_MAPS ) + set_target_properties( pl_editor_kiface PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=_pl_editor.kiface.map" ) + endif() + + # if building pcbnew, then also build pcbnew_kiface if out of date. + add_dependencies( pl_editor pl_editor_kiface ) + + # these 2 binaries are a matched set, keep them together: + install( TARGETS pl_editor DESTINATION ${KICAD_BIN} - COMPONENT binary) + COMPONENT binary + ) + install( TARGETS pl_editor_kiface + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + + +else() + + add_executable( pl_editor WIN32 MACOSX_BUNDLE + pl_editor.cpp + ${PL_EDITOR_SRCS} + ${DIALOGS_SRCS} + ${PL_EDITOR_EXTRA_SRCS} + ${PL_EDITOR_RESOURCES} + ) + + if( APPLE ) + set_target_properties( pl_editor PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) + endif() + + target_link_libraries( pl_editor + common + polygon + bitmaps + ${OPENGL_LIBRARIES} + ${wxWidgets_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ) + + install( TARGETS pl_editor + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +endif() + + +if( APPLE ) + set( PL_EDITOR_RESOURCES pl_editor.icns pl_editor_doc.icns ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/pl_editor.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/pl_editor_doc.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set( MACOSX_BUNDLE_ICON_FILE pl_editor.icns ) + set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.pl_editor ) + + set_target_properties( pl_editor PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) +endif() + diff --git a/pagelayout_editor/events_functions.cpp b/pagelayout_editor/events_functions.cpp index 0851057923..0473900644 100644 --- a/pagelayout_editor/events_functions.cpp +++ b/pagelayout_editor/events_functions.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/pagelayout_editor/menubar.cpp b/pagelayout_editor/menubar.cpp index 77da7936db..7544f66dd8 100644 --- a/pagelayout_editor/menubar.cpp +++ b/pagelayout_editor/menubar.cpp @@ -29,15 +29,15 @@ #include -#include - +#include +#include #include #include #include #include -void PL_EDITOR_FRAME::ReCreateMenuBar( void ) +void PL_EDITOR_FRAME::ReCreateMenuBar() { // Create and try to get the current menubar wxMenuBar* menuBar = GetMenuBar(); @@ -74,11 +74,13 @@ void PL_EDITOR_FRAME::ReCreateMenuBar( void ) // Add this menu to list menu managed by m_fileHistory // (the file history will be updated when adding/removing files in history if( openRecentMenu ) - wxGetApp().GetFileHistory().RemoveMenu( openRecentMenu ); + Kiface().GetFileHistory().RemoveMenu( openRecentMenu ); openRecentMenu = new wxMenu(); - wxGetApp().GetFileHistory().UseMenu( openRecentMenu ); - wxGetApp().GetFileHistory().AddFilesToMenu(); + + Kiface().GetFileHistory().UseMenu( openRecentMenu ); + Kiface().GetFileHistory().AddFilesToMenu(); + AddMenuItem( fileMenu, openRecentMenu, wxID_ANY, _( "Open &Recent Page Layout File" ), wxEmptyString, KiBitmap( pagelayout_recent_xpm ) ); @@ -132,7 +134,7 @@ void PL_EDITOR_FRAME::ReCreateMenuBar( void ) KiBitmap( editor_xpm ) ); // Language submenu - wxGetApp().AddMenuLanguageList( preferencesMenu ); + Pgm().AddMenuLanguageList( preferencesMenu ); // Hotkey submenu AddHotkeyConfigMenu( preferencesMenu ); diff --git a/pagelayout_editor/pl_editor.cpp b/pagelayout_editor/pl_editor.cpp index f8657090dd..b96b07d4aa 100644 --- a/pagelayout_editor/pl_editor.cpp +++ b/pagelayout_editor/pl_editor.cpp @@ -28,7 +28,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -43,24 +44,113 @@ extern EDA_COLOR_T g_DrawBgColor; -IMPLEMENT_APP( EDA_APP ) +namespace PGE { -/* MacOSX: Needed for file association - * http://wiki.wxwidgets.org/WxMac-specific_topics - */ -void EDA_APP::MacOpenFile( const wxString& aFileName ) +static struct IFACE : public KIFACE_I { - PL_EDITOR_FRAME* frame = ((PL_EDITOR_FRAME*)GetTopWindow()); - wxFileName filename = aFileName; + // Of course all are virtual overloads, implementations of the KIFACE. - if( !filename.FileExists() ) - return; + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} - frame->LoadPageLayoutDescrFile( aFileName ); + bool OnKifaceStart( PGM_BASE* aProgram ); + + void OnKifaceEnd(); + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) + { + switch( aClassId ) + { + case PL_EDITOR_FRAME_TYPE: + { + PL_EDITOR_FRAME* frame = new PL_EDITOR_FRAME( aKiway, aParent ); + + /* Is this really needed since at this point there is no open file? + frame->Zoom_Automatique( true ); // Zoom fit in frame + + if so, why is the constructor not doing it? + */ + + return frame; + } + break; + + default: + ; + } + + return NULL; + } + + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) + { + return NULL; + } + +} kiface( "pl_editor", KIWAY::FACE_PL_EDITOR ); + +} // namespace + +using namespace PGE; + +static PGM_BASE* process; + +KIFACE_I& Kiface() { return kiface; } + + +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram ) +{ + process = (PGM_BASE*) aProgram; + return &kiface; } -bool EDA_APP::OnInit() +PGM_BASE& Pgm() +{ + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} + + +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) +{ + start_common(); + + // Must be called before creating the main frame in order to + // display the real hotkeys in menus or tool tips + ReadHotkeyConfig( wxT("PlEditorFrame"), s_PlEditor_Hokeys_Descr ); + + g_UserUnit = MILLIMETRES; + g_DrawBgColor = WHITE; + g_ShowPageLimits = true; + + return true; +} + + +void IFACE::OnKifaceEnd() +{ + end_common(); +} + + +#if 0 +bool MYFACE::OnKifaceStart( PGM_BASE* aProgram ) + { wxFileName fn; @@ -127,3 +217,4 @@ bool EDA_APP::OnInit() return true; } +#endif diff --git a/pagelayout_editor/pl_editor_config.cpp b/pagelayout_editor/pl_editor_config.cpp index b5b8f12866..1586a5ca2b 100644 --- a/pagelayout_editor/pl_editor_config.cpp +++ b/pagelayout_editor/pl_editor_config.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/pagelayout_editor/pl_editor_frame.cpp b/pagelayout_editor/pl_editor_frame.cpp index f1f378deee..d5defe8d16 100644 --- a/pagelayout_editor/pl_editor_frame.cpp +++ b/pagelayout_editor/pl_editor_frame.cpp @@ -27,7 +27,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -52,11 +53,9 @@ #define PL_EDITOR_FRAME_NAME wxT( "PlEditorFrame" ) -PL_EDITOR_FRAME::PL_EDITOR_FRAME( wxWindow* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle ) : - EDA_DRAW_FRAME( aParent, PL_EDITOR_FRAME_TYPE, aTitle, aPosition, aSize, - aStyle, PL_EDITOR_FRAME_NAME ) +PL_EDITOR_FRAME::PL_EDITOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + EDA_DRAW_FRAME( aKiway, aParent, PL_EDITOR_FRAME_TYPE, wxT( "PlEditorFrame" ), + wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, PL_EDITOR_FRAME_NAME ) { m_FrameName = PL_EDITOR_FRAME_NAME; @@ -79,8 +78,7 @@ PL_EDITOR_FRAME::PL_EDITOR_FRAME( wxWindow* aParent, const wxString& aTitle, wxSize pageSizeIU = GetPageLayout().GetPageSettings().GetSizeIU(); SetScreen( new PL_EDITOR_SCREEN( pageSizeIU ) ); - m_config = wxGetApp().GetSettings(); - LoadSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); if( m_LastGridSizeId < ID_POPUP_GRID_LEVEL_1MM-ID_POPUP_GRID_LEVEL_1000 ) @@ -181,6 +179,28 @@ PL_EDITOR_FRAME::~PL_EDITOR_FRAME() } +bool PL_EDITOR_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) +{ + wxString fn = aFileSet[0]; + + if( !LoadPageLayoutDescrFile( fn ) ) + { + wxString msg = wxString::Format( + _( "Error when loading file '%s'" ), + GetChars( fn ) + ); + + wxMessageBox( msg ); + return false; + } + else + { + OnNewPageLayout(); + return true; + } +} + + void PL_EDITOR_FRAME::OnCloseWindow( wxCloseEvent& Event ) { if( GetScreen()->IsModify() ) @@ -232,7 +252,8 @@ void PL_EDITOR_FRAME::OnCloseWindow( wxCloseEvent& Event ) // do not show the window because we do not want any paint event Show( false ); - wxGetApp().SaveCurrentSetupValues( m_configSettings ); + // was: Pgm().SaveCurrentSetupValues( m_configSettings ); + wxConfigSaveSetups( Kiface().KifaceSettings(), m_configSettings ); // On Linux, m_propertiesPagelayout must be destroyed // before deleting the main frame to avoid a crash when closing @@ -268,31 +289,29 @@ double PL_EDITOR_FRAME::BestZoom() #define PROPERTIES_FRAME_WIDTH_KEY wxT("PropertiesFrameWidth") #define CORNER_ORIGIN_CHOICE_KEY wxT("CornerOriginChoice") -void PL_EDITOR_FRAME::LoadSettings() +void PL_EDITOR_FRAME::LoadSettings( wxConfigBase* aCfg ) { - EDA_DRAW_FRAME::LoadSettings(); - m_config->Read( DESIGN_TREE_WIDTH_KEY, &m_designTreeWidth, 100); - m_config->Read( PROPERTIES_FRAME_WIDTH_KEY, &m_propertiesFrameWidth, 150); - m_config->Read( CORNER_ORIGIN_CHOICE_KEY, &m_originSelectChoice ); + EDA_DRAW_FRAME::LoadSettings( aCfg ); + + aCfg->Read( DESIGN_TREE_WIDTH_KEY, &m_designTreeWidth, 100); + aCfg->Read( PROPERTIES_FRAME_WIDTH_KEY, &m_propertiesFrameWidth, 150); + aCfg->Read( CORNER_ORIGIN_CHOICE_KEY, &m_originSelectChoice ); } -void PL_EDITOR_FRAME::SaveSettings() +void PL_EDITOR_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); - - if( config == NULL ) - return; + EDA_DRAW_FRAME::SaveSettings( aCfg ); m_designTreeWidth = m_treePagelayout->GetSize().x; m_propertiesFrameWidth = m_propertiesPagelayout->GetSize().x; - EDA_DRAW_FRAME::SaveSettings(); - m_config->Write( DESIGN_TREE_WIDTH_KEY, m_designTreeWidth); - m_config->Write( PROPERTIES_FRAME_WIDTH_KEY, m_propertiesFrameWidth); - m_config->Write( CORNER_ORIGIN_CHOICE_KEY, m_originSelectChoice ); + aCfg->Write( DESIGN_TREE_WIDTH_KEY, m_designTreeWidth); + aCfg->Write( PROPERTIES_FRAME_WIDTH_KEY, m_propertiesFrameWidth); + aCfg->Write( CORNER_ORIGIN_CHOICE_KEY, m_originSelectChoice ); - wxGetApp().SaveCurrentSetupValues( GetConfigurationSettings() ); + // was: wxGetApp().SaveCurrentSetupValues( GetConfigurationSettings() ); + wxConfigSaveSetups( aCfg, GetConfigurationSettings() ); } diff --git a/pagelayout_editor/pl_editor_frame.h b/pagelayout_editor/pl_editor_frame.h index c88ed638eb..7ba3a8dc15 100644 --- a/pagelayout_editor/pl_editor_frame.h +++ b/pagelayout_editor/pl_editor_frame.h @@ -30,8 +30,8 @@ #define _PL_EDITOR_FRAME_H -#include -#include +#include +#include #include #include #include @@ -40,22 +40,23 @@ class PROPERTIES_FRAME; class DESIGN_TREE_FRAME; class WORKSHEET_DATAITEM; + /** * Class PL_EDITOR_FRAME * is the main window used in the page layout editor. */ - class PL_EDITOR_FRAME : public EDA_DRAW_FRAME { PL_EDITOR_LAYOUT m_pageLayout; - int m_designTreeWidth; // the last width (in pixels) of m_treePagelayout - int m_propertiesFrameWidth; // the last width (in pixels) of m_propertiesPagelayout - wxConfig* m_config; - wxChoice* m_originSelectBox; // Corner origin choice for coordinates - int m_originSelectChoice; // the last choice for m_originSelectBox - wxChoice* m_pageSelectBox; // The page number sel'ector (page 1 or other pages - // usefull when there are some items which are - // only on page 1, not on page 1 + + int m_designTreeWidth; // the last width (in pixels) of m_treePagelayout + int m_propertiesFrameWidth; // the last width (in pixels) of m_propertiesPagelayout + + wxChoice* m_originSelectBox; // Corner origin choice for coordinates + int m_originSelectChoice; // the last choice for m_originSelectBox + wxChoice* m_pageSelectBox; // The page number sel'ector (page 1 or other pages + // usefull when there are some items which are + // only on page 1, not on page 1 wxPoint m_grid_origin; @@ -70,12 +71,33 @@ private: PARAM_CFG_ARRAY m_configSettings; public: - PL_EDITOR_FRAME( wxWindow* aParent, const wxString& aTitle, - const wxPoint& aPosition, const wxSize& aSize, - long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); - + PL_EDITOR_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~PL_EDITOR_FRAME(); + bool OpenProjectFiles( const std::vector& aFileSet, int aCtl ); // overload KIWAY_PLAYER + + /** + * Function LoadPageLayoutDescrFile + * Loads a .kicad_wks page layout descr file + * @param aFullFileName = the filename. + */ + bool LoadPageLayoutDescrFile( const wxString& aFullFileName ); + + /** + * Function SavePageLayoutDescrFile + * Save the current layout in a .kicad_wks page layout descr file + * @param aFullFileName = the filename. + */ + bool SavePageLayoutDescrFile( const wxString& aFullFileName ); + + /** + * Function InsertPageLayoutDescrFile + * Loads a .kicad_wks page layout descr file, and add items + * to the current layout list + * @param aFullFileName = the filename. + */ + bool InsertPageLayoutDescrFile( const wxString& aFullFileName ); + void OnCloseWindow( wxCloseEvent& Event ); // Virtual basic functions: @@ -172,23 +194,9 @@ public: */ PARAM_CFG_ARRAY& GetConfigurationSettings( void ); - /** - * Load applications settings specific to page layout editor. - * - * This overrides the base class EDA_DRAW_FRAME::LoadSettings(). - */ - virtual void LoadSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual - /** - * Save applications settings common to PCB draw frame objects. - * - * This overrides the base class EDA_DRAW_FRAME::SaveSettings() to - * save settings specific to the application main window. It - * calls down to the base class to save settings common to all - * drawing frames. Please put your application settings for pl editor here - * to avoid having application settings saved all over the place. - */ - virtual void SaveSettings(); + void SaveSettings( wxConfigBase* aCfg ); // override virtual /** * Function SetLanguage @@ -266,28 +274,6 @@ public: void OnFileHistory( wxCommandEvent& event ); - /** - * Function LoadPageLayoutDescrFile - * Loads a .kicad_wks page layout descr file - * @param aFullFileName = the filename. - */ - bool LoadPageLayoutDescrFile( const wxString& aFullFileName ); - - /** - * Function SavePageLayoutDescrFile - * Save the current layout in a .kicad_wks page layout descr file - * @param aFullFileName = the filename. - */ - bool SavePageLayoutDescrFile( const wxString& aFullFileName ); - - /** - * Function InsertPageLayoutDescrFile - * Loads a .kicad_wks page layout descr file, and add items - * to the current layout list - * @param aFullFileName = the filename. - */ - bool InsertPageLayoutDescrFile( const wxString& aFullFileName ); - /** * @return the filename of the current layout descr file * If this is the default (no loaded file) returns a emtpy name diff --git a/pcb_calculator/CMakeLists.txt b/pcb_calculator/CMakeLists.txt index 4bbd5be02d..74be8fe1d7 100644 --- a/pcb_calculator/CMakeLists.txt +++ b/pcb_calculator/CMakeLists.txt @@ -1,5 +1,5 @@ -include_directories(BEFORE ${INC_BEFORE}) +include_directories( BEFORE ${INC_BEFORE} ) include_directories( bitmaps dialogs @@ -10,13 +10,12 @@ include_directories( ${INC_AFTER} ) -set(PCB_CALCULATOR_SRCS +set( PCB_CALCULATOR_SRCS attenuators.cpp board_classes_values.cpp colorcode.cpp electrical_spacing_values.cpp params_read_write.cpp - pcb_calculator.cpp pcb_calculator_frame.cpp datafile_read_write.cpp regulators_funct.cpp @@ -38,24 +37,21 @@ set(PCB_CALCULATOR_SRCS dialogs/dialog_regulator_data_base.cpp ) -if(WIN32) - if(MINGW) - # PCB_CALCULATOR_RESOURCES variable is set by the macro. - mingw_resource_compiler(pcb_calculator) - else(MINGW) - set(PCB_CALCULATOR_RESOURCES pcb_calculator.rc) - endif(MINGW) -endif(WIN32) +if( MINGW ) + # PCB_CALCULATOR_RESOURCES variable is set by the macro. + mingw_resource_compiler(pcb_calculator) +endif() -if(APPLE) - set(PCB_CALCULATOR_RESOURCES pcb_calculator.icns) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/pcb_calculator.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - set(MACOSX_BUNDLE_ICON_FILE pcb_calculator.icns) - set(MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.pcb_calculator) - set(MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) -endif(APPLE) +if( APPLE ) + set( PCB_CALCULATOR_RESOURCES pcb_calculator.icns ) + set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/pcb_calculator.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set( MACOSX_BUNDLE_ICON_FILE pcb_calculator.icns ) + set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.pcb_calculator ) + set( MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ) +endif() # auto-generate pcb_calculator_datafile.h and pcb_calculator_datafile_keywords.cpp # for the storage data file format. @@ -70,25 +66,103 @@ make_lexer( ) -add_executable(pcb_calculator WIN32 MACOSX_BUNDLE - ${PCB_CALCULATOR_SRCS} - ${PCB_CALCULATOR_RESOURCES} - ) +if( USE_KIWAY_DLLS ) +#if( false ) + add_executable( pcb_calculator WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ../common/pgm_base.cpp + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=0;BUILD_KIWAY_DLL" + ) + target_link_libraries( pcb_calculator + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. + common + bitmaps + ${wxWidgets_LIBRARIES} + ) + if( MAKE_LINK_MAPS ) + set_target_properties( pcb_calculator PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=pcb_calculator.map" ) + endif() -if(APPLE) - set_target_properties(pcb_calculator PROPERTIES MACOSX_BUNDLE_INFO_PLIST - ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) -endif(APPLE) + # the main pcb_calculator program, in DSO form. + add_library( pcb_calculator_kiface MODULE + pcb_calculator.cpp + ${PCB_CALCULATOR_SRCS} + ${PCB_CALCULATOR_RESOURCES} + ) + set_target_properties( pcb_calculator_kiface PROPERTIES + OUTPUT_NAME pcb_calculator + PREFIX ${KIFACE_PREFIX} + SUFFIX ${KIFACE_SUFFIX} + ) + target_link_libraries( pcb_calculator_kiface + common + bitmaps + polygon + ${wxWidgets_LIBRARIES} + ) + set_source_files_properties( pcb_calculator.cpp PROPERTIES + # The KIFACE is in pcb_calculator.cpp, export it: + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + if( MAKE_LINK_MAPS ) + set_target_properties( pcb_calculator_kiface PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=_pcb_calculator.kiface.map" ) + endif() -target_link_libraries( pcb_calculator - common - bitmaps - polygon - ${wxWidgets_LIBRARIES} - ) + # if building pcb_calculator, then also build pcb_calculator_kiface if out of date. + add_dependencies( pcb_calculator pcb_calculator_kiface ) -install(TARGETS pcb_calculator + # these 2 binaries are a matched set, keep them together + install( TARGETS pcb_calculator DESTINATION ${KICAD_BIN} - COMPONENT binary) + COMPONENT binary + ) + install( TARGETS pcb_calculator_kiface + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + if( APPLE ) + set_target_properties( pcb_calculator PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) + endif() + +else() + + add_executable( pcb_calculator WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + pcb_calculator.cpp + ${PCB_CALCULATOR_SRCS} + ${PCB_CALCULATOR_RESOURCES} + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=0" + ) + set_source_files_properties( pcb_calculator.cpp PROPERTIES + COMPILE_DEFINITIONS "COMPILING_DLL" + ) + + if( APPLE ) + set_target_properties( pcb_calculator PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + ) + endif() + + target_link_libraries( pcb_calculator + common + bitmaps + polygon + ${wxWidgets_LIBRARIES} + ) + install( TARGETS pcb_calculator + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +endif() diff --git a/pcb_calculator/attenuators.cpp b/pcb_calculator/attenuators.cpp index 18c02cd448..b2f27a2c58 100644 --- a/pcb_calculator/attenuators.cpp +++ b/pcb_calculator/attenuators.cpp @@ -30,7 +30,7 @@ #include #include -extern double ReturnDoubleFromString( const wxString& TextValue ); +extern double DoubleFromString( const wxString& TextValue ); // Called on a attenuator selection void PCB_CALCULATOR_FRAME::OnAttenuatorSelection( wxCommandEvent& event ) @@ -66,11 +66,11 @@ void PCB_CALCULATOR_FRAME::TransfPanelDataToAttenuator() wxString msg; msg = m_AttValueCtrl->GetValue(); - m_currAttenuator->m_Attenuation = ReturnDoubleFromString(msg); + m_currAttenuator->m_Attenuation = DoubleFromString(msg); msg = m_ZinValueCtrl->GetValue(); - m_currAttenuator->m_Zin = ReturnDoubleFromString(msg); + m_currAttenuator->m_Zin = DoubleFromString(msg); msg = m_ZoutValueCtrl->GetValue(); - m_currAttenuator->m_Zout = ReturnDoubleFromString(msg); + m_currAttenuator->m_Zout = DoubleFromString(msg); } diff --git a/pcb_calculator/attenuators/attenuator_classes.cpp b/pcb_calculator/attenuators/attenuator_classes.cpp index 122480ec39..ebec3d887e 100644 --- a/pcb_calculator/attenuators/attenuator_classes.cpp +++ b/pcb_calculator/attenuators/attenuator_classes.cpp @@ -52,7 +52,7 @@ ATTENUATOR::~ATTENUATOR() #define KEYWORD_ATTENUATOR_ZOUT wxT( "Zout" ) #define KEYWORD_ATTENUATORS wxT( "Attenuators/" ) -void ATTENUATOR::ReadConfig( wxConfig* aConfig ) +void ATTENUATOR::ReadConfig( wxConfigBase* aConfig ) { aConfig->SetPath( KEYWORD_ATTENUATORS + m_Name ); if( m_Attenuation_Enable ) @@ -63,7 +63,7 @@ void ATTENUATOR::ReadConfig( wxConfig* aConfig ) } -void ATTENUATOR::WriteConfig( wxConfig* aConfig ) +void ATTENUATOR::WriteConfig( wxConfigBase* aConfig ) { aConfig->SetPath( KEYWORD_ATTENUATORS + m_Name ); aConfig->Write( KEYWORD_ATTENUATOR_ATT, m_Attenuation ); diff --git a/pcb_calculator/attenuators/attenuator_classes.h b/pcb_calculator/attenuators/attenuator_classes.h index 65a3705ee9..a2014fa4a2 100644 --- a/pcb_calculator/attenuators/attenuator_classes.h +++ b/pcb_calculator/attenuators/attenuator_classes.h @@ -64,14 +64,14 @@ public: * Read values stored in config for this attenuator * @param aConfig = the config to use */ - void ReadConfig( wxConfig* aConfig ); + void ReadConfig( wxConfigBase* aConfig ); /** * Function WriteConfig * Read values stored in config for this attenuator * @param aConfig = the config to use */ - void WriteConfig( wxConfig* aConfig ); + void WriteConfig( wxConfigBase* aConfig ); }; class ATTENUATOR_PI : public ATTENUATOR diff --git a/pcb_calculator/datafile_read_write.cpp b/pcb_calculator/datafile_read_write.cpp index 618e426166..aef8427ca9 100644 --- a/pcb_calculator/datafile_read_write.cpp +++ b/pcb_calculator/datafile_read_write.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include @@ -127,7 +127,7 @@ int PCB_CALCULATOR_DATAFILE::WriteHeader( OUTPUTFORMATTER* aFormatter ) const th aFormatter->Print( nestlevel++, "(date %s)\n", aFormatter->Quotew( DateAndTime() ).c_str() ); aFormatter->Print( nestlevel++, "(tool %s)\n", - aFormatter->Quotew( wxGetApp().GetAppName() + + aFormatter->Quotew( Pgm().App().GetAppName() + wxChar(' ') + GetBuildVersion() ).c_str() ); return nestlevel; diff --git a/pcb_calculator/dialogs/pcb_calculator_frame_base.cpp b/pcb_calculator/dialogs/pcb_calculator_frame_base.cpp index abb5da9576..c20b6b5080 100644 --- a/pcb_calculator/dialogs/pcb_calculator_frame_base.cpp +++ b/pcb_calculator/dialogs/pcb_calculator_frame_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 5 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -20,7 +20,7 @@ /////////////////////////////////////////////////////////////////////////// -PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) +PCB_CALCULATOR_FRAME_BASE::PCB_CALCULATOR_FRAME_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : KIWAY_PLAYER( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); diff --git a/pcb_calculator/dialogs/pcb_calculator_frame_base.fbp b/pcb_calculator/dialogs/pcb_calculator_frame_base.fbp index 5970dafbc8..da5cd391c3 100644 --- a/pcb_calculator/dialogs/pcb_calculator_frame_base.fbp +++ b/pcb_calculator/dialogs/pcb_calculator_frame_base.fbp @@ -20,8 +20,10 @@ . 1 + 1 1 1 + UI 0 0 @@ -44,7 +46,7 @@ 670,489 wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER - + KIWAY_PLAYER; kiway_player.h Pcb Calculator @@ -472,7 +474,7 @@ - Load From File; F:\kicad-launchpad\testing\pcb_calculator\bitmaps\regul_3pins.xpm + Load From File; ../bitmaps/regul_3pins.xpm 1 0 @@ -3266,7 +3268,7 @@ Track Width 0 - + 1 1 1 @@ -7332,7 +7334,7 @@ Electrical Spacing 0 - + 1 1 1 @@ -8180,7 +8182,7 @@ TransLine 0 - + 1 1 1 @@ -14621,7 +14623,7 @@ RF Attenuators 0 - + 1 1 1 @@ -16952,11 +16954,11 @@ - + Color Code 0 - + 1 1 1 @@ -18130,11 +18132,11 @@ - + Board Classes 0 - + 1 1 1 diff --git a/pcb_calculator/dialogs/pcb_calculator_frame_base.h b/pcb_calculator/dialogs/pcb_calculator_frame_base.h index 117707e747..4c6c666d59 100644 --- a/pcb_calculator/dialogs/pcb_calculator_frame_base.h +++ b/pcb_calculator/dialogs/pcb_calculator_frame_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Oct 8 2012) +// C++ code generated with wxFormBuilder (version Nov 5 2013) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -11,11 +11,13 @@ #include #include #include +class KIWAY_PLAYER; class UNIT_SELECTOR_ANGLE; class UNIT_SELECTOR_FREQUENCY; class UNIT_SELECTOR_LEN; class UNIT_SELECTOR_RESISTOR; +#include "kiway_player.h" #include #include #include @@ -48,7 +50,7 @@ class UNIT_SELECTOR_RESISTOR; /////////////////////////////////////////////////////////////////////////////// /// Class PCB_CALCULATOR_FRAME_BASE /////////////////////////////////////////////////////////////////////////////// -class PCB_CALCULATOR_FRAME_BASE : public wxFrame +class PCB_CALCULATOR_FRAME_BASE : public KIWAY_PLAYER { private: diff --git a/pcb_calculator/electrical_spacing_values.cpp b/pcb_calculator/electrical_spacing_values.cpp index 66609d3533..5a9213b61f 100644 --- a/pcb_calculator/electrical_spacing_values.cpp +++ b/pcb_calculator/electrical_spacing_values.cpp @@ -30,7 +30,7 @@ #include #include -extern double ReturnDoubleFromString( const wxString& TextValue ); +extern double DoubleFromString( const wxString& TextValue ); #define VALUE_COUNT 7 @@ -122,7 +122,7 @@ void PCB_CALCULATOR_FRAME::ElectricalSpacingUpdateData( double aUnitScale ) double voltage = 500.0; // to calculate values at V > 500V txt = m_ElectricalSpacingVoltage->GetValue(); if( ! txt.IsEmpty() ) - voltage = ReturnDoubleFromString(txt); + voltage = DoubleFromString(txt); if( voltage < 500.0 ) voltage = 500.0; txt.Printf( wxT( "%g" ), voltage ); diff --git a/pcb_calculator/params_read_write.cpp b/pcb_calculator/params_read_write.cpp index b1f787c8ef..2261943f4b 100644 --- a/pcb_calculator/params_read_write.cpp +++ b/pcb_calculator/params_read_write.cpp @@ -39,7 +39,7 @@ * but units are ignored. * notation like 1e+3 is legal */ -double ReturnDoubleFromString( const wxString& TextValue ) +double DoubleFromString( const wxString& TextValue ) { double value = 0; diff --git a/pcb_calculator/pcb_calculator.cpp b/pcb_calculator/pcb_calculator.cpp index adeae6d2a6..cfec7e2135 100644 --- a/pcb_calculator/pcb_calculator.cpp +++ b/pcb_calculator/pcb_calculator.cpp @@ -22,7 +22,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include -#include +#include +#include #include #include #include @@ -43,24 +44,88 @@ const wxString PcbCalcDataFileExt( wxT("pcbcalc") ); // PCB_CALCULATOR_APP -void EDA_APP::MacOpenFile( const wxString& aFileName ) + +namespace PCBCALC { + +static struct IFACE : public KIFACE_I { + // Of course all are virtual overloads, implementations of the KIFACE. + + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} + + bool OnKifaceStart( PGM_BASE* aProgram ); + + void OnKifaceEnd(); + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) + { + switch( aClassId ) + { + default: + { + PCB_CALCULATOR_FRAME* frame = new PCB_CALCULATOR_FRAME( aKiway, aParent ); + return frame; + } + break; + } + + return NULL; + } + + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) + { + return NULL; + } + +} kiface( "pcb_calculator", KIWAY::FACE_PCB_CALCULATOR ); + +} // namespace + +using namespace PCBCALC; + +static PGM_BASE* process; + +KIFACE_I& Kiface() { return kiface; } + + +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram ) +{ + process = (PGM_BASE*) aProgram; + return &kiface; } -IMPLEMENT_APP( EDA_APP ) -///----------------------------------------------------------------------------- -// PCB_CALCULATOR_APP -// main program -//----------------------------------------------------------------------------- - -bool EDA_APP::OnInit() +PGM_BASE& Pgm() { - InitEDA_Appl( wxT( "pcb_calculator" ) ); + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} - wxFrame* frame = new PCB_CALCULATOR_FRAME( NULL ); - SetTopWindow( frame ); - frame->Show( true ); + +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) +{ + start_common(); return true; } + + +void IFACE::OnKifaceEnd() +{ + end_common(); +} diff --git a/pcb_calculator/pcb_calculator.h b/pcb_calculator/pcb_calculator.h index 4c09da39d9..808b5da208 100644 --- a/pcb_calculator/pcb_calculator.h +++ b/pcb_calculator/pcb_calculator.h @@ -40,13 +40,13 @@ private: public: - PCB_CALCULATOR_FRAME( wxWindow * parent = NULL ); + PCB_CALCULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ); ~PCB_CALCULATOR_FRAME(); private: // Event handlers - void OnClosePcbCalc( wxCloseEvent& event ); + void OnClosePcbCalc( wxCloseEvent& event ); // These 3 functions are called by the OnPaint event, to draw // icons that show the current item on the specific panels @@ -178,12 +178,12 @@ private: // Regulators Panel void OnRegulatorCalcButtonClick( wxCommandEvent& event ); - void OnRegulTypeSelection( wxCommandEvent& event ); - void OnRegulatorSelection( wxCommandEvent& event ); - void OnDataFileSelection( wxCommandEvent& event ); - void OnAddRegulator( wxCommandEvent& event ); - void OnEditRegulator( wxCommandEvent& event ); - void OnRemoveRegulator( wxCommandEvent& event ); + void OnRegulTypeSelection( wxCommandEvent& event ); + void OnRegulatorSelection( wxCommandEvent& event ); + void OnDataFileSelection( wxCommandEvent& event ); + void OnAddRegulator( wxCommandEvent& event ); + void OnEditRegulator( wxCommandEvent& event ); + void OnRemoveRegulator( wxCommandEvent& event ); /** * Function RegulatorPageUpdate: diff --git a/pcb_calculator/pcb_calculator_frame.cpp b/pcb_calculator/pcb_calculator_frame.cpp index ab32faa8bd..9482a6ee83 100644 --- a/pcb_calculator/pcb_calculator_frame.cpp +++ b/pcb_calculator/pcb_calculator_frame.cpp @@ -52,9 +52,11 @@ // extention of pcb_calculator data filename: const wxString DataFileNameExt( wxT("pcbcalc") ); -PCB_CALCULATOR_FRAME::PCB_CALCULATOR_FRAME( wxWindow* parent ) : - PCB_CALCULATOR_FRAME_BASE( parent ) +PCB_CALCULATOR_FRAME::PCB_CALCULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + PCB_CALCULATOR_FRAME_BASE( aParent ) { + SetKiway( this, aKiway ); + m_currTransLine = NULL; m_currTransLineType = default_type; m_currAttenuator = NULL; @@ -62,7 +64,7 @@ PCB_CALCULATOR_FRAME::PCB_CALCULATOR_FRAME( wxWindow* parent ) : m_Config = new wxConfig(); // Populate transline list ordered like in dialog menu list - transline_type_id tltype_list[8] = + const static transline_type_id tltype_list[8] = { microstrip_type, cpw_type, grounded_cpw_type, rectwaveguide_type, coax_type, c_microstrip_type, diff --git a/pcb_calculator/regulators_funct.cpp b/pcb_calculator/regulators_funct.cpp index 97dd64ee9c..d8995f48ea 100644 --- a/pcb_calculator/regulators_funct.cpp +++ b/pcb_calculator/regulators_funct.cpp @@ -33,7 +33,7 @@ #include -extern double ReturnDoubleFromString( const wxString& TextValue ); +extern double DoubleFromString( const wxString& TextValue ); class DIALOG_EDITOR_DATA: public DIALOG_EDITOR_DATA_BASE { @@ -49,7 +49,7 @@ public: ~DIALOG_EDITOR_DATA() {}; // Event called functions: - void OnOKClick( wxCommandEvent& event ); + void OnOKClick( wxCommandEvent& event ); /** * Function IsOK() @@ -113,7 +113,7 @@ bool DIALOG_EDITOR_DATA::IsOK() ok = false; else { - double vref = ReturnDoubleFromString( m_textCtrlVref->GetValue() ); + double vref = DoubleFromString( m_textCtrlVref->GetValue() ); if( fabs(vref) < 0.01 ) ok = false; } @@ -140,8 +140,8 @@ void DIALOG_EDITOR_DATA::CopyRegulatorDataToDialog( REGULATOR_DATA * aItem ) REGULATOR_DATA * DIALOG_EDITOR_DATA::BuildRegulatorFromData() { - double vref = ReturnDoubleFromString( m_textCtrlVref->GetValue() ); - double iadj = ReturnDoubleFromString( m_RegulIadjValue->GetValue() ); + double vref = DoubleFromString( m_textCtrlVref->GetValue() ); + double iadj = DoubleFromString( m_RegulIadjValue->GetValue() ); int type = m_choiceRegType->GetSelection(); if( type != 1 ) iadj = 0.0; @@ -382,13 +382,13 @@ void PCB_CALCULATOR_FRAME::RegulatorsSolve() // Read values from panel: txt = m_RegulR1Value->GetValue(); - r1 = ReturnDoubleFromString(txt) * r1scale; + r1 = DoubleFromString(txt) * r1scale; txt = m_RegulR2Value->GetValue(); - r2 = ReturnDoubleFromString(txt) * r2scale; + r2 = DoubleFromString(txt) * r2scale; txt = m_RegulVrefValue->GetValue(); - vref = ReturnDoubleFromString(txt); + vref = DoubleFromString(txt); txt = m_RegulVoutValue->GetValue(); - vout = ReturnDoubleFromString(txt); + vout = DoubleFromString(txt); // Some tests: @@ -415,7 +415,7 @@ void PCB_CALCULATOR_FRAME::RegulatorsSolve() { // 3 terminal regulator txt = m_RegulIadjValue->GetValue(); - double iadj = ReturnDoubleFromString(txt); + double iadj = DoubleFromString(txt); // iadj is given in micro amp, so convert it in amp. iadj /= 1000000; diff --git a/pcb_calculator/tracks_width_versus_current.cpp b/pcb_calculator/tracks_width_versus_current.cpp index 331dbac0a0..bdedd47e1f 100644 --- a/pcb_calculator/tracks_width_versus_current.cpp +++ b/pcb_calculator/tracks_width_versus_current.cpp @@ -37,7 +37,7 @@ #include #include -extern double ReturnDoubleFromString( const wxString& TextValue ); +extern double DoubleFromString( const wxString& TextValue ); // Key words to read/write some parameters in config: #define KEYWORD_TW_CURRENT wxT( "TW_Track_Current" ) @@ -67,10 +67,10 @@ void PCB_CALCULATOR_FRAME::TW_WriteConfig() void PCB_CALCULATOR_FRAME::OnTWCalculateButt( wxCommandEvent& event ) { // Prepare parameters: - double current = ReturnDoubleFromString( m_TrackCurrentValue->GetValue() ); - double thickness = ReturnDoubleFromString( m_TrackThicknessValue->GetValue() ); - double deltaT_C = ReturnDoubleFromString( m_TrackDeltaTValue->GetValue() ); - double track_len = ReturnDoubleFromString( m_TrackLengthValue->GetValue() ); + double current = DoubleFromString( m_TrackCurrentValue->GetValue() ); + double thickness = DoubleFromString( m_TrackThicknessValue->GetValue() ); + double deltaT_C = DoubleFromString( m_TrackDeltaTValue->GetValue() ); + double track_len = DoubleFromString( m_TrackLengthValue->GetValue() ); double extTrackWidth; double intTrackWidth; diff --git a/pcb_calculator/transline_dlg_funct.cpp b/pcb_calculator/transline_dlg_funct.cpp index dea6bfde6e..50ee7ea4fa 100644 --- a/pcb_calculator/transline_dlg_funct.cpp +++ b/pcb_calculator/transline_dlg_funct.cpp @@ -30,7 +30,7 @@ #include #include -extern double ReturnDoubleFromString( const wxString& TextValue ); +extern double DoubleFromString( const wxString& TextValue ); /* @@ -359,7 +359,7 @@ void PCB_CALCULATOR_FRAME::TransfDlgDataToTranslineParams() TRANSLINE_PRM* prm = tr_ident->GetPrm( ii ); wxTextCtrl * value_ctrl = (wxTextCtrl * ) prm->m_ValueCtrl; wxString value_txt = value_ctrl->GetValue(); - double value = ReturnDoubleFromString(value_txt); + double value = DoubleFromString(value_txt); prm->m_Value = value; UNIT_SELECTOR * unit_ctrl = (UNIT_SELECTOR * ) prm->m_UnitCtrl; if( unit_ctrl ) diff --git a/pcb_calculator/transline_ident.cpp b/pcb_calculator/transline_ident.cpp index 44e0a4fcca..48369d0c03 100644 --- a/pcb_calculator/transline_ident.cpp +++ b/pcb_calculator/transline_ident.cpp @@ -53,7 +53,7 @@ TRANSLINE_PRM::TRANSLINE_PRM( PRM_TYPE aType, PRMS_ID aId, #define TRANSLINE_PRM_KEY wxT( "translineprm%d" ) -void TRANSLINE_PRM::ReadConfig( wxConfig* aConfig ) +void TRANSLINE_PRM::ReadConfig( wxConfigBase* aConfig ) { if( m_Id == UNKNOWN_ID || m_Id == DUMMY_PRM ) return; @@ -65,7 +65,7 @@ void TRANSLINE_PRM::ReadConfig( wxConfig* aConfig ) } -void TRANSLINE_PRM::WriteConfig( wxConfig* aConfig ) +void TRANSLINE_PRM::WriteConfig( wxConfigBase* aConfig ) { if( m_Id == UNKNOWN_ID || m_Id == DUMMY_PRM ) return; @@ -415,7 +415,7 @@ TRANSLINE_IDENT::~TRANSLINE_IDENT() } -void TRANSLINE_IDENT::ReadConfig( wxConfig* aConfig ) +void TRANSLINE_IDENT::ReadConfig( wxConfigBase* aConfig ) { wxString text = wxString::FromUTF8( m_TLine->m_name ); aConfig->SetPath( text ); @@ -426,7 +426,7 @@ void TRANSLINE_IDENT::ReadConfig( wxConfig* aConfig ) } -void TRANSLINE_IDENT::WriteConfig( wxConfig* aConfig ) +void TRANSLINE_IDENT::WriteConfig( wxConfigBase* aConfig ) { wxString text = wxString::FromUTF8( m_TLine->m_name ); aConfig->SetPath( text ); diff --git a/pcb_calculator/transline_ident.h b/pcb_calculator/transline_ident.h index 4e607ea78c..45854a7877 100644 --- a/pcb_calculator/transline_ident.h +++ b/pcb_calculator/transline_ident.h @@ -54,8 +54,8 @@ public: TRANSLINE_PRM( PRM_TYPE aType, PRMS_ID aId, double aValue = 0.0, bool aConvUnit = false ); - void ReadConfig( wxConfig* aConfig ); - void WriteConfig( wxConfig* aConfig ); + void ReadConfig( wxConfigBase* aConfig ); + void WriteConfig( wxConfigBase* aConfig ); double ToUserUnit(); double FromUserUnit(); }; @@ -100,8 +100,8 @@ public: TRANSLINE_IDENT( enum transline_type_id aType ); } - void ReadConfig( wxConfig* aConfig ); - void WriteConfig( wxConfig* aConfig ); + void ReadConfig( wxConfigBase* aConfig ); + void WriteConfig( wxConfigBase* aConfig ); }; #endif // TRANSLINE_IDENT_H diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 3c7d4f567f..2bff12e75a 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -1,5 +1,4 @@ - -set( MAKE_LINK_MAPS false ) +set( MAKE_LINK_MAPS true ) add_definitions( -DPCBNEW ) add_subdirectory(router) @@ -16,9 +15,6 @@ if( KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES ) endif() -### -# Includes -### include_directories( BEFORE ${INC_BEFORE} ) include_directories( ./dialogs @@ -33,9 +29,6 @@ include_directories( ${INC_AFTER} ) -### -# Sources -# set( PCBNEW_DIALOGS dialogs/dialog_block_options_base.cpp dialogs/dialog_cleaning_options_base.cpp @@ -213,7 +206,6 @@ set( PCBNEW_CLASS_SRCS onleftclick.cpp onrightclick.cpp pad_edition_functions.cpp - pcbnew.cpp pcbnew_config.cpp pcbplot.cpp plot_board_layers.cpp @@ -258,23 +250,18 @@ set( PCBNEW_CLASS_SRCS set( PCBNEW_SRCS ${PCBNEW_AUTOROUTER_SRCS} ${PCBNEW_CLASS_SRCS} ${PCBNEW_DIALOGS} ) -### -# We need some extra sources from common -### + +# extra sources from common set( PCBNEW_COMMON_SRCS ../common/dialogs/dialog_page_settings.cpp ../common/base_units.cpp ) -## -# Scripting sources -## set( PCBNEW_SCRIPTING_DIALOGS dialogs/dialog_scripting_base.cpp dialogs/dialog_scripting.cpp ) - set( PCBNEW_SCRIPTING_PYTHON_HELPERS ../scripting/wx_python_helpers.cpp ../scripting/python_scripting.cpp @@ -287,12 +274,9 @@ if( KICAD_SCRIPTING ) ${PCBNEW_SCRIPTING_DIALOGS} pcbnew_wrap.cxx ${PCBNEW_SCRIPTING_PYTHON_HELPERS} - ) + ) endif() -## -# Scripting build -## if( KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES ) @@ -359,7 +343,7 @@ if( BUILD_GITHUB_PLUGIN ) set( GITHUB_PLUGIN_LIBRARIES github_plugin ) endif() -if( ( KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES ) AND NOT WIN32 AND NOT APPLE ) +if( UNIX AND NOT APPLE ) list( APPEND PCBNEW_EXTRA_LIBS rt ) endif() @@ -394,8 +378,8 @@ if( KICAD_SCRIPTING_MODULES ) ) if( MAKE_LINK_MAPS ) - # generate a link map with cross reference - set_target_properties( _pcbnew PROPERTIES LINK_FLAGS "-Wl,-cref -Wl,-Map=_pcbnew.map" ) + set_target_properties( _pcbnew PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=pcbnew.so.map" ) endif() endif() @@ -449,28 +433,19 @@ endif() - -### -# Windows resource file -### -if( WIN32 ) - if( MINGW ) - # PCBNEW_RESOURCES variable is set by the macro. - mingw_resource_compiler( pcbnew ) - else() - set( PCBNEW_RESOURCES pcbnew.rc ) - endif() +if( MINGW ) + # PCBNEW_RESOURCES variable is set by the macro. + mingw_resource_compiler( pcbnew ) endif() -### -# Set properties for APPLE on pcbnew target -### if( APPLE ) set( PCBNEW_RESOURCES pcbnew.icns pcbnew_doc.icns ) - set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/pcbnew.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) - set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/pcbnew_doc.icns" - PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/pcbnew.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/pcbnew_doc.icns" PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) set( MACOSX_BUNDLE_ICON_FILE pcbnew.icns ) set( MACOSX_BUNDLE_GUI_IDENTIFIER org.kicad-eda.pcbnew ) set( MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ) @@ -506,84 +481,159 @@ make_lexer( ) -### -# subcomponents of pcbnew -### add_subdirectory( pcad2kicadpcb_plugin ) if( BUILD_GITHUB_PLUGIN ) add_subdirectory( github ) endif() -### -# Create the pcbnew executable -### -add_executable( pcbnew WIN32 MACOSX_BUNDLE - ${PCBNEW_SRCS} - ${PCBNEW_COMMON_SRCS} - ${PCBNEW_SCRIPTING_SRCS} - ${PCBNEW_RESOURCES} - ) +if( USE_KIWAY_DLLS ) + + # a very small program launcher for pcbnew_kiface + add_executable( pcbnew WIN32 MACOSX_BUNDLE + ../common/single_top.cpp + ../common/pgm_base.cpp + ) + set_source_files_properties( ../common/single_top.cpp PROPERTIES + COMPILE_DEFINITIONS "TOP_FRAME=PCB_FRAME_TYPE;PGM_DATA_FILE_EXT=\"kicad_pcb\";BUILD_KIWAY_DLL" + ) + target_link_libraries( pcbnew + #singletop # replaces common, giving us restrictive control and link warnings. + # There's way too much crap coming in from common yet. + common + bitmaps + ${wxWidgets_LIBRARIES} + ) + if( MAKE_LINK_MAPS ) + set_target_properties( pcbnew PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=pcbnew.map" ) + endif() + + # the main pcbnew program, in DSO form. + add_library( pcbnew_kiface MODULE + pcbnew.cpp + ${PCBNEW_SRCS} + ${PCBNEW_COMMON_SRCS} + ${PCBNEW_SCRIPTING_SRCS} + ${PCBNEW_RESOURCES} + ) + set_target_properties( pcbnew_kiface PROPERTIES + # Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like + # _pcbnew.so, _pcbnew.dll, or _pcbnew.kiface + OUTPUT_NAME pcbnew + PREFIX ${KIFACE_PREFIX} + SUFFIX ${KIFACE_SUFFIX} + ) + target_link_libraries( pcbnew_kiface + 3d-viewer + pcbcommon + pnsrouter + common + pcad2kicadpcb + polygon + bitmaps + gal + lib_dxf + ${GITHUB_PLUGIN_LIBRARIES} + ${wxWidgets_LIBRARIES} + ${OPENGL_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ${PYTHON_LIBRARIES} + ${GLEW_LIBRARIES} + ${CAIRO_LIBRARIES} + ${PIXMAN_LIBRARY} + ${Boost_LIBRARIES} # must follow GITHUB + ${PCBNEW_EXTRA_LIBS} # -lrt must follow Boost + ) + set_source_files_properties( pcbnew.cpp PROPERTIES + # The KIFACE is in pcbnew.cpp, export it: + COMPILE_DEFINITIONS "BUILD_KIWAY_DLL;COMPILING_DLL" + ) + if( MAKE_LINK_MAPS ) + set_target_properties( pcbnew_kiface PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=_pcbnew.kiface.map" ) + endif() + + # if building pcbnew, then also build pcbnew_kiface if out of date. + add_dependencies( pcbnew pcbnew_kiface ) + + # these 2 binaries are a matched set, keep them together: + install( TARGETS pcbnew + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + install( TARGETS pcbnew_kiface + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +else() # milestone A) kills this off: + + add_executable( pcbnew WIN32 MACOSX_BUNDLE + pcbnew.cpp + ${PCBNEW_SRCS} + ${PCBNEW_COMMON_SRCS} + ${PCBNEW_SCRIPTING_SRCS} + ${PCBNEW_RESOURCES} + ) + target_link_libraries( pcbnew + 3d-viewer + pcbcommon + pnsrouter + common + pcad2kicadpcb + polygon + bitmaps + gal + lib_dxf + ${GITHUB_PLUGIN_LIBRARIES} + ${wxWidgets_LIBRARIES} + ${OPENGL_LIBRARIES} + ${GDI_PLUS_LIBRARIES} + ${PYTHON_LIBRARIES} + ${GLEW_LIBRARIES} + ${CAIRO_LIBRARIES} + ${PIXMAN_LIBRARY} + ${Boost_LIBRARIES} # must follow GITHUB + ${PCBNEW_EXTRA_LIBS} + ) + + # Only for win32 cross compilation using MXE + if( WIN32 AND MSYS AND CMAKE_CROSSCOMPILING ) + target_link_libraries( pcbnew + opengl32 + glu32 + pixman-1 + fontconfig + freetype + bz2 + ) + endif() + + install( TARGETS pcbnew + DESTINATION ${KICAD_BIN} + COMPONENT binary + ) + +endif() + ### # Set properties for APPLE on pcbnew target ### if( APPLE ) - set_target_properties( pcbnew PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ) + set_target_properties( pcbnew PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ) endif() -### -# Link executable target pcbnew with correct libraries -### - -target_link_libraries( pcbnew - 3d-viewer - pcbcommon - pnsrouter - common - pcad2kicadpcb - polygon - bitmaps - gal - lib_dxf - ${GITHUB_PLUGIN_LIBRARIES} - ${wxWidgets_LIBRARIES} - ${OPENGL_LIBRARIES} - ${GDI_PLUS_LIBRARIES} - ${PYTHON_LIBRARIES} - ${PCBNEW_EXTRA_LIBS} - ${GLEW_LIBRARIES} - ${CAIRO_LIBRARIES} - ${PIXMAN_LIBRARY} - ${Boost_LIBRARIES} # must follow GITHUB - ) - -# Only for win32 cross compilation using MXE -if( WIN32 AND MSYS AND CMAKE_CROSSCOMPILING ) -target_link_libraries( pcbnew - opengl32 - glu32 - pixman-1 - fontconfig - freetype - bz2 - ) -endif() if( MAKE_LINK_MAPS ) # generate a link map with cross reference - set_target_properties( pcbnew PROPERTIES LINK_FLAGS "-Wl,-cref -Wl,-Map=pcbnew.map" ) + set_target_properties( pcbnew PROPERTIES + LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=pcbnew.map" ) endif() -### -# Add pcbnew as install target -### -install( TARGETS pcbnew - DESTINATION ${KICAD_BIN} - COMPONENT binary ) - - if( KICAD_SCRIPTING ) add_custom_target( FixSwigImportsScripting ALL COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripting/build_tools/fix_swig_imports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py @@ -603,7 +653,7 @@ if( KICAD_SCRIPTING_MODULES ) install( FILES ${CMAKE_BINARY_DIR}/pcbnew/pcbnew.py DESTINATION ${PYTHON_DEST} ) - if( WIN32 ) + if( MINGW ) install( FILES ${CMAKE_BINARY_DIR}/pcbnew/_pcbnew.pyd DESTINATION ${PYTHON_DEST} ) else() install( FILES ${CMAKE_BINARY_DIR}/pcbnew/_pcbnew.so DESTINATION ${PYTHON_DEST} ) diff --git a/pcbnew/autorouter/graphpcb.cpp b/pcbnew/autorouter/graphpcb.cpp index 294e20e969..28dff7ff32 100644 --- a/pcbnew/autorouter/graphpcb.cpp +++ b/pcbnew/autorouter/graphpcb.cpp @@ -87,7 +87,7 @@ static void TraceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM l void PlacePad( D_PAD* aPad, int color, int marge, int op_logic ) { int dx, dy; - wxPoint shape_pos = aPad->ReturnShapePos(); + wxPoint shape_pos = aPad->ShapePos(); dx = aPad->GetSize().x / 2; dx += marge; @@ -757,7 +757,7 @@ void TraceCircle( int ux0, int uy0, int ux1, int uy1, int lg, LAYER_NUM layer, int ii; int angle; - radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) ); + radius = KiROUND( Distance( ux0, uy0, ux1, uy1 ) ); x0 = x1 = radius; y0 = y1 = 0; diff --git a/pcbnew/autorouter/queue.cpp b/pcbnew/autorouter/queue.cpp index cf82a63633..ca251608a2 100644 --- a/pcbnew/autorouter/queue.cpp +++ b/pcbnew/autorouter/queue.cpp @@ -119,7 +119,7 @@ void GetQueue( int* r, int* c, int* s, int* d, int* a ) /* add a search node to the list - * Return: + * : * 1 - OK * 0 - Failed to allocate memory. */ diff --git a/pcbnew/autorouter/solve.cpp b/pcbnew/autorouter/solve.cpp index c06d8545eb..d3a5476339 100644 --- a/pcbnew/autorouter/solve.cpp +++ b/pcbnew/autorouter/solve.cpp @@ -262,7 +262,7 @@ static long newmask[8] = /* Route all traces - * Return: + * : * 1 if OK * -1 if escape (stop being routed) request * -2 if default memory allocation diff --git a/pcbnew/autorouter/work.cpp b/pcbnew/autorouter/work.cpp index 11d0f1841b..68aa48c1ef 100644 --- a/pcbnew/autorouter/work.cpp +++ b/pcbnew/autorouter/work.cpp @@ -73,7 +73,7 @@ void InitWork() /* add a unit of work to the work list - * Return: + * : * 1 if OK * 0 if memory allocation failed */ diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index 858aa40c0e..f5d2b6ccd7 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -29,10 +29,12 @@ */ #include +#include #include #include #include -#include +//#include +#include #include #include #include @@ -40,6 +42,7 @@ #include #include +#include #include #include #include @@ -126,11 +129,10 @@ BEGIN_EVENT_TABLE( PCB_BASE_FRAME, EDA_DRAW_FRAME ) END_EVENT_TABLE() -PCB_BASE_FRAME::PCB_BASE_FRAME( wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, - const wxString& aTitle, - const wxPoint& aPos, const wxSize& aSize, - long aStyle, const wxString & aFrameName) : - EDA_DRAW_FRAME( aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ) +PCB_BASE_FRAME::PCB_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, ID_DRAWFRAME_TYPE aFrameType, + const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize, + long aStyle, const wxString & aFrameName ) : + EDA_DRAW_FRAME( aKiway, aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName ) { m_Pcb = NULL; m_toolManager = NULL; @@ -172,6 +174,21 @@ PCB_BASE_FRAME::~PCB_BASE_FRAME() } +FP_LIB_TABLE* PCB_BASE_FRAME::FootprintLibs() const +{ + PROJECT& prj = Prj(); + FP_LIB_TABLE* tbl = dynamic_cast( prj.Elem( PROJECT::FPTBL ) ); + + if( !tbl ) + { + tbl = new FP_LIB_TABLE( &GFootprintTable ); + prj.Elem( PROJECT::FPTBL, tbl ); + } + + return tbl; +} + + void PCB_BASE_FRAME::SetBoard( BOARD* aBoard ) { delete m_Pcb; @@ -728,39 +745,35 @@ void PCB_BASE_FRAME::unitsChangeRefresh() } -void PCB_BASE_FRAME::LoadSettings() +void PCB_BASE_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); - - wxConfig* cfg = wxGetApp().GetSettings(); - - EDA_DRAW_FRAME::LoadSettings(); + EDA_DRAW_FRAME::LoadSettings( aCfg ); // Ensure grid id is an existent grid id: if( (m_LastGridSizeId <= 0) || (m_LastGridSizeId > (ID_POPUP_GRID_USER - ID_POPUP_GRID_LEVEL_1000)) ) m_LastGridSizeId = ID_POPUP_GRID_LEVEL_500 - ID_POPUP_GRID_LEVEL_1000; - cfg->Read( m_FrameName + UserGridSizeXEntry, &m_UserGridSize.x, 0.01 ); - cfg->Read( m_FrameName + UserGridSizeYEntry, &m_UserGridSize.y, 0.01 ); + aCfg->Read( m_FrameName + UserGridSizeXEntry, &m_UserGridSize.x, 0.01 ); + aCfg->Read( m_FrameName + UserGridSizeYEntry, &m_UserGridSize.y, 0.01 ); long itmp; - cfg->Read( m_FrameName + UserGridUnitsEntry, &itmp, ( long )INCHES ); + aCfg->Read( m_FrameName + UserGridUnitsEntry, &itmp, ( long )INCHES ); m_UserGridUnit = (EDA_UNITS_T) itmp; - cfg->Read( m_FrameName + DisplayPadFillEntry, &m_DisplayPadFill, true ); - cfg->Read( m_FrameName + DisplayViaFillEntry, &m_DisplayViaFill, true ); - cfg->Read( m_FrameName + DisplayPadNumberEntry, &m_DisplayPadNum, true ); - cfg->Read( m_FrameName + DisplayModuleEdgeEntry, &m_DisplayModEdge, ( long )FILLED ); + aCfg->Read( m_FrameName + DisplayPadFillEntry, &m_DisplayPadFill, true ); + aCfg->Read( m_FrameName + DisplayViaFillEntry, &m_DisplayViaFill, true ); + aCfg->Read( m_FrameName + DisplayPadNumberEntry, &m_DisplayPadNum, true ); + aCfg->Read( m_FrameName + DisplayModuleEdgeEntry, &m_DisplayModEdge, ( long )FILLED ); - cfg->Read( m_FrameName + FastGrid1Entry, &itmp, ( long )0); + aCfg->Read( m_FrameName + FastGrid1Entry, &itmp, ( long )0); m_FastGrid1 = itmp; - cfg->Read( m_FrameName + FastGrid2Entry, &itmp, ( long )0); + aCfg->Read( m_FrameName + FastGrid2Entry, &itmp, ( long )0); m_FastGrid2 = itmp; if( m_DisplayModEdge < LINE || m_DisplayModEdge > SKETCH ) m_DisplayModEdge = FILLED; - cfg->Read( m_FrameName + DisplayModuleTextEntry, &m_DisplayModText, ( long )FILLED ); + aCfg->Read( m_FrameName + DisplayModuleTextEntry, &m_DisplayModText, ( long )FILLED ); if( m_DisplayModText < LINE || m_DisplayModText > SKETCH ) m_DisplayModText = FILLED; @@ -828,23 +841,20 @@ void PCB_BASE_FRAME::LoadSettings() } -void PCB_BASE_FRAME::SaveSettings() +void PCB_BASE_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxASSERT( wxGetApp().GetSettings() != NULL ); + EDA_DRAW_FRAME::SaveSettings( aCfg ); - wxConfig* cfg = wxGetApp().GetSettings(); - - EDA_DRAW_FRAME::SaveSettings(); - cfg->Write( m_FrameName + UserGridSizeXEntry, m_UserGridSize.x ); - cfg->Write( m_FrameName + UserGridSizeYEntry, m_UserGridSize.y ); - cfg->Write( m_FrameName + UserGridUnitsEntry, ( long )m_UserGridUnit ); - cfg->Write( m_FrameName + DisplayPadFillEntry, m_DisplayPadFill ); - cfg->Write( m_FrameName + DisplayViaFillEntry, m_DisplayViaFill ); - cfg->Write( m_FrameName + DisplayPadNumberEntry, m_DisplayPadNum ); - cfg->Write( m_FrameName + DisplayModuleEdgeEntry, ( long )m_DisplayModEdge ); - cfg->Write( m_FrameName + DisplayModuleTextEntry, ( long )m_DisplayModText ); - cfg->Write( m_FrameName + FastGrid1Entry, ( long )m_FastGrid1 ); - cfg->Write( m_FrameName + FastGrid2Entry, ( long )m_FastGrid2 ); + aCfg->Write( m_FrameName + UserGridSizeXEntry, m_UserGridSize.x ); + aCfg->Write( m_FrameName + UserGridSizeYEntry, m_UserGridSize.y ); + aCfg->Write( m_FrameName + UserGridUnitsEntry, ( long )m_UserGridUnit ); + aCfg->Write( m_FrameName + DisplayPadFillEntry, m_DisplayPadFill ); + aCfg->Write( m_FrameName + DisplayViaFillEntry, m_DisplayViaFill ); + aCfg->Write( m_FrameName + DisplayPadNumberEntry, m_DisplayPadNum ); + aCfg->Write( m_FrameName + DisplayModuleEdgeEntry, ( long )m_DisplayModEdge ); + aCfg->Write( m_FrameName + DisplayModuleTextEntry, ( long )m_DisplayModText ); + aCfg->Write( m_FrameName + FastGrid1Entry, ( long )m_FastGrid1 ); + aCfg->Write( m_FrameName + FastGrid2Entry, ( long )m_FastGrid2 ); } diff --git a/pcbnew/block.cpp b/pcbnew/block.cpp index bb86e61cfa..2cb8648da8 100644 --- a/pcbnew/block.cpp +++ b/pcbnew/block.cpp @@ -179,7 +179,7 @@ void DIALOG_BLOCK_OPTIONS::ExecuteCommand( wxCommandEvent& event ) } -int PCB_EDIT_FRAME::ReturnBlockCommand( int aKey ) +int PCB_EDIT_FRAME::BlockCommand( int aKey ) { int cmd = 0; diff --git a/pcbnew/block_module_editor.cpp b/pcbnew/block_module_editor.cpp index d83c1378e7..9fc22bd1e1 100644 --- a/pcbnew/block_module_editor.cpp +++ b/pcbnew/block_module_editor.cpp @@ -30,7 +30,7 @@ */ #include -#include +#include #include #include #include @@ -73,7 +73,7 @@ static void MoveMarkedItems( MODULE* module, wxPoint offset ); static void DeleteMarkedItems( MODULE* module ); -int FOOTPRINT_EDIT_FRAME::ReturnBlockCommand( int key ) +int FOOTPRINT_EDIT_FRAME::BlockCommand( int key ) { int cmd; @@ -306,7 +306,7 @@ static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wx bool aErase ) { BASE_SCREEN* screen = aPanel->GetScreen(); - FOOTPRINT_EDIT_FRAME* moduleEditFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); + FOOTPRINT_EDIT_FRAME* moduleEditFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( aPanel->GetParent() ); wxASSERT( moduleEditFrame ); MODULE* currentModule = moduleEditFrame->GetBoard()->m_Modules; diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index 68059370d1..301cfc9345 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -418,7 +418,7 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer int dy = (m_Size.y / 2) + aClearanceValue; double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree - wxPoint PadShapePos = ReturnShapePos(); /* Note: for pad having a shape offset, + wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset, * the pad position is NOT the shape position */ wxSize psize = m_Size; /* pad size unsed in RECT and TRAPEZOIDAL pads * trapezoidal pads are considered as rect @@ -547,7 +547,7 @@ void D_PAD::BuildPadShapePolygon( CPOLYGONS_LIST& aCornerBuffer, double aCorrectionFactor ) const { wxPoint corners[4]; - wxPoint PadShapePos = ReturnShapePos(); /* Note: for pad having a shape offset, + wxPoint PadShapePos = ShapePos(); /* Note: for pad having a shape offset, * the pad position is NOT the shape position */ switch( GetShape() ) { @@ -662,8 +662,8 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer, double aThermalRot ) { wxPoint corner, corner_end; - wxPoint PadShapePos = aPad.ReturnShapePos(); /* Note: for pad having a shape offset, - * the pad position is NOT the shape position */ + wxPoint PadShapePos = aPad.ShapePos(); // Note: for pad having a shape offset, + // the pad position is NOT the shape position wxSize copper_thickness; int dx = aPad.GetSize().x / 2; diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index e6f1619d18..0c3ca0ecca 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -1502,7 +1502,7 @@ static bool s_SortByNodes( const NETINFO_ITEM* a, const NETINFO_ITEM* b ) } -int BOARD::ReturnSortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount ) +int BOARD::SortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount ) { if( m_NetInfo.GetNetCount() == 0 ) return 0; diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index cd20413baa..9796ab8c42 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -969,13 +969,13 @@ public: REPORTER* aReporter = NULL ); /** - * Function ReturnSortedNetnamesList + * Function SortedNetnamesList * @param aNames An array string to fill with net names. * @param aSortbyPadsCount true = sort by active pads count, false = no sort (i.e. * leave the sort by net names) * @return int - net names count. */ - int ReturnSortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount ); + int SortedNetnamesList( wxArrayString& aNames, bool aSortbyPadsCount ); /**************************************/ /** diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 11f14217fe..41e871d5bf 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -573,7 +573,7 @@ D_PAD* MODULE::FindPadByName( const wxString& aPadName ) const for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) { - pad->ReturnStringPadName( buf ); + pad->StringPadName( buf ); #if 1 if( buf.CmpNoCase( aPadName ) == 0 ) // why case insensitive? #else @@ -588,7 +588,7 @@ D_PAD* MODULE::FindPadByName( const wxString& aPadName ) const D_PAD* MODULE::GetPad( const wxPoint& aPosition, LAYER_MSK aLayerMask ) { - for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) + for( D_PAD* pad = m_Pads; pad; pad = pad->Next() ) { // ... and on the correct layer. if( ( pad->GetLayerMask() & aLayerMask ) == 0 ) @@ -735,7 +735,7 @@ EDA_ITEM* MODULE::Clone() const */ bool MODULE::IsLibNameValid( const wxString & aName ) { - const wxChar * invalids = ReturnStringLibNameInvalidChars( false ); + const wxChar * invalids = StringLibNameInvalidChars( false ); if( aName.find_first_of( invalids ) != std::string::npos ) return false; @@ -751,7 +751,7 @@ bool MODULE::IsLibNameValid( const wxString & aName ) * return a constant string giving the list of invalid chars in lib name * static function */ -const wxChar* MODULE::ReturnStringLibNameInvalidChars( bool aUserReadable ) +const wxChar* MODULE::StringLibNameInvalidChars( bool aUserReadable ) { static const wxChar invalidChars[] = wxT("%$\t \"\\/"); static const wxChar invalidCharsReadable[] = wxT("% $ 'tab' 'space' \\ \" /"); diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 184e9e7288..ebacb7753f 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -470,14 +470,14 @@ public: static bool IsLibNameValid( const wxString & aName ); /** - * static function ReturnStringLibNameInvalidChars + * static function StringLibNameInvalidChars * Test for validity of the name in a library of the footprint * ( no spaces, dir separators ... ) * @param aUserReadable = false to get the list of invalid chars * true to get a readable form (i.e ' ' = 'space' '\\t'= 'tab') * @return a constant std::string giving the list of invalid chars in lib name */ - static const wxChar* ReturnStringLibNameInvalidChars( bool aUserReadable ); + static const wxChar* StringLibNameInvalidChars( bool aUserReadable ); /** * Function SetInitialComments diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index 5a48ac461a..2be9c2466b 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -269,7 +269,7 @@ void D_PAD::AppendConfigs( PARAM_CFG_ARRAY* aResult ) // Returns the position of the pad. -const wxPoint D_PAD::ReturnShapePos() const +const wxPoint D_PAD::ShapePos() const { if( m_Offset.x == 0 && m_Offset.y == 0 ) return m_Pos; @@ -308,13 +308,13 @@ const wxString D_PAD::GetPadName() const wxString name; - ReturnStringPadName( name ); + StringPadName( name ); return name; #endif } -void D_PAD::ReturnStringPadName( wxString& text ) const +void D_PAD::StringPadName( wxString& text ) const { #if 0 // m_Padname is not ASCII and not UTF8, it is LATIN1 basically, whatever // 8 bit font is supported in KiCad plotting and drawing. @@ -573,7 +573,7 @@ void D_PAD::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM>& aList ) { wxString msg = module->GetReference(); aList.push_back( MSG_PANEL_ITEM( _( "Module" ), msg, DARKCYAN ) ); - ReturnStringPadName( Line ); + StringPadName( Line ); aList.push_back( MSG_PANEL_ITEM( _( "Pad" ), Line, BROWN ) ); } @@ -650,7 +650,7 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) { int dx, dy; - wxPoint shape_pos = ReturnShapePos(); + wxPoint shape_pos = ShapePos(); wxPoint delta = aPosition - shape_pos; diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 0391d92b4b..30386fad04 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -35,7 +35,7 @@ #include #include #include -#include // PARAM_CFG_ARRAY +#include // PARAM_CFG_ARRAY #include "zones.h" @@ -353,7 +353,7 @@ public: int BuildSegmentFromOvalShape( wxPoint& aSegStart, wxPoint& aSegEnd, double aRotation, const wxSize& aMargin ) const; - void ReturnStringPadName( wxString& text ) const; // Return pad name as string in a buffer + void StringPadName( wxString& text ) const; // Return pad name as string in a buffer /** * Function GetBoundingRadius @@ -372,7 +372,7 @@ public: return m_boundingRadius; } - const wxPoint ReturnShapePos() const; + const wxPoint ShapePos() const; /** * Function GetSubRatsnest @@ -511,7 +511,7 @@ private: * In all cases the pad position is the pad hole. * The physical shape position (used to draw it for instance) is pad * position (m_Pos) + m_Offset. - * D_PAD::ReturnShapePos() returns the physical shape position according to + * D_PAD::ShapePos() returns the physical shape position according to * the offset and the pad rotation. */ wxPoint m_Offset; diff --git a/pcbnew/class_pad_draw_functions.cpp b/pcbnew/class_pad_draw_functions.cpp index 56f60c2eee..89ce94feec 100644 --- a/pcbnew/class_pad_draw_functions.cpp +++ b/pcbnew/class_pad_draw_functions.cpp @@ -317,7 +317,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) GRSetDrawMode( aDC, aDrawInfo.m_DrawMode ); // calculate pad shape position : - wxPoint shape_pos = ReturnShapePos() - aDrawInfo.m_Offset; + wxPoint shape_pos = ShapePos() - aDrawInfo.m_Offset; wxSize halfsize = m_Size; halfsize.x >>= 1; @@ -544,7 +544,7 @@ void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo ) if( aDrawInfo.m_Display_padnum ) { - ReturnStringPadName( buffer ); + StringPadName( buffer ); int numpad_len = buffer.Len(); numpad_len = std::max( numpad_len, MIN_CHAR_COUNT ); diff --git a/pcbnew/class_pcb_layer_widget.cpp b/pcbnew/class_pcb_layer_widget.cpp index 6dc983babf..82ab8237f7 100644 --- a/pcbnew/class_pcb_layer_widget.cpp +++ b/pcbnew/class_pcb_layer_widget.cpp @@ -29,7 +29,7 @@ /******************************************************/ #include -#include +#include #include #include #include diff --git a/pcbnew/class_track.cpp b/pcbnew/class_track.cpp index 21cca65517..4f6c65f1be 100644 --- a/pcbnew/class_track.cpp +++ b/pcbnew/class_track.cpp @@ -224,7 +224,7 @@ wxString SEGVIA::GetSelectMenuText() const // say which layers, only two for now LAYER_NUM topLayer; LAYER_NUM botLayer; - ReturnLayerPair( &topLayer, &botLayer ); + LayerPair( &topLayer, &botLayer ); text.Printf( format.GetData(), GetChars( ShowWidth() ), GetChars( netname ), GetNet(), GetChars( board->GetLayerName( topLayer ) ), @@ -404,7 +404,7 @@ bool SEGVIA::IsOnLayer( LAYER_NUM layer_number ) const { LAYER_NUM bottom_layer, top_layer; - ReturnLayerPair( &top_layer, &bottom_layer ); + LayerPair( &top_layer, &bottom_layer ); if( bottom_layer <= layer_number && layer_number <= top_layer ) return true; @@ -426,8 +426,8 @@ LAYER_MSK TRACK::GetLayerMask() const LAYER_NUM bottom_layer, top_layer; - // ReturnLayerPair() knows how layers are stored - ( (SEGVIA*) this )->ReturnLayerPair( &top_layer, &bottom_layer ); + // LayerPair() knows how layers are stored + ( (SEGVIA*) this )->LayerPair( &top_layer, &bottom_layer ); LAYER_MSK layermask = NO_LAYERS; @@ -462,7 +462,7 @@ void SEGVIA::SetLayerPair( LAYER_NUM top_layer, LAYER_NUM bottom_layer ) } -void SEGVIA::ReturnLayerPair( LAYER_NUM* top_layer, LAYER_NUM* bottom_layer ) const +void SEGVIA::LayerPair( LAYER_NUM* top_layer, LAYER_NUM* bottom_layer ) const { LAYER_NUM b_layer = LAYER_N_BACK; LAYER_NUM t_layer = LAYER_N_FRONT; @@ -931,7 +931,7 @@ void SEGVIA::Draw( EDA_DRAW_PANEL* panel, wxDC* aDC, GR_DRAWMODE aDrawMode, int ax = 0, ay = radius, bx = 0, by = drill_radius; LAYER_NUM layer_top, layer_bottom; - ( (SEGVIA*) this )->ReturnLayerPair( &layer_top, &layer_bottom ); + ( (SEGVIA*) this )->LayerPair( &layer_top, &layer_bottom ); // lines for the top layer RotatePoint( &ax, &ay, layer_top * 3600.0 / brd->GetCopperLayerCount( ) ); @@ -1153,7 +1153,7 @@ void TRACK::GetMsgPanelInfoBase( std::vector< MSG_PANEL_ITEM >& aList ) SEGVIA* Via = (SEGVIA*) this; LAYER_NUM top_layer, bottom_layer; - Via->ReturnLayerPair( &top_layer, &bottom_layer ); + Via->LayerPair( &top_layer, &bottom_layer ); if( board ) msg = board->GetLayerName( top_layer ) + wxT( "/" ) + board->GetLayerName( bottom_layer ); diff --git a/pcbnew/class_track.h b/pcbnew/class_track.h index 594678bf40..56ac970102 100644 --- a/pcbnew/class_track.h +++ b/pcbnew/class_track.h @@ -400,13 +400,13 @@ public: void SetLayerPair( LAYER_NUM top_layer, LAYER_NUM bottom_layer ); /** - * Function ReturnLayerPair + * Function LayerPair * Return the 2 layers used by the via (the via actually uses * all layers between these 2 layers) * @param top_layer = pointer to the first layer (can be null) * @param bottom_layer = pointer to the last layer (can be null) */ - void ReturnLayerPair( LAYER_NUM* top_layer, LAYER_NUM* bottom_layer ) const; + void LayerPair( LAYER_NUM* top_layer, LAYER_NUM* bottom_layer ) const; const wxPoint& GetPosition() const { return m_Start; } // was overload void SetPosition( const wxPoint& aPoint ) { m_Start = aPoint; m_End = aPoint; } // was overload diff --git a/pcbnew/clean.cpp b/pcbnew/clean.cpp index 2fdd6e9975..55a72d1f7b 100644 --- a/pcbnew/clean.cpp +++ b/pcbnew/clean.cpp @@ -327,7 +327,7 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() } else { - ((SEGVIA*)track)->ReturnLayerPair( &top_layer, &bottom_layer ); + ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(), top_layer, bottom_layer, track->GetNet() ); @@ -355,7 +355,7 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() if( other == NULL ) { - via->ReturnLayerPair( &top_layer, &bottom_layer ); + via->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetStart(), bottom_layer, top_layer, @@ -387,7 +387,7 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() } else { - ((SEGVIA*)track)->ReturnLayerPair( &top_layer, &bottom_layer ); + ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(), top_layer, bottom_layer, track->GetNet() ); @@ -416,7 +416,7 @@ bool TRACKS_CLEANER::deleteUnconnectedTracks() if( other == NULL ) { - via->ReturnLayerPair( &top_layer, &bottom_layer ); + via->LayerPair( &top_layer, &bottom_layer ); zone = m_Brd->HitTestForAnyFilledArea( via->GetEnd(), bottom_layer, top_layer, via->GetNet() ); diff --git a/pcbnew/connect.cpp b/pcbnew/connect.cpp index aa8d4867e6..9398eaa8b4 100644 --- a/pcbnew/connect.cpp +++ b/pcbnew/connect.cpp @@ -79,7 +79,7 @@ void CONNECTIONS::SearchConnectionsPadsToIntersectingPads() pad->m_PadsConnected.clear(); candidates.clear(); - CollectItemsNearTo( candidates, pad->ReturnShapePos(), pad->GetBoundingRadius() ); + CollectItemsNearTo( candidates, pad->ShapePos(), pad->GetBoundingRadius() ); // add pads to pad.m_PadsConnected, if they are connected for( unsigned jj = 0; jj < candidates.size(); jj++ ) diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index d1f41b791f..08a56ec81c 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include diff --git a/pcbnew/dialogs/dialog_SVG_print.cpp b/pcbnew/dialogs/dialog_SVG_print.cpp index f8eec0ad5b..c5114a1145 100644 --- a/pcbnew/dialogs/dialog_SVG_print.cpp +++ b/pcbnew/dialogs/dialog_SVG_print.cpp @@ -28,7 +28,8 @@ #include -#include +//#include +#include #include #include #include @@ -66,7 +67,7 @@ DIALOG_SVG_PRINT::DIALOG_SVG_PRINT( EDA_DRAW_FRAME* parent ) : DIALOG_SVG_PRINT_base( parent ) { m_parent = (PCB_BASE_FRAME*) parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); initDialog(); GetSizer()->SetSizeHints( this ); Centre(); @@ -103,7 +104,7 @@ void DIALOG_SVG_PRINT::initDialog() AddUnitSymbol( *m_TextPenWidth, g_UserUnit ); m_DialogDefaultPenSize->SetValue( - ReturnStringFromValue( g_UserUnit, g_DrawDefaultLineThickness ) ); + StringFromValue( g_UserUnit, g_DrawDefaultLineThickness ) ); // Create layers list LAYER_NUM layer; @@ -206,7 +207,7 @@ void DIALOG_SVG_PRINT::OnOutputDirectoryBrowseClicked( wxCommandEvent& event ) void DIALOG_SVG_PRINT::SetPenWidth() { - int pensize = ReturnValueFromTextCtrl( *m_DialogDefaultPenSize ); + int pensize = ValueFromTextCtrl( *m_DialogDefaultPenSize ); if( pensize > WIDTH_MAX_VALUE ) { @@ -219,7 +220,7 @@ void DIALOG_SVG_PRINT::SetPenWidth() } g_DrawDefaultLineThickness = pensize; - m_DialogDefaultPenSize->SetValue( ReturnStringFromValue( g_UserUnit, pensize ) ); + m_DialogDefaultPenSize->SetValue( StringFromValue( g_UserUnit, pensize ) ); } diff --git a/pcbnew/dialogs/dialog_SVG_print.h b/pcbnew/dialogs/dialog_SVG_print.h index 8fc110286c..bf7309c409 100644 --- a/pcbnew/dialogs/dialog_SVG_print.h +++ b/pcbnew/dialogs/dialog_SVG_print.h @@ -16,7 +16,7 @@ class DIALOG_SVG_PRINT : public DIALOG_SVG_PRINT_base private: PCB_BASE_FRAME* m_parent; BOARD* m_board; - wxConfig* m_config; + wxConfigBase* m_config; LAYER_MSK m_printMaskLayer; wxCheckBox* m_boxSelectLayer[32]; bool m_printBW; diff --git a/pcbnew/dialogs/dialog_copper_zones.cpp b/pcbnew/dialogs/dialog_copper_zones.cpp index 0b07db304f..a343c60198 100644 --- a/pcbnew/dialogs/dialog_copper_zones.cpp +++ b/pcbnew/dialogs/dialog_copper_zones.cpp @@ -29,7 +29,8 @@ #include #include -#include +//#include +#include #include #include #include @@ -57,7 +58,7 @@ public: private: PCB_BASE_FRAME* m_Parent; - wxConfig* m_Config; ///< Current config + wxConfigBase* m_Config; ///< Current config ZONE_EDIT_T m_OnExitCode; ///< exit code: ZONE_ABORT if no change, ///< ZONE_OK if new values accepted @@ -139,7 +140,7 @@ DIALOG_COPPER_ZONE::DIALOG_COPPER_ZONE( PCB_BASE_FRAME* aParent, ZONE_SETTINGS* DIALOG_COPPER_ZONE_BASE( aParent ) { m_Parent = aParent; - m_Config = wxGetApp().GetSettings(); + m_Config = Kiface().KifaceSettings(); m_ptr = aSettings; m_settings = *aSettings; @@ -173,11 +174,11 @@ void DIALOG_COPPER_ZONE::initDialog() m_FillModeCtrl->SetSelection( m_settings.m_FillMode ? 1 : 0 ); AddUnitSymbol( *m_ClearanceValueTitle, g_UserUnit ); - msg = ReturnStringFromValue( g_UserUnit, m_settings.m_ZoneClearance ); + msg = StringFromValue( g_UserUnit, m_settings.m_ZoneClearance ); m_ZoneClearanceCtrl->SetValue( msg ); AddUnitSymbol( *m_MinThicknessValueTitle, g_UserUnit ); - msg = ReturnStringFromValue( g_UserUnit, m_settings.m_ZoneMinThickness ); + msg = StringFromValue( g_UserUnit, m_settings.m_ZoneMinThickness ); m_ZoneMinThicknessCtrl->SetValue( msg ); switch( m_settings.GetPadConnection() ) @@ -388,7 +389,7 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aPromptForErrors, bool aUseExportab m_settings.m_FillMode = (m_FillModeCtrl->GetSelection() == 0) ? 0 : 1; wxString txtvalue = m_ZoneClearanceCtrl->GetValue(); - m_settings.m_ZoneClearance = ReturnValueFromString( g_UserUnit, txtvalue ); + m_settings.m_ZoneClearance = ValueFromString( g_UserUnit, txtvalue ); // Test if this is a reasonable value for this parameter // A too large value can hang Pcbnew @@ -403,7 +404,7 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aPromptForErrors, bool aUseExportab } txtvalue = m_ZoneMinThicknessCtrl->GetValue(); - m_settings.m_ZoneMinThickness = ReturnValueFromString( g_UserUnit, txtvalue ); + m_settings.m_ZoneMinThickness = ValueFromString( g_UserUnit, txtvalue ); if( m_settings.m_ZoneMinThickness < (ZONE_THICKNESS_MIN_VALUE_MIL*IU_PER_MILS) ) { @@ -416,7 +417,7 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aPromptForErrors, bool aUseExportab m_settings.SetCornerSmoothingType( m_cornerSmoothingChoice->GetSelection() ); txtvalue = m_cornerSmoothingCtrl->GetValue(); - m_settings.SetCornerRadius( ReturnValueFromString( g_UserUnit, txtvalue ) ); + m_settings.SetCornerRadius( ValueFromString( g_UserUnit, txtvalue ) ); m_settings.m_ZonePriority = m_PriorityLevelCtrl->GetValue(); @@ -425,8 +426,8 @@ bool DIALOG_COPPER_ZONE::AcceptOptions( bool aPromptForErrors, bool aUseExportab else m_settings.m_Zone_45_Only = true; - m_settings.m_ThermalReliefGap = ReturnValueFromTextCtrl( *m_AntipadSizeValue ); - m_settings.m_ThermalReliefCopperBridge = ReturnValueFromTextCtrl( *m_CopperWidthValue ); + m_settings.m_ThermalReliefGap = ValueFromTextCtrl( *m_AntipadSizeValue ); + m_settings.m_ThermalReliefCopperBridge = ValueFromTextCtrl( *m_CopperWidthValue ); if( m_Config ) { @@ -624,7 +625,7 @@ void DIALOG_COPPER_ZONE::buildAvailableListOfNets() { wxArrayString listNetName; - m_Parent->GetBoard()->ReturnSortedNetnamesList( listNetName, m_NetSortingByPadCount ); + m_Parent->GetBoard()->SortedNetnamesList( listNetName, m_NetSortingByPadCount ); if( m_NetFiltering ) { diff --git a/pcbnew/dialogs/dialog_design_rules.cpp b/pcbnew/dialogs/dialog_design_rules.cpp index e5325943fe..f83be84b9e 100644 --- a/pcbnew/dialogs/dialog_design_rules.cpp +++ b/pcbnew/dialogs/dialog_design_rules.cpp @@ -190,15 +190,15 @@ void DIALOG_DESIGN_RULES::PrintCurrentSettings() m_MessagesList->AppendToPage( _( "Current general settings:
" ) ); // Display min values: - value = ReturnStringFromValue( g_UserUnit, m_BrdSettings.m_TrackMinWidth, true ); + value = StringFromValue( g_UserUnit, m_BrdSettings.m_TrackMinWidth, true ); msg.Printf( _( "Minimum value for tracks width: %s
\n" ), GetChars( value ) ); m_MessagesList->AppendToPage( msg ); - value = ReturnStringFromValue( g_UserUnit, m_BrdSettings.m_ViasMinSize, true ); + value = StringFromValue( g_UserUnit, m_BrdSettings.m_ViasMinSize, true ); msg.Printf( _( "Minimum value for vias diameter: %s
\n" ), GetChars( value ) ); m_MessagesList->AppendToPage( msg ); - value = ReturnStringFromValue( g_UserUnit, m_BrdSettings.m_MicroViasMinSize, true ); + value = StringFromValue( g_UserUnit, m_BrdSettings.m_MicroViasMinSize, true ); msg.Printf( _( "Minimum value for microvias diameter: %s
\n" ), GetChars( value ) ); m_MessagesList->AppendToPage( msg ); } @@ -312,17 +312,17 @@ void DIALOG_DESIGN_RULES::InitDimensionsLists() for( unsigned ii = 0; ii < m_TracksWidthList.size(); ii++ ) { - msg = ReturnStringFromValue( g_UserUnit, m_TracksWidthList[ii], false ); + msg = StringFromValue( g_UserUnit, m_TracksWidthList[ii], false ); m_gridTrackWidthList->SetCellValue( ii, 0, msg ); } for( unsigned ii = 0; ii < m_ViasDimensionsList.size(); ii++ ) { - msg = ReturnStringFromValue( g_UserUnit, m_ViasDimensionsList[ii].m_Diameter, false ); + msg = StringFromValue( g_UserUnit, m_ViasDimensionsList[ii].m_Diameter, false ); m_gridViaSizeList->SetCellValue( ii, 0, msg ); if( m_ViasDimensionsList[ii].m_Drill > 0 ) { - msg = ReturnStringFromValue( g_UserUnit, m_ViasDimensionsList[ii].m_Drill, false ); + msg = StringFromValue( g_UserUnit, m_ViasDimensionsList[ii].m_Drill, false ); m_gridViaSizeList->SetCellValue( ii, 1, msg ); } } @@ -458,22 +458,22 @@ static void class2gridRow( wxGrid* grid, int row, NETCLASS* nc ) // label is netclass name grid->SetRowLabelValue( row, nc->GetName() ); - msg = ReturnStringFromValue( g_UserUnit, nc->GetClearance() ); + msg = StringFromValue( g_UserUnit, nc->GetClearance() ); grid->SetCellValue( row, GRID_CLEARANCE, msg ); - msg = ReturnStringFromValue( g_UserUnit, nc->GetTrackWidth() ); + msg = StringFromValue( g_UserUnit, nc->GetTrackWidth() ); grid->SetCellValue( row, GRID_TRACKSIZE, msg ); - msg = ReturnStringFromValue( g_UserUnit, nc->GetViaDiameter() ); + msg = StringFromValue( g_UserUnit, nc->GetViaDiameter() ); grid->SetCellValue( row, GRID_VIASIZE, msg ); - msg = ReturnStringFromValue( g_UserUnit, nc->GetViaDrill() ); + msg = StringFromValue( g_UserUnit, nc->GetViaDrill() ); grid->SetCellValue( row, GRID_VIADRILL, msg ); - msg = ReturnStringFromValue( g_UserUnit, nc->GetuViaDiameter() ); + msg = StringFromValue( g_UserUnit, nc->GetuViaDiameter() ); grid->SetCellValue( row, GRID_uVIASIZE, msg ); - msg = ReturnStringFromValue( g_UserUnit, nc->GetuViaDrill() ); + msg = StringFromValue( g_UserUnit, nc->GetuViaDrill() ); grid->SetCellValue( row, GRID_uVIADRILL, msg ); } @@ -509,7 +509,7 @@ void DIALOG_DESIGN_RULES::InitRulesList() static void gridRow2class( wxGrid* grid, int row, NETCLASS* nc ) { #define MYCELL( col ) \ - ReturnValueFromString( g_UserUnit, grid->GetCellValue( row, col ) ) + ValueFromString( g_UserUnit, grid->GetCellValue( row, col ) ) nc->SetClearance( MYCELL( GRID_CLEARANCE ) ); nc->SetTrackWidth( MYCELL( GRID_TRACKSIZE ) ); @@ -571,17 +571,17 @@ void DIALOG_DESIGN_RULES::CopyGlobalRulesToBoard() m_BrdSettings.m_BlindBuriedViaAllowed = m_OptViaType->GetSelection() > 0; // Update vias minimum values for DRC - m_BrdSettings.m_ViasMinSize = ReturnValueFromTextCtrl( *m_SetViasMinSizeCtrl ); - m_BrdSettings.m_ViasMinDrill = ReturnValueFromTextCtrl( *m_SetViasMinDrillCtrl ); + m_BrdSettings.m_ViasMinSize = ValueFromTextCtrl( *m_SetViasMinSizeCtrl ); + m_BrdSettings.m_ViasMinDrill = ValueFromTextCtrl( *m_SetViasMinDrillCtrl ); m_BrdSettings.m_MicroViasAllowed = m_AllowMicroViaCtrl->GetSelection() == 1; // Update microvias minimum values for DRC - m_BrdSettings.m_MicroViasMinSize = ReturnValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl ); - m_BrdSettings.m_MicroViasMinDrill = ReturnValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl ); + m_BrdSettings.m_MicroViasMinSize = ValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl ); + m_BrdSettings.m_MicroViasMinDrill = ValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl ); // Update tracks minimum values for DRC - m_BrdSettings.m_TrackMinWidth = ReturnValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); + m_BrdSettings.m_TrackMinWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); } @@ -600,7 +600,7 @@ void DIALOG_DESIGN_RULES::CopyDimensionsListsToBoard() if( msg.IsEmpty() ) continue; - int value = ReturnValueFromString( g_UserUnit, msg ); + int value = ValueFromString( g_UserUnit, msg ); m_TracksWidthList.push_back( value ); } @@ -617,14 +617,14 @@ void DIALOG_DESIGN_RULES::CopyDimensionsListsToBoard() if( msg.IsEmpty() ) continue; - int value = ReturnValueFromString( g_UserUnit, msg ); + int value = ValueFromString( g_UserUnit, msg ); VIA_DIMENSION via_dim; via_dim.m_Diameter = value; msg = m_gridViaSizeList->GetCellValue( row, 1 ); if( !msg.IsEmpty() ) { - value = ReturnValueFromString( g_UserUnit, msg ); + value = ValueFromString( g_UserUnit, msg ); via_dim.m_Drill = value; } @@ -949,18 +949,18 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() wxString msg; - int minViaDia = ReturnValueFromTextCtrl( *m_SetViasMinSizeCtrl ); - int minViaDrill = ReturnValueFromTextCtrl( *m_SetViasMinDrillCtrl ); - int minUViaDia = ReturnValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl ); - int minUViaDrill = ReturnValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl ); - int minTrackWidth = ReturnValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); + int minViaDia = ValueFromTextCtrl( *m_SetViasMinSizeCtrl ); + int minViaDrill = ValueFromTextCtrl( *m_SetViasMinDrillCtrl ); + int minUViaDia = ValueFromTextCtrl( *m_SetMicroViasMinSizeCtrl ); + int minUViaDrill = ValueFromTextCtrl( *m_SetMicroViasMinDrillCtrl ); + int minTrackWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); int maxval = 1000 * IU_PER_MILS; // a max value for tracks and vias sizes (1 inch) for( int row = 0; row < m_grid->GetNumberRows(); row++ ) { - int tracksize = ReturnValueFromString( g_UserUnit, + int tracksize = ValueFromString( g_UserUnit, m_grid->GetCellValue( row, GRID_TRACKSIZE ) ); if( tracksize < minTrackWidth ) { @@ -972,7 +972,7 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() } // Test vias - int viadia = ReturnValueFromString( g_UserUnit, + int viadia = ValueFromString( g_UserUnit, m_grid->GetCellValue( row, GRID_VIASIZE ) ); if( viadia < minViaDia ) @@ -984,7 +984,7 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() m_MessagesList->AppendToPage( msg ); } - int viadrill = ReturnValueFromString( g_UserUnit, + int viadrill = ValueFromString( g_UserUnit, m_grid->GetCellValue( row, GRID_VIADRILL ) ); if( viadrill >= viadia ) { @@ -1005,7 +1005,7 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() } // Test Micro vias - int muviadia = ReturnValueFromString( g_UserUnit, + int muviadia = ValueFromString( g_UserUnit, m_grid->GetCellValue( row, GRID_uVIASIZE ) ); if( muviadia < minUViaDia ) @@ -1017,7 +1017,7 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() m_MessagesList->AppendToPage( msg ); } - int muviadrill = ReturnValueFromString( g_UserUnit, + int muviadrill = ValueFromString( g_UserUnit, m_grid->GetCellValue( row, GRID_uVIADRILL ) ); if( muviadrill >= muviadia ) { @@ -1046,7 +1046,7 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() if( tvalue.IsEmpty() ) continue; - int tracksize = ReturnValueFromString( g_UserUnit, tvalue ); + int tracksize = ValueFromString( g_UserUnit, tvalue ); if( tracksize < minTrackWidth ) { @@ -1073,12 +1073,12 @@ bool DIALOG_DESIGN_RULES::TestDataValidity() if( tvalue.IsEmpty() ) continue; - int viadia = ReturnValueFromString( g_UserUnit, tvalue ); + int viadia = ValueFromString( g_UserUnit, tvalue ); int viadrill = 0; wxString drlvalue = m_gridViaSizeList->GetCellValue( row, 1 ); if( !drlvalue.IsEmpty() ) - viadrill = ReturnValueFromString( g_UserUnit, drlvalue ); + viadrill = ValueFromString( g_UserUnit, drlvalue ); if( viadia < minViaDia ) { diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index d65d497784..4eafff3832 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -99,9 +99,9 @@ void DIALOG_DRC_CONTROL::InitValues() */ void DIALOG_DRC_CONTROL::SetDrcParmeters( ) { - m_BrdSettings.m_TrackMinWidth = ReturnValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); - m_BrdSettings.m_ViasMinSize = ReturnValueFromTextCtrl( *m_SetViaMinSizeCtrl ); - m_BrdSettings.m_MicroViasMinSize = ReturnValueFromTextCtrl( *m_SetMicroViakMinSizeCtrl ); + m_BrdSettings.m_TrackMinWidth = ValueFromTextCtrl( *m_SetTrackMinWidthCtrl ); + m_BrdSettings.m_ViasMinSize = ValueFromTextCtrl( *m_SetViaMinSizeCtrl ); + m_BrdSettings.m_MicroViasMinSize = ValueFromTextCtrl( *m_SetMicroViakMinSizeCtrl ); m_Parent->GetBoard()->SetDesignSettings( m_BrdSettings ); } diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp index 1a66d7e21b..db1817b1f5 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp @@ -29,11 +29,12 @@ #include +#include #include #include #include #include -#include +#include #include #include <3d_struct.h> #include <3d_viewer.h> @@ -420,17 +421,30 @@ void DIALOG_MODULE_BOARD_EDITOR::Remove3DShape( wxCommandEvent& event ) void DIALOG_MODULE_BOARD_EDITOR::Browse3DLib( wxCommandEvent& event ) { - wxString fullfilename, shortfilename; - wxString fullpath; + PROJECT& prj = Prj(); + SEARCH_STACK& search = Kiface().KifaceSearch(); + + wxString fullpath; + wxString kisys3dmod = wxGetenv( wxT( KISYS3DMOD ) ); + + if( !kisys3dmod || !wxFileName::IsDirReadable( kisys3dmod ) ) + { + fullpath = search.FindValidPath( LIB3D_PATH ); + } + + if( !fullpath ) + fullpath = prj.RPath(PROJECT::VIEWER_3D).LastVisitedPath( search, LIB3D_PATH ); - fullpath = wxGetApp().ReturnLastVisitedLibraryPath( LIB3D_PATH ); #ifdef __WINDOWS__ fullpath.Replace( wxT( "/" ), wxT( "\\" ) ); #endif - wxString fileFilters; - fileFilters = wxGetTranslation( Shapes3DFileWildcard ); - fileFilters += wxChar( '|' ); + wxString fullfilename; + wxString shortfilename; + + wxString fileFilters = wxGetTranslation( Shapes3DFileWildcard ); + + fileFilters += wxChar( '|' ); fileFilters += wxGetTranslation( IDF3DFileWildcard ); fullfilename = EDA_FileSelector( _( "3D Shape:" ), @@ -447,7 +461,8 @@ void DIALOG_MODULE_BOARD_EDITOR::Browse3DLib( wxCommandEvent& event ) return; wxFileName fn = fullfilename; - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + + prj.RPath(PROJECT::VIEWER_3D).SaveLastVisitedPath( fn.GetPath() ); /* If the file path is already in the library search paths * list, just add the library name to the list. Otherwise, add @@ -456,8 +471,7 @@ void DIALOG_MODULE_BOARD_EDITOR::Browse3DLib( wxCommandEvent& event ) * because it preserve use of default libraries paths, when the path is a * sub path of these default paths */ - shortfilename = - wxGetApp().ReturnFilenameWithRelativePathInLibPath( fullfilename ); + shortfilename = search.FilenameWithRelativePathInSearchList( fullfilename ); wxFileName aux = shortfilename; if( aux.IsAbsolute() ) @@ -475,10 +489,12 @@ void DIALOG_MODULE_BOARD_EDITOR::Browse3DLib( wxCommandEvent& event ) } S3D_MASTER* new3DShape = new S3D_MASTER( NULL ); + #ifdef __WINDOWS__ // Store filename in Unix notation shortfilename.Replace( wxT( "\\" ), wxT( "/" ) ); #endif + new3DShape->SetShape3DName( shortfilename ); m_Shapes3D_list.push_back( new3DShape ); m_3D_ShapeNameListBox->Append( shortfilename ); @@ -512,9 +528,9 @@ void DIALOG_MODULE_BOARD_EDITOR::OnOkClick( wxCommandEvent& event ) m_CurrentModule->Value().Copy( m_ValueCopy ); // Initialize masks clearances - m_CurrentModule->SetLocalClearance( ReturnValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); - m_CurrentModule->SetLocalSolderMaskMargin( ReturnValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); - m_CurrentModule->SetLocalSolderPasteMargin( ReturnValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); + m_CurrentModule->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); + m_CurrentModule->SetLocalSolderMaskMargin( ValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); + m_CurrentModule->SetLocalSolderPasteMargin( ValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); double dtmp = 0.0; msg = m_SolderPasteMarginRatioCtrl->GetValue(); @@ -551,8 +567,8 @@ void DIALOG_MODULE_BOARD_EDITOR::OnOkClick( wxCommandEvent& event ) } // Set Module Position - modpos.x = ReturnValueFromTextCtrl( *m_ModPositionX ); - modpos.y = ReturnValueFromTextCtrl( *m_ModPositionY ); + modpos.x = ValueFromTextCtrl( *m_ModPositionX ); + modpos.y = ValueFromTextCtrl( *m_ModPositionY ); m_CurrentModule->SetPosition( modpos ); m_CurrentModule->SetLocked( m_AutoPlaceCtrl->GetSelection() == 1 ); @@ -600,7 +616,7 @@ void DIALOG_MODULE_BOARD_EDITOR::OnOkClick( wxCommandEvent& event ) m_CurrentModule->Flip( m_CurrentModule->GetPosition() ); // Update 3D shape list - int ii = m_3D_ShapeNameListBox->GetSelection(); + int ii = m_3D_ShapeNameListBox->GetSelection(); if( ii >= 0 ) TransfertDisplayTo3DValues( ii ); @@ -678,3 +694,4 @@ void DIALOG_MODULE_BOARD_EDITOR::OnEditValue( wxCommandEvent& event ) m_Parent->SetCrossHairPosition( tmp ); m_ValueCtrl->SetValue( m_ValueCopy->GetText() ); } + diff --git a/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp b/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp index 0b97c21f0e..3582067ed6 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include <3d_struct.h> #include <3d_viewer.h> @@ -283,17 +283,27 @@ void DIALOG_MODULE_MODULE_EDITOR::Remove3DShape(wxCommandEvent& event) void DIALOG_MODULE_MODULE_EDITOR::BrowseAndAdd3DLib( wxCommandEvent& event ) { - wxString fullfilename, shortfilename; - wxString fullpath; + PROJECT& prj = Prj(); + SEARCH_STACK& search = Kiface().KifaceSearch(); - fullpath = wxGetApp().ReturnLastVisitedLibraryPath( LIB3D_PATH ); + wxString fullpath; + wxString kisys3dmod = wxGetenv( wxT( KISYS3DMOD ) ); + + if( !kisys3dmod || !wxFileName::IsDirReadable( kisys3dmod ) ) + { + fullpath = search.FindValidPath( LIB3D_PATH ); + } + + if( !fullpath ) + fullpath = prj.RPath(PROJECT::VIEWER_3D).LastVisitedPath( search, LIB3D_PATH ); #ifdef __WINDOWS__ fullpath.Replace( wxT( "/" ), wxT( "\\" ) ); #endif - wxString fileFilters; - fileFilters = wxGetTranslation( Shapes3DFileWildcard ); + wxString fullfilename, shortfilename; + wxString fileFilters = wxGetTranslation( Shapes3DFileWildcard ); + fileFilters += wxChar( '|' ); fileFilters += wxGetTranslation( IDF3DFileWildcard ); @@ -311,7 +321,8 @@ void DIALOG_MODULE_MODULE_EDITOR::BrowseAndAdd3DLib( wxCommandEvent& event ) return; wxFileName fn = fullfilename; - wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); + + prj.RPath(PROJECT::VIEWER_3D).SaveLastVisitedPath( fn.GetPath() ); /* If the file path is already in the library search paths * list, just add the library name to the list. Otherwise, add @@ -319,7 +330,7 @@ void DIALOG_MODULE_MODULE_EDITOR::BrowseAndAdd3DLib( wxCommandEvent& event ) * the relative path, when possible is preferable, * because it preserve use of default libraries paths, when the path is a sub path of these default paths */ - shortfilename = wxGetApp().ReturnFilenameWithRelativePathInLibPath( fullfilename ); + shortfilename = search.FilenameWithRelativePathInSearchList( fullfilename ); wxFileName aux = shortfilename; @@ -354,7 +365,6 @@ void DIALOG_MODULE_MODULE_EDITOR::BrowseAndAdd3DLib( wxCommandEvent& event ) m_lastSelected3DShapeIndex = m_3D_ShapeNameListBox->GetCount() - 1; m_3D_ShapeNameListBox->SetSelection( m_lastSelected3DShapeIndex ); Transfert3DValuesToDisplay( m_shapes3D_list[m_lastSelected3DShapeIndex] ); - } @@ -375,7 +385,7 @@ void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) { wxString msg; msg.Printf( _( "Error:\none of invalid chars <%s> found\nin <%s>" ), - MODULE::ReturnStringLibNameInvalidChars( true ), + MODULE::StringLibNameInvalidChars( true ), GetChars( footprintName ) ); DisplayError( NULL, msg ); @@ -415,9 +425,9 @@ void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) m_currentModule->Value().Copy( m_valueCopy ); // Initialize masks clearances - m_currentModule->SetLocalClearance( ReturnValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); - m_currentModule->SetLocalSolderMaskMargin( ReturnValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); - m_currentModule->SetLocalSolderPasteMargin( ReturnValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); + m_currentModule->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); + m_currentModule->SetLocalSolderMaskMargin( ValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); + m_currentModule->SetLocalSolderPasteMargin( ValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); double dtmp; wxString msg = m_SolderPasteMarginRatioCtrl->GetValue(); msg.ToDouble( &dtmp ); diff --git a/pcbnew/dialogs/dialog_edit_module_text.cpp b/pcbnew/dialogs/dialog_edit_module_text.cpp index 267bc05cd6..928ca8541c 100644 --- a/pcbnew/dialogs/dialog_edit_module_text.cpp +++ b/pcbnew/dialogs/dialog_edit_module_text.cpp @@ -197,15 +197,15 @@ void DialogEditModuleText::OnOkClick( wxCommandEvent& event ) wxPoint tmp; msg = m_TxtPosCtrlX->GetValue(); - tmp.x = ReturnValueFromString( g_UserUnit, msg ); + tmp.x = ValueFromString( g_UserUnit, msg ); msg = m_TxtPosCtrlY->GetValue(); - tmp.y = ReturnValueFromString( g_UserUnit, msg ); + tmp.y = ValueFromString( g_UserUnit, msg ); m_currentText->SetPos0( tmp ); - wxSize textSize( wxSize( ReturnValueFromString( g_UserUnit, m_TxtSizeCtrlX->GetValue() ), - ReturnValueFromString( g_UserUnit, m_TxtSizeCtrlY->GetValue() ) ) ); + wxSize textSize( wxSize( ValueFromString( g_UserUnit, m_TxtSizeCtrlX->GetValue() ), + ValueFromString( g_UserUnit, m_TxtSizeCtrlY->GetValue() ) ) ); // Test for a reasonnable size: if( textSize.x < TEXTS_MIN_SIZE ) @@ -216,7 +216,7 @@ void DialogEditModuleText::OnOkClick( wxCommandEvent& event ) m_currentText->SetSize( textSize ), msg = m_TxtWidthCtlr->GetValue(); - int width = ReturnValueFromString( g_UserUnit, msg ); + int width = ValueFromString( g_UserUnit, msg ); // Test for a reasonnable width: if( width <= 1 ) diff --git a/pcbnew/dialogs/dialog_export_idf.cpp b/pcbnew/dialogs/dialog_export_idf.cpp index 6f7b762d27..955c5e932a 100644 --- a/pcbnew/dialogs/dialog_export_idf.cpp +++ b/pcbnew/dialogs/dialog_export_idf.cpp @@ -26,7 +26,7 @@ */ #include -#include +#include #include #include @@ -43,7 +43,7 @@ class DIALOG_EXPORT_IDF3: public DIALOG_EXPORT_IDF3_BASE { private: PCB_EDIT_FRAME* m_parent; - wxConfig* m_config; + wxConfigBase* m_config; bool m_idfThouOpt; // remember last preference for units in THOU void OnCancelClick( wxCommandEvent& event ) @@ -60,7 +60,7 @@ public: DIALOG_EXPORT_IDF3_BASE( parent ) { m_parent = parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); SetFocus(); m_idfThouOpt = false; m_config->Read( OPTKEY_IDF_THOU, &m_idfThouOpt ); diff --git a/pcbnew/dialogs/dialog_export_vrml.cpp b/pcbnew/dialogs/dialog_export_vrml.cpp index 712568e796..acf1cbc2f1 100644 --- a/pcbnew/dialogs/dialog_export_vrml.cpp +++ b/pcbnew/dialogs/dialog_export_vrml.cpp @@ -28,10 +28,11 @@ */ #include #include -#include +#include #include #include + /* the dialog to create VRML files, derived from DIALOG_EXPORT_3DFILE_BASE, * created by wxFormBuilder */ @@ -44,7 +45,7 @@ class DIALOG_EXPORT_3DFILE : public DIALOG_EXPORT_3DFILE_BASE { private: PCB_EDIT_FRAME* m_parent; - wxConfig* m_config; + wxConfigBase* m_config; int m_unitsOpt; // to remember last option int m_3DFilesOpt; // to remember last option @@ -56,7 +57,7 @@ public: DIALOG_EXPORT_3DFILE_BASE( parent ) { m_parent = parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); SetFocus(); m_config->Read( OPTKEY_OUTPUT_UNIT, &m_unitsOpt ); m_config->Read( OPTKEY_3DFILES_OPT, &m_3DFilesOpt ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 0a4d383ea2..a2ed8f5d38 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -705,7 +706,7 @@ private: // Make sure this special environment variable shows up even if it was // not used yet. It is automatically set by KiCad to the directory holding // the current project. - unique.insert( FP_LIB_TABLE::ProjectPathEnvVariableName() ); + unique.insert( PROJECT_VAR_NAME ); unique.insert( FP_LIB_TABLE::GlobalPathEnvVariableName() ); m_path_subs_grid->AppendRows( unique.size() ); diff --git a/pcbnew/dialogs/dialog_freeroute_exchange.cpp b/pcbnew/dialogs/dialog_freeroute_exchange.cpp index ca3bef0cde..81608d3276 100644 --- a/pcbnew/dialogs/dialog_freeroute_exchange.cpp +++ b/pcbnew/dialogs/dialog_freeroute_exchange.cpp @@ -27,7 +27,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -77,7 +78,10 @@ void DIALOG_FREEROUTE::MyInit() m_FreeRouteSetupChanged = false; wxString msg; - wxGetApp().GetSettings()->Read( FREEROUTE_URL_KEY, &msg ); + + wxConfigBase* cfg = Kiface().KifaceSettings(); + + cfg->Read( FREEROUTE_URL_KEY, &msg ); if( msg.IsEmpty() ) m_FreerouteURLName->SetValue( wxT( "http://www.freerouting.net/" ) ); @@ -207,8 +211,8 @@ void DIALOG_FREEROUTE::OnOKButtonClick( wxCommandEvent& event ) { if( m_FreeRouteSetupChanged ) // Save new config { - wxGetApp().GetSettings()->Write( FREEROUTE_URL_KEY, - m_FreerouteURLName->GetValue() ); + Kiface().KifaceSettings()->Write( + FREEROUTE_URL_KEY, m_FreerouteURLName->GetValue() ); } EndModal(wxID_OK); diff --git a/pcbnew/dialogs/dialog_gendrill.cpp b/pcbnew/dialogs/dialog_gendrill.cpp index c46e1f8e37..6350bbe8ba 100644 --- a/pcbnew/dialogs/dialog_gendrill.cpp +++ b/pcbnew/dialogs/dialog_gendrill.cpp @@ -27,7 +27,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -74,7 +75,7 @@ DIALOG_GENDRILL::DIALOG_GENDRILL( PCB_EDIT_FRAME* parent ) : { m_parent = parent; m_board = parent->GetBoard(); - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); m_plotOpts = m_parent->GetPlotSettings(); SetReturnCode( 1 ); diff --git a/pcbnew/dialogs/dialog_gendrill.h b/pcbnew/dialogs/dialog_gendrill.h index b7c2717886..8d452833ed 100644 --- a/pcbnew/dialogs/dialog_gendrill.h +++ b/pcbnew/dialogs/dialog_gendrill.h @@ -50,7 +50,7 @@ public: private: PCB_EDIT_FRAME* m_parent; - wxConfig* m_config; + wxConfigBase* m_config; BOARD* m_board; PCB_PLOT_PARAMS m_plotOpts; @@ -69,9 +69,9 @@ private: // event functions void OnSelDrillUnitsSelected( wxCommandEvent& event ); void OnSelZerosFmtSelected( wxCommandEvent& event ); - void OnGenDrillFile( wxCommandEvent& event ); - void OnGenMapFile( wxCommandEvent& event ); - void OnGenReportFile( wxCommandEvent& event ); + void OnGenDrillFile( wxCommandEvent& event ); + void OnGenMapFile( wxCommandEvent& event ); + void OnGenReportFile( wxCommandEvent& event ); void OnCancelClick( wxCommandEvent& event ); void OnOutputDirectoryBrowseClicked( wxCommandEvent& event ); diff --git a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp index b5114a0ce8..02577075cd 100644 --- a/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp +++ b/pcbnew/dialogs/dialog_global_edit_tracks_and_vias.cpp @@ -74,13 +74,13 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::MyInit() // Display current values, and current netclass values: int value = netclass->GetTrackWidth(); // Display track width - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 0, msg ); if( board->GetTrackWidthIndex() ) { value = board->GetCurrentTrackWidth(); - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); } else msg = _( "Default" ); @@ -88,45 +88,45 @@ void DIALOG_GLOBAL_EDIT_TRACKS_AND_VIAS::MyInit() m_gridDisplayCurrentSettings->SetCellValue( 1, 0, msg ); value = netclass->GetViaDiameter(); // Display via diameter - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 1, msg ); if( board->GetViaSizeIndex() ) { value = board->GetCurrentViaSize(); - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); } else msg = _( "Default" ); m_gridDisplayCurrentSettings->SetCellValue( 1, 1, msg ); value = netclass->GetViaDrill(); // Display via drill - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 2, msg ); value = board->GetCurrentViaDrill(); if( value >= 0 ) - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); else msg = _( "Default" ); m_gridDisplayCurrentSettings->SetCellValue( 1, 2, msg ); value = netclass->GetuViaDiameter(); // Display micro via diameter - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 3, msg ); #if 0 // Currently we use always the default netclass value value = board->GetCurrentMicroViaSize(); - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); #endif msg = _( "Default" ); m_gridDisplayCurrentSettings->SetCellValue( 1, 3, msg ); value = netclass->GetuViaDrill(); // Display micro via drill - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); m_gridDisplayCurrentSettings->SetCellValue( 0, 4, msg ); #if 0 // Currently we use always the default netclass value value = board->GetCurrentMicroViaDrill(); if( value >= 0 ) - msg = ReturnStringFromValue( g_UserUnit, value, true ); + msg = StringFromValue( g_UserUnit, value, true ); else #endif msg = _( "Default" ); diff --git a/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp b/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp index 63b4df2308..9f391c2e24 100644 --- a/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp +++ b/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp @@ -97,11 +97,11 @@ void DIALOG_GLOBAL_MODULES_FIELDS_EDITION::initDialog() m_SizeYunit->SetLabel( GetAbbreviatedUnitsLabel() ); m_Ticknessunit->SetLabel( GetAbbreviatedUnitsLabel() ); m_SizeX_Value->SetValue( - ReturnStringFromValue( g_UserUnit, m_brdSettings->m_ModuleTextSize.x ) ); + StringFromValue( g_UserUnit, m_brdSettings->m_ModuleTextSize.x ) ); m_SizeY_Value->SetValue( - ReturnStringFromValue( g_UserUnit, m_brdSettings->m_ModuleTextSize.y ) ); + StringFromValue( g_UserUnit, m_brdSettings->m_ModuleTextSize.y ) ); m_TicknessValue->SetValue( - ReturnStringFromValue( g_UserUnit, m_brdSettings->m_ModuleTextWidth) ); + StringFromValue( g_UserUnit, m_brdSettings->m_ModuleTextWidth) ); Layout(); GetSizer()->SetSizeHints( this ); @@ -116,9 +116,9 @@ void DIALOG_GLOBAL_MODULES_FIELDS_EDITION::OnOKClick( wxCommandEvent& event ) m_othersSelection = m_OtherFields->GetValue(); m_filterString = m_ModuleFilter->GetValue(); - m_brdSettings->m_ModuleTextSize.x = ReturnValueFromTextCtrl( *m_SizeX_Value ); - m_brdSettings->m_ModuleTextSize.y = ReturnValueFromTextCtrl( *m_SizeY_Value ); - m_brdSettings->m_ModuleTextWidth = ReturnValueFromTextCtrl( *m_TicknessValue ); + m_brdSettings->m_ModuleTextSize.x = ValueFromTextCtrl( *m_SizeX_Value ); + m_brdSettings->m_ModuleTextSize.y = ValueFromTextCtrl( *m_SizeY_Value ); + m_brdSettings->m_ModuleTextWidth = ValueFromTextCtrl( *m_TicknessValue ); // clip m_ModuleTextWidth to the 1/4 of min size, to keep it always readable int minsize = std::min( m_brdSettings->m_ModuleTextSize.x, diff --git a/pcbnew/dialogs/dialog_graphic_item_properties.cpp b/pcbnew/dialogs/dialog_graphic_item_properties.cpp index ddff38dbd8..ea133794b8 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties.cpp @@ -215,22 +215,22 @@ void DIALOG_GRAPHIC_ITEM_PROPERTIES::OnOkClick( wxCommandEvent& event ) m_Item->Draw( m_parent->GetCanvas(), m_DC, GR_XOR ); msg = m_Center_StartXCtrl->GetValue(); - m_Item->SetStartX( ReturnValueFromString( g_UserUnit, msg ) ); + m_Item->SetStartX( ValueFromString( g_UserUnit, msg ) ); msg = m_Center_StartYCtrl->GetValue(); - m_Item->SetStartY( ReturnValueFromString( g_UserUnit, msg ) ); + m_Item->SetStartY( ValueFromString( g_UserUnit, msg ) ); msg = m_EndX_Radius_Ctrl->GetValue(); - m_Item->SetEndX( ReturnValueFromString( g_UserUnit, msg ) ); + m_Item->SetEndX( ValueFromString( g_UserUnit, msg ) ); msg = m_EndY_Ctrl->GetValue(); - m_Item->SetEndY( ReturnValueFromString( g_UserUnit, msg ) ); + m_Item->SetEndY( ValueFromString( g_UserUnit, msg ) ); msg = m_ThicknessCtrl->GetValue(); - m_Item->SetWidth( ReturnValueFromString( g_UserUnit, msg ) ); + m_Item->SetWidth( ValueFromString( g_UserUnit, msg ) ); msg = m_DefaultThicknessCtrl->GetValue(); - int thickness = ReturnValueFromString( g_UserUnit, msg ); + int thickness = ValueFromString( g_UserUnit, msg ); m_Item->SetLayer( m_LayerSelectionCtrl->GetLayerSelection() ); diff --git a/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp b/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp index 9c4fdd2dfe..c04fb03acd 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp @@ -199,24 +199,24 @@ void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::OnOkClick( wxCommandEvent& event ) wxPoint coord; msg = m_Center_StartXCtrl->GetValue(); - coord.x = ReturnValueFromString( g_UserUnit, msg ); + coord.x = ValueFromString( g_UserUnit, msg ); msg = m_Center_StartYCtrl->GetValue(); - coord.y = ReturnValueFromString( g_UserUnit, msg ); + coord.y = ValueFromString( g_UserUnit, msg ); m_item->SetStart( coord ); m_item->SetStart0( coord ); msg = m_EndX_Radius_Ctrl->GetValue(); - coord.x = ReturnValueFromString( g_UserUnit, msg ); + coord.x = ValueFromString( g_UserUnit, msg ); msg = m_EndY_Ctrl->GetValue(); - coord.y = ReturnValueFromString( g_UserUnit, msg ); + coord.y = ValueFromString( g_UserUnit, msg ); m_item->SetEnd( coord ); m_item->SetEnd0( coord ); msg = m_ThicknessCtrl->GetValue(); - m_item->SetWidth( ReturnValueFromString( g_UserUnit, msg ) ); + m_item->SetWidth( ValueFromString( g_UserUnit, msg ) ); msg = m_DefaultThicknessCtrl->GetValue(); - int thickness = ReturnValueFromString( g_UserUnit, msg ); + int thickness = ValueFromString( g_UserUnit, msg ); m_brdSettings.m_ModuleSegmentWidth = thickness; m_parent->SetDesignSettings( m_brdSettings ); diff --git a/pcbnew/dialogs/dialog_graphic_items_options.cpp b/pcbnew/dialogs/dialog_graphic_items_options.cpp index 7b39406aa8..b68819810f 100644 --- a/pcbnew/dialogs/dialog_graphic_items_options.cpp +++ b/pcbnew/dialogs/dialog_graphic_items_options.cpp @@ -97,20 +97,20 @@ void DIALOG_GRAPHIC_ITEMS_OPTIONS::initValues() void DIALOG_GRAPHIC_ITEMS_OPTIONS::OnOkClick( wxCommandEvent& event ) { - m_brdSettings.m_DrawSegmentWidth = ReturnValueFromTextCtrl( *m_OptPcbSegmWidth ); - m_brdSettings.m_EdgeSegmentWidth = ReturnValueFromTextCtrl( *m_OptPcbEdgesWidth ); - m_brdSettings.m_PcbTextWidth = ReturnValueFromTextCtrl( *m_OptPcbTextWidth ); - m_brdSettings.m_PcbTextSize.y = ReturnValueFromTextCtrl( *m_OptPcbTextVSize ); - m_brdSettings.m_PcbTextSize.x = ReturnValueFromTextCtrl( *m_OptPcbTextHSize ); + m_brdSettings.m_DrawSegmentWidth = ValueFromTextCtrl( *m_OptPcbSegmWidth ); + m_brdSettings.m_EdgeSegmentWidth = ValueFromTextCtrl( *m_OptPcbEdgesWidth ); + m_brdSettings.m_PcbTextWidth = ValueFromTextCtrl( *m_OptPcbTextWidth ); + m_brdSettings.m_PcbTextSize.y = ValueFromTextCtrl( *m_OptPcbTextVSize ); + m_brdSettings.m_PcbTextSize.x = ValueFromTextCtrl( *m_OptPcbTextHSize ); m_parent->GetBoard()->SetDesignSettings( m_brdSettings ); - m_brdSettings.m_ModuleSegmentWidth = ReturnValueFromTextCtrl( *m_OptModuleEdgesWidth ); - m_brdSettings.m_ModuleTextWidth = ReturnValueFromTextCtrl( *m_OptModuleTextWidth ); - m_brdSettings.m_ModuleTextSize.y = ReturnValueFromTextCtrl( *m_OptModuleTextVSize ); - m_brdSettings.m_ModuleTextSize.x = ReturnValueFromTextCtrl( *m_OptModuleTextHSize ); + m_brdSettings.m_ModuleSegmentWidth = ValueFromTextCtrl( *m_OptModuleEdgesWidth ); + m_brdSettings.m_ModuleTextWidth = ValueFromTextCtrl( *m_OptModuleTextWidth ); + m_brdSettings.m_ModuleTextSize.y = ValueFromTextCtrl( *m_OptModuleTextVSize ); + m_brdSettings.m_ModuleTextSize.x = ValueFromTextCtrl( *m_OptModuleTextHSize ); - g_DrawDefaultLineThickness = ReturnValueFromTextCtrl( *m_DefaultPenSizeCtrl ); + g_DrawDefaultLineThickness = ValueFromTextCtrl( *m_DefaultPenSizeCtrl ); if( g_DrawDefaultLineThickness < 0 ) g_DrawDefaultLineThickness = 0; diff --git a/pcbnew/dialogs/dialog_keepout_area_properties.cpp b/pcbnew/dialogs/dialog_keepout_area_properties.cpp index 17e7843054..af5ba6ff24 100644 --- a/pcbnew/dialogs/dialog_keepout_area_properties.cpp +++ b/pcbnew/dialogs/dialog_keepout_area_properties.cpp @@ -29,7 +29,8 @@ #include #include -#include +//#include +#include #include #include #include @@ -56,7 +57,7 @@ public: private: PCB_BASE_FRAME* m_parent; - wxConfig* m_config; ///< Current config + wxConfigBase* m_config; ///< Current config ZONE_SETTINGS m_zonesettings; ZONE_SETTINGS* m_ptr; @@ -105,7 +106,7 @@ DIALOG_KEEPOUT_AREA_PROPERTIES::DIALOG_KEEPOUT_AREA_PROPERTIES( PCB_BASE_FRAME* DIALOG_KEEPOUT_AREA_PROPERTIES_BASE( aParent ) { m_parent = aParent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); m_ptr = aSettings; m_zonesettings = *aSettings; diff --git a/pcbnew/dialogs/dialog_mask_clearance.cpp b/pcbnew/dialogs/dialog_mask_clearance.cpp index 07f8948a16..913ba2e8ff 100644 --- a/pcbnew/dialogs/dialog_mask_clearance.cpp +++ b/pcbnew/dialogs/dialog_mask_clearance.cpp @@ -85,10 +85,10 @@ void DIALOG_PADS_MASK_CLEARANCE::myInit() void DIALOG_PADS_MASK_CLEARANCE::OnButtonOkClick( wxCommandEvent& event ) { - m_brdSettings.m_SolderMaskMargin = ReturnValueFromTextCtrl( *m_SolderMaskMarginCtrl ); - m_brdSettings.m_SolderMaskMinWidth = ReturnValueFromTextCtrl( *m_SolderMaskMinWidthCtrl ); + m_brdSettings.m_SolderMaskMargin = ValueFromTextCtrl( *m_SolderMaskMarginCtrl ); + m_brdSettings.m_SolderMaskMinWidth = ValueFromTextCtrl( *m_SolderMaskMinWidthCtrl ); - m_brdSettings.m_SolderPasteMargin = ReturnValueFromTextCtrl( *m_SolderPasteMarginCtrl ); + m_brdSettings.m_SolderPasteMargin = ValueFromTextCtrl( *m_SolderPasteMarginCtrl ); double dtmp = 0; wxString msg = m_SolderPasteMarginRatioCtrl->GetValue(); diff --git a/pcbnew/dialogs/dialog_netlist.cpp b/pcbnew/dialogs/dialog_netlist.cpp index 50ad5f0063..e7cb66c29e 100644 --- a/pcbnew/dialogs/dialog_netlist.cpp +++ b/pcbnew/dialogs/dialog_netlist.cpp @@ -27,7 +27,9 @@ */ #include -#include +//#include +#include +#include #include #include #include @@ -86,7 +88,10 @@ void PCB_EDIT_FRAME::InstallNetlistFrame( wxDC* DC ) { wxFileName fn = GetBoard()->GetFileName(); fn.SetExt( ProjectFileExtension ); - wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters() ); + + // was: wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters() ); + Prj().ConfigSave( Kiface().KifaceSearch(), fn.GetFullPath(), + GROUP, GetProjectFileParameters() ); } } @@ -97,7 +102,7 @@ DIALOG_NETLIST::DIALOG_NETLIST( PCB_EDIT_FRAME* aParent, wxDC * aDC, { m_parent = aParent; m_dc = aDC; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); m_silentMode = m_config->Read( NETLIST_SILENTMODE_KEY, 0l ); m_reportAll = m_config->Read( NETLIST_FULLMESSAGES_KEY, 1l ); bool tmp = m_config->Read( NETLIST_DELETESINGLEPADNETS_KEY, 0l ); diff --git a/pcbnew/dialogs/dialog_netlist.h b/pcbnew/dialogs/dialog_netlist.h index 475588bce0..33910fbbe5 100644 --- a/pcbnew/dialogs/dialog_netlist.h +++ b/pcbnew/dialogs/dialog_netlist.h @@ -43,7 +43,7 @@ private: bool m_silentMode; // if true, do not display warning message about undo bool m_reportAll; // If true report all messages, // false, report only warnings or errors - wxConfig* m_config; + wxConfigBase* m_config; public: DIALOG_NETLIST( PCB_EDIT_FRAME* aParent, wxDC* aDC, const wxString & aNetlistFullFilename ); diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 0ab2b700ca..fbc555232b 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -863,11 +863,11 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) aPad->SetShape( CodeShape[m_PadShape->GetSelection()] ); // Read pad clearances values: - aPad->SetLocalClearance( ReturnValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); - aPad->SetLocalSolderMaskMargin( ReturnValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); - aPad->SetLocalSolderPasteMargin( ReturnValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); - aPad->SetThermalWidth( ReturnValueFromTextCtrl( *m_ThermalWidthCtrl ) ); - aPad->SetThermalGap( ReturnValueFromTextCtrl( *m_ThermalGapCtrl ) ); + aPad->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); + aPad->SetLocalSolderMaskMargin( ValueFromTextCtrl( *m_SolderMaskMarginCtrl ) ); + aPad->SetLocalSolderPasteMargin( ValueFromTextCtrl( *m_SolderPasteMarginCtrl ) ); + aPad->SetThermalWidth( ValueFromTextCtrl( *m_ThermalWidthCtrl ) ); + aPad->SetThermalGap( ValueFromTextCtrl( *m_ThermalGapCtrl ) ); double dtmp = 0.0; msg = m_SolderPasteMarginRatioCtrl->GetValue(); msg.ToDouble( &dtmp ); @@ -903,15 +903,15 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) } // Read pad position: - x = ReturnValueFromTextCtrl( *m_PadPosition_X_Ctrl ); - y = ReturnValueFromTextCtrl( *m_PadPosition_Y_Ctrl ); + x = ValueFromTextCtrl( *m_PadPosition_X_Ctrl ); + y = ValueFromTextCtrl( *m_PadPosition_Y_Ctrl ); aPad->SetPosition( wxPoint( x, y ) ); aPad->SetPos0( wxPoint( x, y ) ); // Read pad drill: - x = ReturnValueFromTextCtrl( *m_PadDrill_X_Ctrl ); - y = ReturnValueFromTextCtrl( *m_PadDrill_Y_Ctrl ); + x = ValueFromTextCtrl( *m_PadDrill_X_Ctrl ); + y = ValueFromTextCtrl( *m_PadDrill_Y_Ctrl ); if( m_DrillShapeCtrl->GetSelection() == 0 ) { @@ -924,24 +924,24 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) aPad->SetDrillSize( wxSize( x, y ) ); // Read pad shape size: - x = ReturnValueFromTextCtrl( *m_ShapeSize_X_Ctrl ); - y = ReturnValueFromTextCtrl( *m_ShapeSize_Y_Ctrl ); + x = ValueFromTextCtrl( *m_ShapeSize_X_Ctrl ); + y = ValueFromTextCtrl( *m_ShapeSize_Y_Ctrl ); if( aPad->GetShape() == PAD_CIRCLE ) y = x; aPad->SetSize( wxSize( x, y ) ); // Read pad length die - aPad->SetPadToDieLength( ReturnValueFromTextCtrl( *m_LengthPadToDieCtrl ) ); + aPad->SetPadToDieLength( ValueFromTextCtrl( *m_LengthPadToDieCtrl ) ); // Read pad shape delta size: // m_DeltaSize.x or m_DeltaSize.y must be NULL. for a trapezoid. wxSize delta; if( m_trapDeltaDirChoice->GetSelection() == 0 ) - delta.x = ReturnValueFromTextCtrl( *m_ShapeDelta_Ctrl ); + delta.x = ValueFromTextCtrl( *m_ShapeDelta_Ctrl ); else - delta.y = ReturnValueFromTextCtrl( *m_ShapeDelta_Ctrl ); + delta.y = ValueFromTextCtrl( *m_ShapeDelta_Ctrl ); // Test bad values (be sure delta values are not too large) // remember DeltaSize.x is the Y size variation @@ -974,8 +974,8 @@ bool DIALOG_PAD_PROPERTIES::transferDataToPad( D_PAD* aPad ) aPad->SetDelta( delta ); // Read pad shape offset: - x = ReturnValueFromTextCtrl( *m_ShapeOffset_X_Ctrl ); - y = ReturnValueFromTextCtrl( *m_ShapeOffset_Y_Ctrl ); + x = ValueFromTextCtrl( *m_ShapeOffset_X_Ctrl ); + y = ValueFromTextCtrl( *m_ShapeOffset_Y_Ctrl ); aPad->SetOffset( wxPoint( x, y ) ); double orient_value = 0; diff --git a/pcbnew/dialogs/dialog_pcb_text_properties.cpp b/pcbnew/dialogs/dialog_pcb_text_properties.cpp index 4a0f91440e..9f58be5e1d 100644 --- a/pcbnew/dialogs/dialog_pcb_text_properties.cpp +++ b/pcbnew/dialogs/dialog_pcb_text_properties.cpp @@ -211,13 +211,13 @@ void DIALOG_PCB_TEXT_PROPERTIES::OnOkClick( wxCommandEvent& event ) } // Set PCB Text position - newPosition.x = ReturnValueFromString( g_UserUnit, m_PositionXCtrl->GetValue() ); - newPosition.y = ReturnValueFromString( g_UserUnit, m_PositionYCtrl->GetValue() ); + newPosition.x = ValueFromString( g_UserUnit, m_PositionXCtrl->GetValue() ); + newPosition.y = ValueFromString( g_UserUnit, m_PositionYCtrl->GetValue() ); m_SelectedPCBText->SetTextPosition( newPosition ); // Check constraints and set PCB Text size - newSize.x = ReturnValueFromString( g_UserUnit, m_SizeXCtrl->GetValue() ); - newSize.y = ReturnValueFromString( g_UserUnit, m_SizeYCtrl->GetValue() ); + newSize.x = ValueFromString( g_UserUnit, m_SizeXCtrl->GetValue() ); + newSize.y = ValueFromString( g_UserUnit, m_SizeYCtrl->GetValue() ); if( newSize.x < TEXTS_MIN_SIZE ) newSize.x = TEXTS_MIN_SIZE; @@ -234,7 +234,7 @@ void DIALOG_PCB_TEXT_PROPERTIES::OnOkClick( wxCommandEvent& event ) m_SelectedPCBText->SetSize( newSize ); // Set the new thickness - m_SelectedPCBText->SetThickness( ReturnValueFromString( g_UserUnit, + m_SelectedPCBText->SetThickness( ValueFromString( g_UserUnit, m_ThicknessCtrl->GetValue() ) ); // Test for acceptable values for thickness and size and clamp if fails diff --git a/pcbnew/dialogs/dialog_plot.cpp b/pcbnew/dialogs/dialog_plot.cpp index bc13af8558..36b8d3da07 100644 --- a/pcbnew/dialogs/dialog_plot.cpp +++ b/pcbnew/dialogs/dialog_plot.cpp @@ -25,7 +25,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include + +#include #include #include #include @@ -44,7 +45,7 @@ DIALOG_PLOT::DIALOG_PLOT( PCB_EDIT_FRAME* aParent ) : m_board( aParent->GetBoard() ), m_plotOpts( aParent->GetPlotSettings() ) { - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); m_brdSettings = m_board->GetDesignSettings(); Init_Dialog(); @@ -100,25 +101,25 @@ void DIALOG_PLOT::Init_Dialog() break; } - msg = ReturnStringFromValue( g_UserUnit, m_brdSettings.m_SolderMaskMargin, true ); + msg = StringFromValue( g_UserUnit, m_brdSettings.m_SolderMaskMargin, true ); m_SolderMaskMarginCurrValue->SetLabel( msg ); - msg = ReturnStringFromValue( g_UserUnit, m_brdSettings.m_SolderMaskMinWidth, true ); + msg = StringFromValue( g_UserUnit, m_brdSettings.m_SolderMaskMinWidth, true ); m_SolderMaskMinWidthCurrValue->SetLabel( msg ); // Set units and value for HPGL pen size (this param in in mils). AddUnitSymbol( *m_textPenSize, g_UserUnit ); - msg = ReturnStringFromValue( g_UserUnit, + msg = StringFromValue( g_UserUnit, m_plotOpts.GetHPGLPenDiameter() * IU_PER_MILS ); m_HPGLPenSizeOpt->AppendText( msg ); // Set units and value for HPGL pen overlay (this param in in mils). AddUnitSymbol( *m_textPenOvr, g_UserUnit ); - msg = ReturnStringFromValue( g_UserUnit, + msg = StringFromValue( g_UserUnit, m_plotOpts.GetHPGLPenOverlay() * IU_PER_MILS ); m_HPGLPenOverlayOpt->AppendText( msg ); AddUnitSymbol( *m_textDefaultPenSize, g_UserUnit ); - msg = ReturnStringFromValue( g_UserUnit, m_plotOpts.GetLineWidth() ); + msg = StringFromValue( g_UserUnit, m_plotOpts.GetLineWidth() ); m_linesWidth->AppendText( msg ); // Set units for PS global width correction. @@ -583,11 +584,11 @@ void DIALOG_PLOT::applyPlotSettings() // read HPLG pen size (this param is stored in mils) wxString msg = m_HPGLPenSizeOpt->GetValue(); - int tmp = ReturnValueFromString( g_UserUnit, msg ) / IU_PER_MILS; + int tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS; if( !tempOptions.SetHPGLPenDiameter( tmp ) ) { - msg = ReturnStringFromValue( g_UserUnit, tempOptions.GetHPGLPenDiameter() * IU_PER_MILS ); + msg = StringFromValue( g_UserUnit, tempOptions.GetHPGLPenDiameter() * IU_PER_MILS ); m_HPGLPenSizeOpt->SetValue( msg ); msg.Printf( _( "HPGL pen size constrained!\n" ) ); m_messagesBox->AppendText( msg ); @@ -595,11 +596,11 @@ void DIALOG_PLOT::applyPlotSettings() // Read HPGL pen overlay (this param is stored in mils) msg = m_HPGLPenOverlayOpt->GetValue(); - tmp = ReturnValueFromString( g_UserUnit, msg ) / IU_PER_MILS; + tmp = ValueFromString( g_UserUnit, msg ) / IU_PER_MILS; if( !tempOptions.SetHPGLPenOverlay( tmp ) ) { - msg = ReturnStringFromValue( g_UserUnit, + msg = StringFromValue( g_UserUnit, tempOptions.GetHPGLPenOverlay() * IU_PER_MILS ); m_HPGLPenOverlayOpt->SetValue( msg ); msg.Printf( _( "HPGL pen overlay constrained!\n" ) ); @@ -608,11 +609,11 @@ void DIALOG_PLOT::applyPlotSettings() // Default linewidth msg = m_linesWidth->GetValue(); - tmp = ReturnValueFromString( g_UserUnit, msg ); + tmp = ValueFromString( g_UserUnit, msg ); if( !tempOptions.SetLineWidth( tmp ) ) { - msg = ReturnStringFromValue( g_UserUnit, tempOptions.GetLineWidth() ); + msg = StringFromValue( g_UserUnit, tempOptions.GetLineWidth() ); m_linesWidth->SetValue( msg ); msg.Printf( _( "Default line width constrained!\n" ) ); m_messagesBox->AppendText( msg ); @@ -649,11 +650,11 @@ void DIALOG_PLOT::applyPlotSettings() // PS Width correction msg = m_PSFineAdjustWidthOpt->GetValue(); - int itmp = ReturnValueFromString( g_UserUnit, msg ); + int itmp = ValueFromString( g_UserUnit, msg ); if( !setInt( &m_PSWidthAdjust, itmp, m_widthAdjustMinValue, m_widthAdjustMaxValue ) ) { - msg = ReturnStringFromValue( g_UserUnit, m_PSWidthAdjust ); + msg = StringFromValue( g_UserUnit, m_PSWidthAdjust ); m_PSFineAdjustWidthOpt->SetValue( msg ); msg.Printf( _( "Width correction constrained!\n" "The reasonable width correction value must be in a range of\n" diff --git a/pcbnew/dialogs/dialog_plot.h b/pcbnew/dialogs/dialog_plot.h index 14bb893fcc..4be5e712d5 100644 --- a/pcbnew/dialogs/dialog_plot.h +++ b/pcbnew/dialogs/dialog_plot.h @@ -42,7 +42,7 @@ private: PCB_EDIT_FRAME* m_parent; BOARD* m_board; BOARD_DESIGN_SETTINGS m_brdSettings; - wxConfig* m_config; + wxConfigBase* m_config; std::vector m_layerList; // List to hold CheckListBox layer numbers double m_XScaleAdjust; // X scale factor adjust to compensate // plotter X scaling error diff --git a/pcbnew/dialogs/dialog_print_for_modedit.cpp b/pcbnew/dialogs/dialog_print_for_modedit.cpp index 9a2b0beda7..12073f5df3 100644 --- a/pcbnew/dialogs/dialog_print_for_modedit.cpp +++ b/pcbnew/dialogs/dialog_print_for_modedit.cpp @@ -2,7 +2,8 @@ /* File: dialog_print_for_modedit.cpp */ #include -#include +//#include +#include #include #include #include @@ -34,7 +35,7 @@ public: private: PCB_BASE_FRAME* m_parent; - wxConfig* m_config; + wxConfigBase* m_config; void OnCloseWindow( wxCloseEvent& event ); @@ -87,7 +88,7 @@ DIALOG_PRINT_FOR_MODEDIT::DIALOG_PRINT_FOR_MODEDIT( PCB_BASE_FRAME* parent ) : { m_parent = parent; s_Parameters.m_ForceCentered = true; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); InitValues(); m_buttonPrint->SetDefault(); diff --git a/pcbnew/dialogs/dialog_print_using_printer.cpp b/pcbnew/dialogs/dialog_print_using_printer.cpp index 33f9a5662a..fae82d0625 100644 --- a/pcbnew/dialogs/dialog_print_using_printer.cpp +++ b/pcbnew/dialogs/dialog_print_using_printer.cpp @@ -6,7 +6,8 @@ //#define wxTEST_POSTSCRIPT_IN_MSW 1 #include -#include +//#include +#include #include #include #include @@ -61,7 +62,7 @@ public: private: PCB_EDIT_FRAME* m_parent; - wxConfig* m_config; + wxConfigBase* m_config; wxCheckBox* m_BoxSelectLayer[32]; static bool m_ExcludeEdgeLayer; @@ -124,7 +125,7 @@ DIALOG_PRINT_USING_PRINTER::DIALOG_PRINT_USING_PRINTER( PCB_EDIT_FRAME* parent ) DIALOG_PRINT_USING_PRINTER_base( parent ) { m_parent = parent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); InitValues( ); @@ -259,7 +260,7 @@ void DIALOG_PRINT_USING_PRINTER::InitValues( ) s_Parameters.m_PenDefaultSize = g_DrawDefaultLineThickness; AddUnitSymbol( *m_TextPenWidth, g_UserUnit ); m_DialogPenWidth->SetValue( - ReturnStringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) ); + StringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) ); // Create scale adjust option msg.Printf( wxT( "%f" ), s_Parameters.m_XScaleAdjust ); @@ -385,7 +386,7 @@ void DIALOG_PRINT_USING_PRINTER::SetPenWidth() // Get the new pen width value, and verify min et max value // NOTE: s_Parameters.m_PenDefaultSize is in internal units - s_Parameters.m_PenDefaultSize = ReturnValueFromTextCtrl( *m_DialogPenWidth ); + s_Parameters.m_PenDefaultSize = ValueFromTextCtrl( *m_DialogPenWidth ); if( s_Parameters.m_PenDefaultSize > PEN_WIDTH_MAX_VALUE ) { @@ -400,7 +401,7 @@ void DIALOG_PRINT_USING_PRINTER::SetPenWidth() g_DrawDefaultLineThickness = s_Parameters.m_PenDefaultSize; m_DialogPenWidth->SetValue( - ReturnStringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) ); + StringFromValue( g_UserUnit, s_Parameters.m_PenDefaultSize ) ); } void DIALOG_PRINT_USING_PRINTER::OnScaleSelectionClick( wxCommandEvent& event ) diff --git a/pcbnew/dialogs/dialog_set_grid.cpp b/pcbnew/dialogs/dialog_set_grid.cpp index d22890b572..d60e152805 100644 --- a/pcbnew/dialogs/dialog_set_grid.cpp +++ b/pcbnew/dialogs/dialog_set_grid.cpp @@ -141,8 +141,8 @@ wxPoint DIALOG_SET_GRID::getGridOrigin() wxPoint grid; // @todo Some error checking here would be a good thing. - grid.x = ReturnValueFromTextCtrl( *m_GridOriginXCtrl ); - grid.y = ReturnValueFromTextCtrl( *m_GridOriginYCtrl ); + grid.x = ValueFromTextCtrl( *m_GridOriginXCtrl ); + grid.y = ValueFromTextCtrl( *m_GridOriginYCtrl ); return grid; } diff --git a/pcbnew/dimension.cpp b/pcbnew/dimension.cpp index 819c1a3110..09e9b35d24 100644 --- a/pcbnew/dimension.cpp +++ b/pcbnew/dimension.cpp @@ -176,22 +176,22 @@ void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) // Get new size value: msg = m_TxtSizeXCtrl->GetValue(); - CurrentDimension->Text().SetWidth( ReturnValueFromString( g_UserUnit, msg ) ); + CurrentDimension->Text().SetWidth( ValueFromString( g_UserUnit, msg ) ); msg = m_TxtSizeYCtrl->GetValue(); - CurrentDimension->Text().SetHeight( ReturnValueFromString( g_UserUnit, msg ) ); + CurrentDimension->Text().SetHeight( ValueFromString( g_UserUnit, msg ) ); // Get new position value: // It will be copied later in dimension, because msg = m_textCtrlPosX->GetValue(); wxPoint pos; - pos.x = ReturnValueFromString( g_UserUnit, msg ); + pos.x = ValueFromString( g_UserUnit, msg ); msg = m_textCtrlPosY->GetValue(); - pos.y = ReturnValueFromString( g_UserUnit, msg ); + pos.y = ValueFromString( g_UserUnit, msg ); CurrentDimension->Text().SetTextPosition( pos ); // Get new line thickness value: msg = m_TxtWidthCtrl->GetValue(); - int width = ReturnValueFromString( g_UserUnit, msg ); + int width = ValueFromString( g_UserUnit, msg ); int maxthickness = Clamp_Text_PenSize( width, CurrentDimension->Text().GetSize() ); if( width > maxthickness ) diff --git a/pcbnew/drc.cpp b/pcbnew/drc.cpp index bad9f65fd7..0fd5214de5 100644 --- a/pcbnew/drc.cpp +++ b/pcbnew/drc.cpp @@ -299,7 +299,7 @@ bool DRC::doNetClass( NETCLASS* nc, wxString& msg ) const BOARD_DESIGN_SETTINGS& g = m_pcb->GetDesignSettings(); -#define FmtVal( x ) GetChars( ReturnStringFromValue( g_UserUnit, x ) ) +#define FmtVal( x ) GetChars( StringFromValue( g_UserUnit, x ) ) #if 0 // set to 1 when (if...) BOARD_DESIGN_SETTINGS has a m_MinClearance value if( nc->GetClearance() < g.m_MinClearance ) diff --git a/pcbnew/drc_clearance_test_functions.cpp b/pcbnew/drc_clearance_test_functions.cpp index 1fd8a94ccd..c012c2456a 100644 --- a/pcbnew/drc_clearance_test_functions.cpp +++ b/pcbnew/drc_clearance_test_functions.cpp @@ -207,7 +207,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) LAYER_NUM layer1, layer2; bool err = true; - ( (SEGVIA*) aRefSeg )->ReturnLayerPair( &layer1, &layer2 ); + ( (SEGVIA*) aRefSeg )->LayerPair( &layer1, &layer2 ); if( layer1 > layer2 ) EXCHG( layer1, layer2 ); @@ -315,7 +315,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads ) continue; // DRC for the pad - shape_pos = pad->ReturnShapePos(); + shape_pos = pad->ShapePos(); m_padToTestPos = shape_pos - origin; if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) ) @@ -588,7 +588,7 @@ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) int dist_min = aRefPad->GetClearance( aPad ); // relativePadPos is the aPad shape position relative to the aRefPad shape position - wxPoint relativePadPos = aPad->ReturnShapePos() - aRefPad->ReturnShapePos(); + wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos(); dist = KiROUND( EuclideanNorm( relativePadPos ) ); diff --git a/pcbnew/edgemod.cpp b/pcbnew/edgemod.cpp index 14843623a1..7239dc37a8 100644 --- a/pcbnew/edgemod.cpp +++ b/pcbnew/edgemod.cpp @@ -251,14 +251,14 @@ void FOOTPRINT_EDIT_FRAME::Enter_Edge_Width( EDGE_MODULE* aEdge ) { wxString buffer; - buffer = ReturnStringFromValue( g_UserUnit, GetDesignSettings().m_ModuleSegmentWidth ); + buffer = StringFromValue( g_UserUnit, GetDesignSettings().m_ModuleSegmentWidth ); wxTextEntryDialog dlg( this, _( "New Width:" ), _( "Edge Width" ), buffer ); if( dlg.ShowModal() != wxID_OK ) return; // canceled by user buffer = dlg.GetValue( ); - GetDesignSettings().m_ModuleSegmentWidth = ReturnValueFromString( g_UserUnit, buffer ); + GetDesignSettings().m_ModuleSegmentWidth = ValueFromString( g_UserUnit, buffer ); if( aEdge ) { diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index 7b3ddc2846..ecfaedbf97 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -30,7 +30,8 @@ */ #include -#include +#include +#include #include #include #include @@ -189,36 +190,38 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_OPEN_MODULE_EDITOR: { - FOOTPRINT_EDIT_FRAME* editorFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); + FOOTPRINT_EDIT_FRAME* editor = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( this ); - if( editorFrame == NULL ) + if( !editor ) { - editorFrame = new FOOTPRINT_EDIT_FRAME( this, m_footprintLibTable ); - editorFrame->Show( true ); - editorFrame->Zoom_Automatique( false ); + editor = (FOOTPRINT_EDIT_FRAME*) Kiface().CreateWindow( this, MODULE_EDITOR_FRAME_TYPE, &Kiway() ); + + editor->Show( true ); + editor->Zoom_Automatique( false ); } else { - if( editorFrame->IsIconized() ) - editorFrame->Iconize( false ); + if( editor->IsIconized() ) + editor->Iconize( false ); - editorFrame->Raise(); + editor->Raise(); // Raising the window does not set the focus on Linux. This should work on // any platform. - if( wxWindow::FindFocus() != editorFrame ) - editorFrame->SetFocus(); + if( wxWindow::FindFocus() != editor ) + editor->SetFocus(); } } break; case ID_OPEN_MODULE_VIEWER: { - FOOTPRINT_VIEWER_FRAME * viewer = - FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer(); - if( viewer == NULL ) + FOOTPRINT_VIEWER_FRAME* viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer( this ); + + if( !viewer ) { - viewer = new FOOTPRINT_VIEWER_FRAME( this, m_footprintLibTable, NULL ); + viewer = (FOOTPRINT_VIEWER_FRAME*) Kiface().CreateWindow( this, MODULE_VIEWER_FRAME_TYPE, &Kiway() ); + viewer->Show( true ); viewer->Zoom_Automatique( false ); } @@ -832,16 +835,18 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) } { - FOOTPRINT_EDIT_FRAME* editorFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); + FOOTPRINT_EDIT_FRAME* editor = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( this ); - if( editorFrame == NULL ) - editorFrame = new FOOTPRINT_EDIT_FRAME( this, m_footprintLibTable ); + if( !editor ) + { + editor = (FOOTPRINT_EDIT_FRAME*) Kiface().CreateWindow( this, MODULE_EDITOR_FRAME_TYPE, &Kiway() ); + } - editorFrame->Load_Module_From_BOARD( (MODULE*)GetCurItem() ); + editor->Load_Module_From_BOARD( (MODULE*)GetCurItem() ); SetCurItem( NULL ); // the current module could be deleted by - editorFrame->Show( true ); - editorFrame->Iconize( false ); + editor->Show( true ); + editor->Iconize( false ); } m_canvas->MoveCursorToCrossHair(); break; @@ -1168,9 +1173,9 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_POPUP_PCB_DISPLAY_FOOTPRINT_DOC: { - wxConfig* cfg = wxGetApp().GetCommonSettings(); + wxConfigBase* cfg = Pgm().CommonSettings(); cfg->Read( wxT( "module_doc_file" ), g_DocModulesFileName ); - GetAssociatedDocument( this, g_DocModulesFileName, &wxGetApp().GetLibraryPathList() ); + GetAssociatedDocument( this, g_DocModulesFileName, &Kiface().KifaceSearch() ); } break; diff --git a/pcbnew/editmod.cpp b/pcbnew/editmod.cpp index 1f217d6194..7eed255d4c 100644 --- a/pcbnew/editmod.cpp +++ b/pcbnew/editmod.cpp @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -67,22 +68,24 @@ void PCB_EDIT_FRAME::InstallModuleOptionsFrame( MODULE* Module, wxDC* DC ) #ifdef __WXMAC__ // If something edited, push a refresh request - if (retvalue == 0 || retvalue == 1) + if( retvalue == 0 || retvalue == 1 ) m_canvas->Refresh(); #endif if( retvalue == 2 ) { - FOOTPRINT_EDIT_FRAME* editorFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); + FOOTPRINT_EDIT_FRAME* editor = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( this ); - if( editorFrame == NULL ) - editorFrame = new FOOTPRINT_EDIT_FRAME( this, m_footprintLibTable ); + if( !editor ) + { + editor = (FOOTPRINT_EDIT_FRAME*) Kiface().CreateWindow( this, MODULE_EDITOR_FRAME_TYPE, &Kiway() ); + } - editorFrame->Load_Module_From_BOARD( Module ); + editor->Load_Module_From_BOARD( Module ); SetCurItem( NULL ); - editorFrame->Show( true ); - editorFrame->Iconize( false ); + editor->Show( true ); + editor->Iconize( false ); } } diff --git a/pcbnew/exporters/export_d356.cpp b/pcbnew/exporters/export_d356.cpp index e8ef8f3fbf..24e7c576a7 100644 --- a/pcbnew/exporters/export_d356.cpp +++ b/pcbnew/exporters/export_d356.cpp @@ -27,22 +27,22 @@ * @brief Export IPC-D-356 test format */ -#include "fctsys.h" -#include "class_drawpanel.h" -#include "confirm.h" -#include "gestfich.h" -#include "appl_wxstruct.h" -#include "wxPcbStruct.h" -#include "trigo.h" -#include "build_version.h" -#include "macros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "pcbnew.h" +#include -#include "class_board.h" -#include "class_module.h" -#include "class_track.h" -#include "class_edge_mod.h" +#include +#include +#include +#include #include #include @@ -131,7 +131,7 @@ static void build_pad_testpoints( BOARD *aPcb, { rk.netname = pad->GetNetname(); rk.refdes = module->GetReference(); - pad->ReturnStringPadName( rk.pin ); + pad->StringPadName( rk.pin ); rk.midpoint = false; // XXX MAYBE need to be computed (how?) const wxSize& drill = pad->GetDrillSize(); rk.drill = std::min( drill.x, drill.y ); @@ -214,7 +214,7 @@ static void build_via_testpoints( BOARD *aPcb, rk.drill = via->GetDrillValue(); rk.mechanical = false; LAYER_NUM top_layer, bottom_layer; - via->ReturnLayerPair( &top_layer, &bottom_layer ); + via->LayerPair( &top_layer, &bottom_layer ); rk.access = via_access_code( aPcb, top_layer, bottom_layer ); rk.x_location = via->GetPosition().x - origin.x; rk.y_location = origin.y - via->GetPosition().y; diff --git a/pcbnew/exporters/export_gencad.cpp b/pcbnew/exporters/export_gencad.cpp index f04496ff7c..192fc0ca8b 100644 --- a/pcbnew/exporters/export_gencad.cpp +++ b/pcbnew/exporters/export_gencad.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -525,7 +525,7 @@ static void CreateShapesSection( FILE* aFile, BOARD* aPcb ) layer = ( module->GetFlag() ) ? "BOTTOM" : "TOP"; } - pad->ReturnStringPadName( pinname ); + pad->StringPadName( pinname ); if( pinname.IsEmpty() ) pinname = wxT( "none" ); @@ -667,7 +667,7 @@ static void CreateSignalsSection( FILE* aFile, BOARD* aPcb ) if( pad->GetNet() != net->GetNet() ) continue; - pad->ReturnStringPadName( padname ); + pad->StringPadName( padname ); msg.Printf( wxT( "NODE %s %s" ), GetChars( module->GetReference() ), GetChars( padname ) ); @@ -693,7 +693,7 @@ static bool CreateHeaderInfoData( FILE* aFile, PCB_EDIT_FRAME* aFrame ) // Please note: GenCAD syntax requires quoted strings if they can contain spaces msg.Printf( wxT( "USER \"%s %s\"\n" ), - GetChars( wxGetApp().GetAppName() ), + GetChars( Pgm().App().GetAppName() ), GetChars( GetBuildVersion() ) ); fputs( TO_UTF8( msg ), aFile ); diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp index 9002657d19..54b64d44a0 100644 --- a/pcbnew/exporters/export_vrml.cpp +++ b/pcbnew/exporters/export_vrml.cpp @@ -66,7 +66,7 @@ #include #include #include -#include +#include #include <3d_struct.h> #include @@ -811,7 +811,7 @@ static void export_vrml_via( MODEL_VRML& aModel, BOARD* pcb, SEGVIA* via ) r = via->GetWidth() * aModel.scale / 2.0; x = via->GetStart().x * aModel.scale + aModel.tx; y = via->GetStart().y * aModel.scale + aModel.ty; - via->ReturnLayerPair( &top_layer, &bottom_layer ); + via->LayerPair( &top_layer, &bottom_layer ); // do not render a buried via if( top_layer != LAST_COPPER_LAYER && bottom_layer != FIRST_COPPER_LAYER ) @@ -955,7 +955,7 @@ static void export_vrml_padshape( MODEL_VRML& aModel, VRML_LAYER* aLayer, VRML_LAYER* aTinLayer, D_PAD* aPad ) { // The (maybe offset) pad position - wxPoint pad_pos = aPad->ReturnShapePos(); + wxPoint pad_pos = aPad->ShapePos(); double pad_x = pad_pos.x * aModel.scale + aModel.tx; double pad_y = pad_pos.y * aModel.scale + aModel.ty; wxSize pad_delta = aPad->GetDelta(); diff --git a/pcbnew/exporters/gen_modules_placefile.cpp b/pcbnew/exporters/gen_modules_placefile.cpp index 609b6adebf..b572338064 100644 --- a/pcbnew/exporters/gen_modules_placefile.cpp +++ b/pcbnew/exporters/gen_modules_placefile.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include @@ -462,7 +462,7 @@ int PCB_EDIT_FRAME::DoGenFootprintsPositionFile( const wxString& aFullFileName, sprintf( line, "### Module positions - created on %s ###\n", TO_UTF8( DateAndTime() ) ); fputs( line, file ); - wxString Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion(); + wxString Title = Pgm().App().GetAppName() + wxT( " " ) + GetBuildVersion(); sprintf( line, "### Printed by Pcbnew version %s\n", TO_UTF8( Title ) ); fputs( line, file ); @@ -582,7 +582,7 @@ bool PCB_EDIT_FRAME::DoGenFootprintsReport( const wxString& aFullFilename, bool sprintf( line, "## Module report - date %s\n", TO_UTF8( DateAndTime() ) ); fputs( line, rptfile ); - wxString Title = wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion(); + wxString Title = Pgm().App().GetAppName() + wxT( " " ) + GetBuildVersion(); sprintf( line, "## Created by Pcbnew version %s\n", TO_UTF8( Title ) ); fputs( line, rptfile ); fputs( unit_text, rptfile ); diff --git a/pcbnew/exporters/gendrill_Excellon_writer.cpp b/pcbnew/exporters/gendrill_Excellon_writer.cpp index 7ad2293b95..265ff406ca 100644 --- a/pcbnew/exporters/gendrill_Excellon_writer.cpp +++ b/pcbnew/exporters/gendrill_Excellon_writer.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include @@ -351,7 +351,8 @@ void EXCELLON_WRITER::WriteEXCELLONHeader() if( !m_minimalHeader ) { // The next 2 lines in EXCELLON files are comments: - wxString msg = wxGetApp().GetTitle() + wxT( " " ) + GetBuildVersion(); + wxString msg = Pgm().App().GetAppName() + wxT( " " ) + GetBuildVersion(); + fprintf( m_file, ";DRILL file {%s} date %s\n", TO_UTF8( msg ), TO_UTF8( DateAndTime() ) ); msg = wxT( ";FORMAT={" ); @@ -482,9 +483,9 @@ void EXCELLON_WRITER::BuildHolesList( int aFirstLayer, new_hole.m_Hole_Shape = 0; // hole shape: round new_hole.m_Hole_Pos = via->GetStart(); - via->ReturnLayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer ); + via->LayerPair( &new_hole.m_Hole_Top_Layer, &new_hole.m_Hole_Bottom_Layer ); - // ReturnLayerPair return params with m_Hole_Bottom_Layer < m_Hole_Top_Layer + // LayerPair return params with m_Hole_Bottom_Layer < m_Hole_Top_Layer if( (new_hole.m_Hole_Bottom_Layer > aFirstLayer) && (aFirstLayer >= 0) ) continue; diff --git a/pcbnew/exporters/idf.cpp b/pcbnew/exporters/idf.cpp index 510c0100db..8c848817c9 100644 --- a/pcbnew/exporters/idf.cpp +++ b/pcbnew/exporters/idf.cpp @@ -39,7 +39,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 77dfeea698..c62010d22c 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -39,7 +39,7 @@ #include <3d_viewer.h> #include #include -#include +#include #include #include @@ -58,20 +58,29 @@ #define USE_INSTRUMENTATION false -static const wxString backupFileExtensionSuffix( wxT( "-bak" ) ); -static const wxString autosaveFilePrefix( wxT( "_autosave-" ) ); +static const wxChar backupSuffix[] = wxT( "-bak" ); +static const wxChar autosavePrefix[]= wxT( "_autosave-" ); + void PCB_EDIT_FRAME::OnFileHistory( wxCommandEvent& event ) { - wxString fn; + wxString fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) ); - fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) ); - - if( fn != wxEmptyString ) + if( !!fn ) { + int open_ctl = 0; + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); ::wxSetWorkingDirectory( ::wxPathOnly( fn ) ); - LoadOnePcbFile( fn ); + + // LoadOnePcbFile( fn, bool aAppend = false, bool aForceFileDialog = false ); + if( !wxFileName::IsFileReadable( fn ) ) + { + if( !AskBoardFileName( this, &open_ctl, &fn ) ) + return; + } + + OpenProjectFiles( std::vector( 1, fn ), open_ctl ); } } @@ -91,7 +100,17 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) switch( id ) { case ID_LOAD_FILE: - LoadOnePcbFile( GetBoard()->GetFileName(), false, true ); + { + // LoadOnePcbFile( GetBoard()->GetFileName(), append=false, aForceFileDialog=true ); + + int open_ctl; + wxString fileName = GetBoard()->GetFileName(); + + if( !AskBoardFileName( this, &open_ctl, &fileName ) ) + return; + + OpenProjectFiles( std::vector( 1, fileName ), open_ctl ); + } break; case ID_MENU_READ_BOARD_BACKUP_FILE: @@ -99,33 +118,36 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) { wxFileName currfn = GetBoard()->GetFileName(); wxFileName fn = currfn; + if( id == ID_MENU_RECOVER_BOARD_AUTOSAVE ) { - wxString rec_name = autosaveFilePrefix + fn.GetName(); + wxString rec_name = wxString( autosavePrefix ) + fn.GetName(); fn.SetName( rec_name ); } else { - wxString backup_ext = fn.GetExt()+ backupFileExtensionSuffix; + wxString backup_ext = fn.GetExt()+ backupSuffix; fn.SetExt( backup_ext ); } if( !fn.FileExists() ) { - msg.Printf( _( "Recovery file <%s> not found." ), + msg.Printf( _( "Recovery file '%s' not found." ), GetChars( fn.GetFullPath() ) ); DisplayInfoMessage( this, msg ); break; } - msg.Printf( _( "OK to load recovery or backup file <%s>" ), + msg.Printf( _( "OK to load recovery or backup file '%s'" ), GetChars(fn.GetFullPath() ) ); if( !IsOK( this, msg ) ) break; GetScreen()->ClrModify(); // do not prompt the user for changes - LoadOnePcbFile( fn.GetFullPath(), false ); + + // LoadOnePcbFile( fn.GetFullPath(), aAppend=false, aForceFileDialog=false ); + OpenProjectFiles( std::vector( 1, fn.GetFullPath() ) ); // Re-set the name since name or extension was changed GetBoard()->SetFileName( currfn.GetFullPath() ); @@ -134,34 +156,34 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) break; case ID_APPEND_FILE: - LoadOnePcbFile( wxEmptyString, true ); + { + // LoadOnePcbFile( wxEmptyString, aAppend = true, aForceFileDialog=false ); + int open_ctl; + wxString fileName; + + if( !AskBoardFileName( this, &open_ctl, &fileName ) ) + break; + + OpenProjectFiles( std::vector( 1, fileName ), open_ctl | KICTL_OPEN_APPEND ); + } break; case ID_NEW_BOARD: { Clear_Pcb( true ); - // Create a new empty footprint library table for the new board. - delete m_footprintLibTable; - m_footprintLibTable = new FP_LIB_TABLE( m_globalFootprintTable ); - - FOOTPRINT_EDIT_FRAME* editFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); - - if( editFrame ) - editFrame->SetFootprintLibTable( m_footprintLibTable ); - - FOOTPRINT_VIEWER_FRAME* viewFrame = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer(); - - if( viewFrame ) - viewFrame->SetFootprintLibTable( m_footprintLibTable ); - - wxFileName emptyFileName; - FP_LIB_TABLE::SetProjectPathEnvVariable( emptyFileName ); + // Clear footprint library table for the new board. + FootprintLibs()->Clear(); wxFileName fn; + fn.AssignCwd(); fn.SetName( wxT( "noname" ) ); + + Prj().SetProjectFullName( fn.GetFullPath() ); + fn.SetExt( PcbFileExtension ); + GetBoard()->SetFileName( fn.GetFullPath() ); UpdateTitle(); ReCreateLayerBox(); @@ -182,33 +204,8 @@ void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event ) } -bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, - bool aForceFileDialog ) +bool AskBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName ) { - if( GetScreen()->IsModify() && !aAppend ) - { - int response = YesNoCancelDialog( this, _( "The current board has been modified. Do " - "you wish to save the changes?" ), - wxEmptyString, - _( "Save and Load" ), _( "Load Without Saving" ) ); - - if( response == wxID_CANCEL ) - return false; - else if( response == wxID_YES ) - SavePcbFile( GetBoard()->GetFileName(), true ); - } - - if( aAppend ) - { - GetBoard()->SetFileName( wxEmptyString ); - OnModify(); - GetBoard()->m_Status_Pcb = 0; - } - - wxFileName fileName = aFileName; - - IO_MGR::PCB_FILE_T pluginType = IO_MGR::LEGACY; - // This is a subset of all PLUGINs which are trusted to be able to // load a BOARD. Order is subject to change as KICAD plugin matures. // User may occasionally use the wrong plugin to load a *.brd file, @@ -226,56 +223,114 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, { PCadPcbFileWildcard, IO_MGR::PCAD }, }; - if( !fileName.IsOk() || !fileName.FileExists() || aForceFileDialog ) + wxFileName fileName( *aFileName ); + wxString fileFilters; + + for( unsigned i=0; i 0 ) + fileFilters += wxChar( '|' ); - for( unsigned i=0; i 0 ) - fileFilters += wxChar( '|' ); + fileFilters += wxGetTranslation( loaders[i].filter ); + } - fileFilters += wxGetTranslation( loaders[i].filter ); - } + wxString path; + wxString name; - if( aForceFileDialog && fileName.FileExists() ) - { - path = fileName.GetPath(); - name = fileName.GetFullName(); - } + if( fileName.FileExists() ) + { + path = fileName.GetPath(); + name = fileName.GetFullName(); + } + else + { + path = wxGetCwd(); + // leave name empty + } - wxFileDialog dlg( this, _( "Open Board File" ), path, name, fileFilters, - wxFD_OPEN | wxFD_FILE_MUST_EXIST ); - - if( dlg.ShowModal() == wxID_CANCEL ) - return false; - - fileName = dlg.GetPath(); + wxFileDialog dlg( aParent, _( "Open Board File" ), path, name, fileFilters, + wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + if( dlg.ShowModal() != wxID_CANCEL ) + { int chosenFilter = dlg.GetFilterIndex(); - pluginType = loaders[chosenFilter].pluginType; + + // if Eagle, tell OpenProjectFiles() to use Eagle plugin. It's the only special + // case because of the duplicate use of the *.brd file extension. Other cases + // are clear because of unique file extensions. + *aCtl = chosenFilter == 2 ? KICTL_EAGLE_BRD : 0; + *aFileName = dlg.GetPath(); + + return true; } - else // if a filename is given, force IO_MGR::KICAD if the file ext is kicad_pcb - // for instance if the filename comes from file history - // or it is a backup file with ext = kicad_pcb-bak + else + return false; +} + + +bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, int aCtl ) +{ + wxASSERT( aFileSet.size() == 1 ); + + bool doAppend = aCtl & KICTL_OPEN_APPEND; + wxFileName fileName( aFileSet[0] ); + + // Make filename absolute, to avoid issues when the filename is relative, + // for instance when stored in history list without path, and when building + // the config filename ( which should have a path ) + if( fileName.IsRelative() ) + fileName.MakeAbsolute(); + + if( GetScreen()->IsModify() && !doAppend ) { - wxString backup_ext = IO_MGR::GetFileExtension( IO_MGR::KICAD ) + - backupFileExtensionSuffix; - if( fileName.GetExt() == IO_MGR::GetFileExtension( IO_MGR::KICAD ) || - fileName.GetExt() == backup_ext ) - pluginType = IO_MGR::KICAD; + int response = YesNoCancelDialog( this, _( + "The current board has been modified. Do " + "you wish to save the changes?" ), + wxEmptyString, + _( "Save and Load" ), + _( "Load Without Saving" ) + ); + + if( response == wxID_CANCEL ) + return false; + else if( response == wxID_YES ) + SavePcbFile( GetBoard()->GetFileName(), true ); } + if( doAppend ) + { + GetBoard()->SetFileName( wxEmptyString ); + OnModify(); + GetBoard()->m_Status_Pcb = 0; + } + + // The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so + // determine how to load the BOARD here, with minor assistance from KICTL_EAGLE_BRD + // bit flag. + + IO_MGR::PCB_FILE_T pluginType; + + if( fileName.GetExt() == IO_MGR::GetFileExtension( IO_MGR::LEGACY ) ) + { + // both legacy and eagle share a common file extension. + pluginType = ( aCtl & KICTL_EAGLE_BRD ) ? IO_MGR::EAGLE : IO_MGR::LEGACY; + } + else if( fileName.GetExt() == IO_MGR::GetFileExtension( IO_MGR::LEGACY ) + backupSuffix ) + { + pluginType = IO_MGR::LEGACY; + } + else if( fileName.GetExt() == IO_MGR::GetFileExtension( IO_MGR::IO_MGR::PCAD ) ) + { + pluginType = IO_MGR::PCAD; + } + else + pluginType = IO_MGR::KICAD; + PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); - if( !fileName.HasExt() ) - fileName.SetExt( pi->GetFileExtension() ); - - if( !aAppend ) + if( !doAppend ) { - if( !wxGetApp().LockFile( fileName.GetFullPath() ) ) + if( !Pgm().LockFile( fileName.GetFullPath() ) ) { DisplayError( this, _( "This file is already open." ) ); return false; @@ -287,7 +342,7 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, GetBoard()->SetFileName( fileName.GetFullPath() ); - if( !aAppend ) + if( !doAppend ) { // Update the option toolbar m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill; @@ -325,7 +380,7 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, #endif // load or append either: - loadedBoard = pi->Load( GetBoard()->GetFileName(), aAppend ? GetBoard() : NULL, &props ); + loadedBoard = pi->Load( GetBoard()->GetFileName(), doAppend ? GetBoard() : NULL, &props ); #if USE_INSTRUMENTATION unsigned stopTime = GetRunningMicroSecs(); @@ -336,7 +391,7 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, // set its own name GetBoard()->SetFileName( fileName.GetFullPath() ); - if( !aAppend ) + if( !doAppend ) { if( pluginType == IO_MGR::LEGACY && loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION ) @@ -364,16 +419,19 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, SetStatusText( wxEmptyString ); BestZoom(); + + // update the layer names in the listbox + ReCreateLayerBox( false ); } GetScreen()->ClrModify(); - // If append option: change the initial board name to -append.brd - if( aAppend ) + if( doAppend ) { + // change the initial board name to -append.brd wxString new_filename = GetBoard()->GetFileName().BeforeLast( '.' ); - if ( ! new_filename.EndsWith( wxT( "-append" ) ) ) + if( !new_filename.EndsWith( wxT( "-append" ) ) ) new_filename += wxT( "-append" ); new_filename += wxT( "." ) + PcbFileExtension; @@ -448,8 +506,11 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, Zoom_Automatique( false ); // Compile ratsnest and displays net info - wxBusyCursor dummy; // Displays an Hourglass while building connectivity - Compile_Ratsnest( NULL, true ); + { + wxBusyCursor dummy; // Displays an Hourglass while building connectivity + Compile_Ratsnest( NULL, true ); + } + SetMsgPanel( GetBoard() ); // Refresh the 3D view, if any @@ -457,16 +518,24 @@ bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend, m_Draw3DFrame->NewDisplay(); #if 0 && defined(DEBUG) - // note this freezes up Pcbnew when run under the KiCad project - // manager. runs fine from command prompt. This is because the KiCad - // project manager redirects stdout of the child Pcbnew process to itself, - // but never reads from that pipe, and that in turn eventually blocks - // the Pcbnew program when the pipe it is writing to gets full. - // Output the board object tree to stdout, but please run from command prompt: GetBoard()->Show( 0, std::cout ); #endif + // from EDA_APPL which was first loaded BOARD only: + { + /* For an obscure reason the focus is lost after loading a board file + * when starting up the process. + * (seems due to the recreation of the layer manager after loading the file) + * Give focus to main window and Drawpanel + * must be done for these 2 windows (for an obscure reason ...) + * Linux specific + * This is more a workaround than a fix. + */ + SetFocus(); + GetCanvas()->SetFocus(); + } + return true; } @@ -528,13 +597,13 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF // when multiple wildcards are defined, we have to check it ourselves to prevent an // existing board file from silently being over written. if( pcbFileName.FileExists() - && !IsOK( this, wxString::Format( _( "The file <%s> already exists.\n\nDo you want " + && !IsOK( this, wxString::Format( _( "The file '%s' already exists.\n\nDo you want " "to overwrite it?" ), GetChars( pcbFileName.GetFullPath() ) )) ) return false; // Save the project specific footprint library table. - if( !m_footprintLibTable->IsEmpty( false ) ) + if( !FootprintLibs()->IsEmpty( false ) ) { wxFileName fn = pcbFileName; fn.ClearExt(); @@ -546,13 +615,13 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF { try { - m_footprintLibTable->Save( fn ); + FootprintLibs()->Save( fn ); } catch( IO_ERROR& ioe ) { DisplayError( this, wxString::Format( _( "An error occurred attempting to save the " - "footprint library table <%s>\n\n%s" ), + "footprint library table '%s'\n\n%s" ), GetChars( fn.GetFullPath() ), GetChars( ioe.errorText ) ) ); } @@ -579,7 +648,7 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF { // Get the backup file name backupFileName = pcbFileName; - backupFileName.SetExt( pcbFileName.GetExt() + backupFileExtensionSuffix ); + backupFileName.SetExt( pcbFileName.GetExt() + backupSuffix ); // If an old backup file exists, delete it. If an old board file exists, rename // it to the backup file name. @@ -656,7 +725,8 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF { // Delete auto save file on successful save. wxFileName autoSaveFileName = pcbFileName; - autoSaveFileName.SetName( autosaveFilePrefix + pcbFileName.GetName() ); + + autoSaveFileName.SetName( wxString( autosavePrefix ) + pcbFileName.GetName() ); if( autoSaveFileName.FileExists() ) wxRemoveFile( autoSaveFileName.GetFullPath() ); @@ -687,7 +757,7 @@ bool PCB_EDIT_FRAME::doAutoSave() // Auto save file name is the normal file name prepended with // autosaveFilePrefix string. - fn.SetName( autosaveFilePrefix + fn.GetName() ); + fn.SetName( wxString( autosavePrefix ) + fn.GetName() ); wxLogTrace( traceAutoSave, wxT( "Creating auto save file <" + fn.GetFullPath() ) + wxT( ">" ) ); diff --git a/pcbnew/footprint_wizard_frame.cpp b/pcbnew/footprint_wizard_frame.cpp index 23ee998473..a5d5a5a325 100644 --- a/pcbnew/footprint_wizard_frame.cpp +++ b/pcbnew/footprint_wizard_frame.cpp @@ -29,7 +29,7 @@ */ #include -#include +#include #include #include #include <3d_viewer.h> @@ -119,9 +119,9 @@ static wxAcceleratorEntry accels[] = #define FOOTPRINT_WIZARD_FRAME_NAME wxT( "FootprintWizard" ) -FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( FOOTPRINT_EDIT_FRAME* parent, - wxSemaphore* semaphore, long style ) : - PCB_BASE_FRAME( parent, FOOTPRINT_WIZARD_FRAME_TYPE, +FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( KIWAY* aKiway, FOOTPRINT_EDIT_FRAME* aParent, + wxSemaphore* semaphore, long style ) : + PCB_BASE_FRAME( aKiway, aParent, FOOTPRINT_WIZARD_FRAME_TYPE, _( "Footprint Wizard" ), wxDefaultPosition, wxDefaultSize, style, FOOTPRINT_WIZARD_FRAME_NAME ) { @@ -150,7 +150,7 @@ FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( FOOTPRINT_EDIT_FRAME* parent, SetScreen( new PCB_SCREEN( GetPageSizeIU() ) ); GetScreen()->m_Center = true; // Center coordinate origins on screen. - LoadSettings(); + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId ); @@ -429,18 +429,14 @@ void FOOTPRINT_WIZARD_FRAME::ClickOnPageList( wxCommandEvent& event ) #define PARAMLIST_WIDTH_KEY wxT( "Paramlist_width" ) -void FOOTPRINT_WIZARD_FRAME::LoadSettings() +void FOOTPRINT_WIZARD_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* cfg; + EDA_DRAW_FRAME::LoadSettings( aCfg ); - EDA_DRAW_FRAME::LoadSettings(); + wxConfigPathChanger cpc( aCfg, m_configPath ); - wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - - cfg = wxGetApp().GetSettings(); - - cfg->Read( PARTLIST_WIDTH_KEY, &m_pageListWidth, 100 ); - cfg->Read( PARAMLIST_WIDTH_KEY, &m_parameterGridWidth, 200 ); + aCfg->Read( PARTLIST_WIDTH_KEY, &m_pageListWidth, 100 ); + aCfg->Read( PARAMLIST_WIDTH_KEY, &m_parameterGridWidth, 200 ); // Set parameters to a reasonable value. if( m_pageListWidth > m_FrameSize.x / 3 ) @@ -451,15 +447,13 @@ void FOOTPRINT_WIZARD_FRAME::LoadSettings() } -void FOOTPRINT_WIZARD_FRAME::SaveSettings() +void FOOTPRINT_WIZARD_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* cfg = wxGetApp().GetSettings();; + EDA_DRAW_FRAME::SaveSettings( aCfg ); - EDA_DRAW_FRAME::SaveSettings(); - - wxConfigPathChanger cpc( cfg, m_configPath ); - cfg->Write( PARTLIST_WIDTH_KEY, m_pageList->GetSize().x ); - cfg->Write( PARAMLIST_WIDTH_KEY, m_parameterGrid->GetSize().x ); + wxConfigPathChanger cpc( aCfg, m_configPath ); + aCfg->Write( PARTLIST_WIDTH_KEY, m_pageList->GetSize().x ); + aCfg->Write( PARAMLIST_WIDTH_KEY, m_parameterGrid->GetSize().x ); } @@ -591,7 +585,7 @@ void FOOTPRINT_WIZARD_FRAME::Show3D_Frame( wxCommandEvent& event ) return; } - m_Draw3DFrame = new EDA_3D_FRAME( this, wxEmptyString ); + m_Draw3DFrame = new EDA_3D_FRAME( &Kiway(), this, wxEmptyString ); Update3D_Frame( false ); m_Draw3DFrame->Show( true ); } diff --git a/pcbnew/footprint_wizard_frame.h b/pcbnew/footprint_wizard_frame.h index 653545d698..c44331a88c 100644 --- a/pcbnew/footprint_wizard_frame.h +++ b/pcbnew/footprint_wizard_frame.h @@ -63,9 +63,9 @@ protected: wxString m_wizardStatus; // < current wizard status public: - FOOTPRINT_WIZARD_FRAME( FOOTPRINT_EDIT_FRAME* parent, - wxSemaphore* semaphore = NULL, - long style = KICAD_DEFAULT_DRAWFRAME_STYLE ); + FOOTPRINT_WIZARD_FRAME( KIWAY* aKiway, + FOOTPRINT_EDIT_FRAME* parent, wxSemaphore* semaphore = NULL, + long style = KICAD_DEFAULT_DRAWFRAME_STYLE ); ~FOOTPRINT_WIZARD_FRAME(); @@ -140,23 +140,8 @@ private: void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); - /** - * Function LoadSettings - * loads the library viewer frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get loaded. - */ - void LoadSettings(); - - /** - * Function SaveSettings - * save library viewer frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get saved. - */ - void SaveSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual + void SaveSettings( wxConfigBase* aCfg ); // override virtual /** diff --git a/pcbnew/import_dxf/dialog_dxf_import.cpp b/pcbnew/import_dxf/dialog_dxf_import.cpp index d3fe5e4d97..aaeeba403a 100644 --- a/pcbnew/import_dxf/dialog_dxf_import.cpp +++ b/pcbnew/import_dxf/dialog_dxf_import.cpp @@ -27,7 +27,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +//#include +#include #include #include #include @@ -44,7 +45,7 @@ class DIALOG_DXF_IMPORT : public DIALOG_DXF_IMPORT_BASE { private: PCB_EDIT_FRAME * m_parent; - wxConfig* m_config; // Current config + wxConfigBase* m_config; // Current config static wxString m_dxfFilename; static int m_offsetSelection; @@ -59,7 +60,7 @@ private: // Virtual event handlers void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } void OnOKClick( wxCommandEvent& event ); - void OnBrowseDxfFiles( wxCommandEvent& event ); + void OnBrowseDxfFiles( wxCommandEvent& event ); }; // Static members of DIALOG_DXF_IMPORT, to remember @@ -73,7 +74,7 @@ DIALOG_DXF_IMPORT::DIALOG_DXF_IMPORT( PCB_EDIT_FRAME* aParent ) : DIALOG_DXF_IMPORT_BASE( aParent ) { m_parent = aParent; - m_config = wxGetApp().GetSettings(); + m_config = Kiface().KifaceSettings(); if( m_config ) { diff --git a/pcbnew/initpcb.cpp b/pcbnew/initpcb.cpp index 8b3b398995..80f6fc8135 100644 --- a/pcbnew/initpcb.cpp +++ b/pcbnew/initpcb.cpp @@ -16,11 +16,6 @@ #include -/** - * Function Clear_Pcb - * delete all and reinitialize the current board - * @param aQuery = true to prompt user for confirmation, false to initialize silently - */ bool PCB_EDIT_FRAME::Clear_Pcb( bool aQuery ) { if( GetBoard() == NULL ) @@ -40,11 +35,11 @@ bool PCB_EDIT_FRAME::Clear_Pcb( bool aQuery ) // Clear undo and redo lists because we want a full deletion GetScreen()->ClearUndoRedoList(); - /* Items visibility flags will be set becuse a new board will be created. - * Grid and ratsnest can be left to their previous state - */ + // Items visibility flags will be set becuse a new board will be created. + // Grid and ratsnest can be left to their previous state bool showGrid = IsElementVisible( GRID_VISIBLE ); bool showRats = IsElementVisible( RATSNEST_VISIBLE ); + // delete the old BOARD and create a new BOARD so that the default // layer names are put into the BOARD. SetBoard( new BOARD() ); @@ -84,7 +79,6 @@ bool PCB_EDIT_FRAME::Clear_Pcb( bool aQuery ) } - bool FOOTPRINT_EDIT_FRAME::Clear_Pcb( bool aQuery ) { if( GetBoard() == NULL ) diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 99211a7e4d..aca016677e 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -1340,14 +1340,14 @@ void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const LAYER_NUM layer1, layer2; SEGVIA* via = (SEGVIA*) aTrack; - BOARD* board = (BOARD*) via->GetParent(); + BOARD* board = (BOARD*) via->GetParent(); wxCHECK_RET( board != 0, wxT( "Via " ) + via->GetSelectMenuText() + wxT( " has no parent." ) ); m_out->Print( aNestLevel, "(via" ); - via->ReturnLayerPair( &layer1, &layer2 ); + via->LayerPair( &layer1, &layer2 ); switch( aTrack->GetShape() ) { diff --git a/pcbnew/librairi.cpp b/pcbnew/librairi.cpp index 7fd65174f3..1b65c89b97 100644 --- a/pcbnew/librairi.cpp +++ b/pcbnew/librairi.cpp @@ -29,7 +29,8 @@ #include #include -#include +#include +#include #include #include #include @@ -96,8 +97,9 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module() // Some day it might be useful save the last library type selected along with the path. static int lastFilterIndex = 0; - wxString lastOpenedPathForLoading; - wxConfig* config = wxGetApp().GetSettings(); + + wxString lastOpenedPathForLoading; + wxConfigBase* config = Kiface().KifaceSettings(); if( config ) config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading ); @@ -279,10 +281,10 @@ MODULE* FOOTPRINT_EDIT_FRAME::Import_Module() void FOOTPRINT_EDIT_FRAME::Export_Module( MODULE* aModule ) { - wxFileName fn; - wxConfig* config = wxGetApp().GetSettings(); + wxFileName fn; + wxConfigBase* config = Kiface().KifaceSettings(); - if( aModule == NULL ) + if( !aModule ) return; fn.SetName( aModule->GetFPID().GetFootprintName() ); @@ -366,8 +368,8 @@ bool FOOTPRINT_EDIT_FRAME::SaveCurrentModule( const wxString* aLibPath ) wxString FOOTPRINT_EDIT_FRAME::CreateNewLibrary() { - wxFileName fn; - wxConfig* config = wxGetApp().GetSettings(); + wxFileName fn; + wxConfigBase* config = Kiface().KifaceSettings(); if( config ) { @@ -467,7 +469,7 @@ bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary() { wxString nickname = getLibNickName(); - if( !m_footprintLibTable->IsFootprintLibWritable( nickname ) ) + if( !FootprintLibs()->IsFootprintLibWritable( nickname ) ) { wxString msg = wxString::Format( _( "Library '%s' is read only" ), @@ -479,7 +481,7 @@ bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary() } wxString fpid_txt = PCB_BASE_FRAME::SelectFootprint( this, nickname, - wxEmptyString, wxEmptyString, m_footprintLibTable ); + wxEmptyString, wxEmptyString, FootprintLibs() ); if( !fpid_txt ) return false; @@ -495,7 +497,7 @@ bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary() try { - m_footprintLibTable->FootprintDelete( nickname, fpname ); + FootprintLibs()->FootprintDelete( nickname, fpname ); } catch( IO_ERROR ioe ) { @@ -519,14 +521,17 @@ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aNewModulesOnly ) return; } - wxString last_nickname = wxGetApp().ReturnLastVisitedLibraryPath(); + PROJECT& prj = Prj(); + SEARCH_STACK& search = Kiface().KifaceSearch(); + + wxString last_nickname = prj.RPath(PROJECT::PCB_LIB).LastVisitedPath( search ); wxString nickname = SelectLibrary( last_nickname ); if( !nickname ) return; - wxGetApp().SaveLastVisitedLibraryPath( nickname ); + prj.RPath(PROJECT::PCB_LIB).SaveLastVisitedPath( nickname ); if( !aNewModulesOnly ) { @@ -543,19 +548,19 @@ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aNewModulesOnly ) // Delete old library if we're replacing it entirely. if( !aNewModulesOnly ) { - m_footprintLibTable->FootprintLibDelete( nickname ); - m_footprintLibTable->FootprintLibCreate( nickname ); + FootprintLibs()->FootprintLibDelete( nickname ); + FootprintLibs()->FootprintLibCreate( nickname ); for( MODULE* m = GetBoard()->m_Modules; m; m = m->Next() ) { - m_footprintLibTable->FootprintSave( nickname, m, true ); + FootprintLibs()->FootprintSave( nickname, m, true ); } } else { for( MODULE* m = GetBoard()->m_Modules; m; m = m->Next() ) { - m_footprintLibTable->FootprintSave( nickname, m, false ); + FootprintLibs()->FootprintSave( nickname, m, false ); // Check for request to stop backup (ESCAPE key actuated) if( m_canvas->GetAbortRequest() ) @@ -601,7 +606,7 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibrary, { wxString msg = wxString::Format( _("Error:\none of invalid chars '%s' found\nin '%s'" ), - MODULE::ReturnStringLibNameInvalidChars( true ), + MODULE::StringLibNameInvalidChars( true ), GetChars( footprintName ) ); DisplayError( NULL, msg ); @@ -622,7 +627,7 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibrary, try { - MODULE* m = m_footprintLibTable->FootprintLoad( aLibrary, footprintName ); + MODULE* m = FootprintLibs()->FootprintLoad( aLibrary, footprintName ); if( m ) { @@ -648,7 +653,7 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibrary, // this always overwrites any existing footprint, but should yell on its // own if the library or footprint is not writable. - m_footprintLibTable->FootprintSave( aLibrary, aModule ); + FootprintLibs()->FootprintSave( aLibrary, aModule ); } catch( IO_ERROR ioe ) { @@ -733,15 +738,17 @@ wxString PCB_BASE_FRAME::SelectLibrary( const wxString& aNicknameExisting ) headers.Add( _( "Nickname" ) ); headers.Add( _( "Description" ) ); + FP_LIB_TABLE* fptbl = FootprintLibs(); + std::vector< wxArrayString > itemsToDisplay; - std::vector< wxString > nicknames = m_footprintLibTable->GetLogicalLibs(); + std::vector< wxString > nicknames = fptbl->GetLogicalLibs(); for( unsigned i = 0; i < nicknames.size(); i++ ) { wxArrayString item; item.Add( nicknames[i] ); - item.Add( m_footprintLibTable->GetDescription( nicknames[i] ) ); + item.Add( fptbl->GetDescription( nicknames[i] ) ); itemsToDisplay.push_back( item ); } diff --git a/pcbnew/loadcmp.cpp b/pcbnew/loadcmp.cpp index 059d1f66a4..990198953a 100644 --- a/pcbnew/loadcmp.cpp +++ b/pcbnew/loadcmp.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -119,13 +119,12 @@ wxString PCB_BASE_FRAME::SelectFootprintFromLibBrowser() wxSemaphore semaphore( 0, 1 ); // Close the current Lib browser, if opened, and open a new one, in "modal" mode: - FOOTPRINT_VIEWER_FRAME * viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer(); + FOOTPRINT_VIEWER_FRAME* viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer( this ); if( viewer ) viewer->Destroy(); - viewer = new FOOTPRINT_VIEWER_FRAME( this, m_footprintLibTable, &semaphore, - KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT ); + viewer = new FOOTPRINT_VIEWER_FRAME( &Kiway(), this, &semaphore ); // Show the library viewer frame until it is closed while( semaphore.TryWait() == wxSEMA_BUSY ) // Wait for viewer closing event @@ -318,28 +317,29 @@ MODULE* PCB_BASE_FRAME::LoadFootprint( const FPID& aFootprintId ) MODULE* PCB_BASE_FRAME::loadFootprint( const FPID& aFootprintId ) throw( IO_ERROR, PARSE_ERROR ) { - wxCHECK_MSG( m_footprintLibTable != NULL, NULL, - wxT( "Cannot look up FPID in NULL FP_LIB_TABLE." ) ); + FP_LIB_TABLE* fptbl = FootprintLibs(); + + wxCHECK_MSG( fptbl, NULL, wxT( "Cannot look up FPID in NULL FP_LIB_TABLE." ) ); wxString nickname = aFootprintId.GetLibNickname(); wxString fpname = aFootprintId.GetFootprintName(); if( nickname.size() ) { - return m_footprintLibTable->FootprintLoad( nickname, fpname ); + return fptbl->FootprintLoad( nickname, fpname ); } // user did not enter a nickname, just a footprint name, help him out a little: else { - std::vector nicks = m_footprintLibTable->GetLogicalLibs(); + std::vector nicks = fptbl->GetLogicalLibs(); // Search each library going through libraries alphabetically. for( unsigned i = 0; iFootprintLoad( nicks[i], fpname ); + MODULE* ret = fptbl->FootprintLoad( nicks[i], fpname ); if( ret ) return ret; } diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 27dc4e32be..307c895dcd 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -29,7 +29,8 @@ * Pcbnew editor menu bar */ #include -#include +#include +#include #include #include #include @@ -46,6 +47,8 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() wxString text; wxMenuBar* menuBar = GetMenuBar(); + wxFileHistory& fhist = Kiface().GetFileHistory(); + if( ! menuBar ) menuBar = new wxMenuBar(); @@ -79,17 +82,18 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() // Add this menu to list menu managed by m_fileHistory // (the file history will be updated when adding/removing files in history if( openRecentMenu ) - wxGetApp().GetFileHistory().RemoveMenu( openRecentMenu ); + fhist.RemoveMenu( openRecentMenu ); openRecentMenu = new wxMenu(); - wxGetApp().GetFileHistory().UseMenu( openRecentMenu ); - wxGetApp().GetFileHistory().AddFilesToMenu(); + + fhist.UseMenu( openRecentMenu ); + fhist.AddFilesToMenu(); + AddMenuItem( filesMenu, openRecentMenu, -1, _( "Open &Recent" ), _( "Open a recent opened board" ), KiBitmap( open_project_xpm ) ); - // Pcbnew Board AddMenuItem( filesMenu, ID_APPEND_FILE, _( "&Append Board" ), @@ -530,7 +534,7 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() // Language submenu - wxGetApp().AddMenuLanguageList( configmenu ); + Pgm().AddMenuLanguageList( configmenu ); // Hotkey submenu AddHotkeyConfigMenu( configmenu ); diff --git a/pcbnew/modedit.cpp b/pcbnew/modedit.cpp index e4d13c9952..2729504ab1 100644 --- a/pcbnew/modedit.cpp +++ b/pcbnew/modedit.cpp @@ -26,11 +26,11 @@ */ #include -#include +#include #include #include #include -#include +#include #include #include <3d_viewer.h> #include @@ -262,11 +262,16 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_OPEN_MODULE_VIEWER: { - FOOTPRINT_VIEWER_FRAME * viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer(); + // Make a _project specific_ PCB_EDIT_FRAME be the start of the search in + // FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer(); - if( viewer == NULL ) + PCB_EDIT_FRAME* top_project = dynamic_cast( GetParent() ); + wxASSERT( top_project ); // dynamic_cast returns NULL if class mismatch. + + FOOTPRINT_VIEWER_FRAME* viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer( top_project ); + if( !viewer ) { - viewer = new FOOTPRINT_VIEWER_FRAME( this, m_footprintLibTable, NULL ); + viewer = (FOOTPRINT_VIEWER_FRAME*) Kiface().CreateWindow( this, MODULE_VIEWER_FRAME_TYPE, &Kiway() ); viewer->Show( true ); viewer->Zoom_Automatique( false ); } @@ -290,36 +295,38 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_MODEDIT_NEW_MODULE: - { - Clear_Pcb( true ); - GetScreen()->ClearUndoRedoList(); - SetCurItem( NULL ); - SetCrossHairPosition( wxPoint( 0, 0 ) ); - - MODULE* module = Create_1_Module( wxEmptyString ); - - if( module ) // i.e. if create module command not aborted { - // Initialize data relative to nets and netclasses (for a new - // module the defaults are used) - // This is mandatory to handle and draw pads - GetBoard()->BuildListOfNets(); - redraw = true; - module->SetPosition( wxPoint( 0, 0 ) ); + Clear_Pcb( true ); + GetScreen()->ClearUndoRedoList(); + SetCurItem( NULL ); + SetCrossHairPosition( wxPoint( 0, 0 ) ); - if( GetBoard()->m_Modules ) - GetBoard()->m_Modules->ClearFlags(); + MODULE* module = Create_1_Module( wxEmptyString ); - Zoom_Automatique( false ); + if( module ) // i.e. if create module command not aborted + { + // Initialize data relative to nets and netclasses (for a new + // module the defaults are used) + // This is mandatory to handle and draw pads + GetBoard()->BuildListOfNets(); + redraw = true; + module->SetPosition( wxPoint( 0, 0 ) ); + + if( GetBoard()->m_Modules ) + GetBoard()->m_Modules->ClearFlags(); + + Zoom_Automatique( false ); + } } - } break; case ID_MODEDIT_NEW_MODULE_FROM_WIZARD: { wxSemaphore semaphore( 0, 1 ); - FOOTPRINT_WIZARD_FRAME *wizard = new FOOTPRINT_WIZARD_FRAME( this, &semaphore, - KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT ); + + FOOTPRINT_WIZARD_FRAME* wizard = new FOOTPRINT_WIZARD_FRAME( &Kiway(), this, &semaphore, + KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT ); + wizard->Show( true ); wizard->Zoom_Automatique( false ); @@ -492,7 +499,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) Clear_Pcb( true ); SetCrossHairPosition( wxPoint( 0, 0 ) ); - LoadModuleFromLibrary( getLibNickName(), m_footprintLibTable, true ); + LoadModuleFromLibrary( getLibNickName(), FootprintLibs(), true ); redraw = true; if( GetBoard()->m_Modules ) diff --git a/pcbnew/module_editor_frame.h b/pcbnew/module_editor_frame.h index 5cb6ea1166..dbf0bcc8c7 100644 --- a/pcbnew/module_editor_frame.h +++ b/pcbnew/module_editor_frame.h @@ -35,11 +35,14 @@ class FP_LIB_TABLE; +namespace PCB { struct IFACE; } // A KIFACE_I coded in pcbnew.c + class FOOTPRINT_EDIT_FRAME : public PCB_BASE_FRAME { + friend struct PCB::IFACE; + public: - FOOTPRINT_EDIT_FRAME( PCB_EDIT_FRAME* aParent, FP_LIB_TABLE* aTable ); ~FOOTPRINT_EDIT_FRAME(); @@ -52,10 +55,14 @@ public: /** * Function GetActiveFootprintEditor (static) + * + * @param aTopOfProject is a PCB_EDIT_FRAME* window which anchors the search in + * a project specific way. + * * @return a reference to the current opened Footprint editor * or NULL if no Footprint editor currently opened */ - static FOOTPRINT_EDIT_FRAME* GetActiveFootprintEditor(); + static FOOTPRINT_EDIT_FRAME* GetActiveFootprintEditor( const wxWindow* aTopOfProject ); BOARD_DESIGN_SETTINGS& GetDesignSettings() const; // overload PCB_BASE_FRAME, get parent's void SetDesignSettings( const BOARD_DESIGN_SETTINGS& aSettings ); // overload @@ -195,7 +202,7 @@ public: bool Clear_Pcb( bool aQuery ); /* handlers for block commands */ - virtual int ReturnBlockCommand( int key ); + virtual int BlockCommand( int key ); /** * Function HandleBlockPlace @@ -406,6 +413,10 @@ public: DECLARE_EVENT_TABLE() protected: + + /// protected so only friend PCB::IFACE::CreateWindow() can act as sole factory. + FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, PCB_EDIT_FRAME* aParent ); + static BOARD* s_Pcb; ///< retain board across invocations of module editor /** @@ -433,7 +444,7 @@ protected: /// The library nickName is a short string, for now the same as the library path /// but without path and without extension. After library table support it becomes /// a lookup key. - const wxString& getLibNickName() const; + const wxString getLibNickName() const; void setLibNickName( const wxString& aNickname ); diff --git a/pcbnew/moduleframe.cpp b/pcbnew/moduleframe.cpp index 02b2f52958..bdbaf7d971 100644 --- a/pcbnew/moduleframe.cpp +++ b/pcbnew/moduleframe.cpp @@ -30,7 +30,9 @@ */ #include -#include +#include +//#include +#include #include #include #include @@ -150,8 +152,8 @@ END_EVENT_TABLE() #define FOOTPRINT_EDIT_FRAME_NAME wxT( "ModEditFrame" ) -FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( PCB_EDIT_FRAME* aParent, FP_LIB_TABLE* aTable ) : - PCB_BASE_FRAME( aParent, MODULE_EDITOR_FRAME_TYPE, wxEmptyString, +FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, PCB_EDIT_FRAME* aParent ) : + PCB_BASE_FRAME( aKiway, aParent, MODULE_EDITOR_FRAME_TYPE, wxEmptyString, wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, GetFootprintEditorFrameName() ) { @@ -160,7 +162,6 @@ FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( PCB_EDIT_FRAME* aParent, FP_LIB_TABL m_showAxis = true; // true to show X and Y axis on screen m_showGridAxis = true; // show the grid origin axis m_HotkeysZoomAndGridList = g_Module_Editor_Hokeys_Descr; - m_footprintLibTable = aTable; // Give an icon wxIcon icon; @@ -186,7 +187,7 @@ FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( PCB_EDIT_FRAME* aParent, FP_LIB_TABL SetScreen( s_screenModule ); GetScreen()->SetCurItem( NULL ); - LoadSettings(); + LoadSettings( config() ); GetBoard()->SetVisibleAlls(); @@ -256,15 +257,15 @@ FOOTPRINT_EDIT_FRAME::~FOOTPRINT_EDIT_FRAME() } -const wxString& FOOTPRINT_EDIT_FRAME::getLibNickName() const +const wxString FOOTPRINT_EDIT_FRAME::getLibNickName() const { - return wxGetApp().GetModuleLibraryNickname(); + return Prj().GetModuleLibraryNickname(); } void FOOTPRINT_EDIT_FRAME::setLibNickName( const wxString& aNickname ) { - wxGetApp().SetModuleLibraryNickname( aNickname ); + Prj().SetModuleLibraryNickname( aNickname ); } @@ -274,7 +275,7 @@ wxString FOOTPRINT_EDIT_FRAME::getLibPath() { const wxString& nickname = getLibNickName(); - const FP_LIB_TABLE::ROW* row = GetFootprintLibraryTable()->FindRow( nickname ); + const FP_LIB_TABLE::ROW* row = FootprintLibs()->FindRow( nickname ); return row->GetFullURI( true ); } @@ -294,9 +295,13 @@ const wxChar* FOOTPRINT_EDIT_FRAME::GetFootprintEditorFrameName() /* return a reference to the current opened Footprint editor * or NULL if no Footprint editor currently opened */ -FOOTPRINT_EDIT_FRAME* FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor() +FOOTPRINT_EDIT_FRAME* FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( const wxWindow* aParent ) { - return (FOOTPRINT_EDIT_FRAME*) wxWindow::FindWindowByName( GetFootprintEditorFrameName() ); + // top_of_project! + wxASSERT( dynamic_cast( aParent ) ); + + wxWindow* ret = wxWindow::FindWindowByName( GetFootprintEditorFrameName(), aParent ); + return (FOOTPRINT_EDIT_FRAME*) ret; } @@ -484,7 +489,9 @@ void FOOTPRINT_EDIT_FRAME::OnUpdateReplaceModuleInBoard( wxUpdateUIEvent& aEvent void FOOTPRINT_EDIT_FRAME::OnUpdateSelectCurrentLib( wxUpdateUIEvent& aEvent ) { - aEvent.Enable( m_footprintLibTable && !m_footprintLibTable->IsEmpty() ); + FP_LIB_TABLE* fptbl = FootprintLibs(); + + aEvent.Enable( fptbl && !fptbl->IsEmpty() ); } @@ -506,7 +513,7 @@ void FOOTPRINT_EDIT_FRAME::Show3D_Frame( wxCommandEvent& event ) return; } - m_Draw3DFrame = new EDA_3D_FRAME( this, _( "3D Viewer" ) ); + m_Draw3DFrame = new EDA_3D_FRAME( &Kiway(), this, _( "3D Viewer" ) ); m_Draw3DFrame->Show( true ); } @@ -622,7 +629,7 @@ void FOOTPRINT_EDIT_FRAME::updateTitle() { try { - bool writable = m_footprintLibTable->IsFootprintLibWritable( nickname ); + bool writable = FootprintLibs()->IsFootprintLibWritable( nickname ); // no exception was thrown, this means libPath is valid, but it may be read only. title = _( "Module Editor (active library: " ) + nickname + wxT( ")" ); diff --git a/pcbnew/modview_frame.cpp b/pcbnew/modview_frame.cpp index 99677a34ed..8375336b75 100644 --- a/pcbnew/modview_frame.cpp +++ b/pcbnew/modview_frame.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include @@ -118,17 +118,16 @@ static wxAcceleratorEntry accels[] = #define FOOTPRINT_VIEWER_FRAME_NAME wxT( "ModViewFrame" ) -FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( PCB_BASE_FRAME* aParent, - FP_LIB_TABLE* aTable, - wxSemaphore* aSemaphore, - long aStyle ) : - PCB_BASE_FRAME( aParent, MODULE_VIEWER_FRAME_TYPE, _( "Footprint Library Browser" ), - wxDefaultPosition, wxDefaultSize, aStyle, GetFootprintViewerFrameName() ) +FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent, wxSemaphore* aSemaphore ) : + PCB_BASE_FRAME( aKiway, aParent, MODULE_VIEWER_FRAME_TYPE, _( "Footprint Library Browser" ), + wxDefaultPosition, wxDefaultSize, + !aSemaphore ? + KICAD_DEFAULT_DRAWFRAME_STYLE : + KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT, + GetFootprintViewerFrameName() ) { wxAcceleratorTable table( DIM( accels ), accels ); - m_footprintLibTable = aTable; - m_FrameName = GetFootprintViewerFrameName(); m_configPath = wxT( "FootprintViewer" ); m_showAxis = true; // true to draw axis. @@ -159,8 +158,7 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( PCB_BASE_FRAME* aParent, SetScreen( new PCB_SCREEN( GetPageSizeIU() ) ); GetScreen()->m_Center = true; // Center coordinate origins on screen. - LoadSettings(); - + LoadSettings( config() ); SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y ); @@ -273,10 +271,13 @@ const wxChar* FOOTPRINT_VIEWER_FRAME::GetFootprintViewerFrameName() } -FOOTPRINT_VIEWER_FRAME* FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer() +FOOTPRINT_VIEWER_FRAME* FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer( const wxWindow* aParent ) { - return (FOOTPRINT_VIEWER_FRAME*) - wxWindow::FindWindowByName( GetFootprintViewerFrameName() ); + // top_of_project! + wxASSERT( dynamic_cast( aParent ) ); + + return (FOOTPRINT_VIEWER_FRAME*) wxWindow::FindWindowByName( + GetFootprintViewerFrameName(), aParent ); } @@ -314,7 +315,7 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateLibraryList() { m_libList->Clear(); - std::vector< wxString > nicknames = m_footprintLibTable->GetLogicalLibs(); + std::vector< wxString > nicknames = FootprintLibs()->GetLogicalLibs(); for( unsigned ii = 0; ii < nicknames.size(); ii++ ) m_libList->Append( nicknames[ii] ); @@ -353,7 +354,7 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateFootprintList() FOOTPRINT_LIST fp_info_list; - fp_info_list.ReadFootprintFiles( m_footprintLibTable, &m_libraryName ); + fp_info_list.ReadFootprintFiles( FootprintLibs(), &m_libraryName ); if( fp_info_list.GetErrorCount() ) { @@ -468,29 +469,15 @@ void FOOTPRINT_VIEWER_FRAME::ExportSelectedFootprint( wxCommandEvent& event ) } -void FOOTPRINT_VIEWER_FRAME::LoadSettings( ) +void FOOTPRINT_VIEWER_FRAME::LoadSettings( wxConfigBase* aCfg ) { - EDA_DRAW_FRAME::LoadSettings(); - -/* - wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - - // wxConfig* cfg = - wxGetApp().GetSettings(); -*/ + EDA_DRAW_FRAME::LoadSettings( aCfg ); } -void FOOTPRINT_VIEWER_FRAME::SaveSettings() +void FOOTPRINT_VIEWER_FRAME::SaveSettings( wxConfigBase* aCfg ) { - EDA_DRAW_FRAME::SaveSettings(); - -/* - wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath ); - - // wxConfig* cfg = - wxGetApp().GetSettings(); -*/ + EDA_DRAW_FRAME::SaveSettings( aCfg ); } @@ -505,7 +492,7 @@ void FOOTPRINT_VIEWER_FRAME::OnActivate( wxActivateEvent& event ) m_selectedFootprintName.Empty(); // Ensure we have the right library list: - std::vector< wxString > libNicknames = m_footprintLibTable->GetLogicalLibs(); + std::vector< wxString > libNicknames = FootprintLibs()->GetLogicalLibs(); if( libNicknames.size() == m_libList->GetCount() ) { @@ -635,7 +622,7 @@ void FOOTPRINT_VIEWER_FRAME::Show3D_Frame( wxCommandEvent& event ) return; } - m_Draw3DFrame = new EDA_3D_FRAME( this, wxEmptyString ); + m_Draw3DFrame = new EDA_3D_FRAME( &Kiway(), this, wxEmptyString ); Update3D_Frame( false ); m_Draw3DFrame->Show( true ); } @@ -741,7 +728,7 @@ void FOOTPRINT_VIEWER_FRAME::SelectCurrentFootprint( wxCommandEvent& event ) PCB_EDIT_FRAME* parent = (PCB_EDIT_FRAME*) GetParent(); wxString libname = m_libraryName + wxT( "." ) + LegacyFootprintLibPathExtension; MODULE* oldmodule = GetBoard()->m_Modules; - MODULE* module = LoadModuleFromLibrary( libname, parent->GetFootprintLibraryTable(), + MODULE* module = LoadModuleFromLibrary( libname, parent->FootprintLibs(), false ); if( module ) @@ -802,7 +789,7 @@ void FOOTPRINT_VIEWER_FRAME::SelectAndViewFootprint( int aMode ) // Delete the current footprint GetBoard()->m_Modules.DeleteAll(); - MODULE* footprint = m_footprintLibTable->FootprintLoad( m_libraryName, m_footprintName ); + MODULE* footprint = FootprintLibs()->FootprintLoad( m_libraryName, m_footprintName ); if( footprint ) GetBoard()->Add( footprint, ADD_APPEND ); diff --git a/pcbnew/modview_frame.h b/pcbnew/modview_frame.h index fd8d017df4..a120ef0177 100644 --- a/pcbnew/modview_frame.h +++ b/pcbnew/modview_frame.h @@ -37,12 +37,15 @@ class wxListBox; class wxSemaphore; class FP_LIB_TABLE; +namespace PCB { struct IFACE; } /** * Component library viewer main window. */ class FOOTPRINT_VIEWER_FRAME : public PCB_BASE_FRAME { + friend struct PCB::IFACE; + private: wxListBox* m_libList; // The list of libs names wxListBox* m_footprintList; // The list of footprint names @@ -58,9 +61,7 @@ protected: // the selected footprint is here public: - FOOTPRINT_VIEWER_FRAME( PCB_BASE_FRAME* aParent, FP_LIB_TABLE* aTable, - wxSemaphore* aSemaphore = NULL, - long aStyle = KICAD_DEFAULT_DRAWFRAME_STYLE ); + FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, PCB_BASE_FRAME* aParent, wxSemaphore* aSemaphore = NULL ); ~FOOTPRINT_VIEWER_FRAME(); @@ -76,10 +77,10 @@ public: * @return a reference to the current opened Footprint viewer * or NULL if no Footprint viewer currently opened */ - static FOOTPRINT_VIEWER_FRAME* GetActiveFootprintViewer(); + static FOOTPRINT_VIEWER_FRAME* GetActiveFootprintViewer( const wxWindow* aParent ); wxString& GetSelectedFootprint( void ) const { return m_selectedFootprintName; } - const wxString GetSelectedLibraryFullName( void ); + const wxString GetSelectedLibraryFullName(); /** * Function GetSelectedLibrary @@ -87,7 +88,7 @@ public: */ const wxString& GetSelectedLibrary() { return m_libraryName; } - virtual EDA_COLOR_T GetGridColor( void ) const; + virtual EDA_COLOR_T GetGridColor() const; /** * Function ReCreateLibraryList @@ -128,23 +129,8 @@ private: void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 ); - /** - * Function LoadSettings - * loads the library viewer frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get loaded. - */ - void LoadSettings(); - - /** - * Function SaveSettings - * save library viewer frame specific configuration settings. - * - * Don't forget to call this base method from any derived classes or the - * settings will not get saved. - */ - void SaveSettings(); + void LoadSettings( wxConfigBase* aCfg ); // override virtual + void SaveSettings( wxConfigBase* aCfg ); // override virtual wxString& GetFootprintName( void ) const { return m_footprintName; } diff --git a/pcbnew/muonde.cpp b/pcbnew/muonde.cpp index bd0d6c191a..f943b13c42 100644 --- a/pcbnew/muonde.cpp +++ b/pcbnew/muonde.cpp @@ -198,14 +198,14 @@ MODULE* PCB_EDIT_FRAME::Genere_Self( wxDC* DC ) Mself.lng = min_len; // Enter the desired length. - msg = ReturnStringFromValue( g_UserUnit, Mself.lng ); + msg = StringFromValue( g_UserUnit, Mself.lng ); wxTextEntryDialog dlg( this, _( "Length:" ), _( "Length" ), msg ); if( dlg.ShowModal() != wxID_OK ) return NULL; // canceled by user msg = dlg.GetValue(); - Mself.lng = ReturnValueFromString( g_UserUnit, msg ); + Mself.lng = ValueFromString( g_UserUnit, msg ); // Control values (ii = minimum length) if( Mself.lng < min_len ) @@ -614,7 +614,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWaveComponent( int shape_type ) break; } - wxString value = ReturnStringFromValue( g_UserUnit, gap_size ); + wxString value = StringFromValue( g_UserUnit, gap_size ); wxTextEntryDialog dlg( this, msg, _( "Create microwave module" ), value ); if( dlg.ShowModal() != wxID_OK ) @@ -624,7 +624,7 @@ MODULE* PCB_EDIT_FRAME::Create_MuWaveComponent( int shape_type ) } value = dlg.GetValue(); - gap_size = ReturnValueFromString( g_UserUnit, value ); + gap_size = ValueFromString( g_UserUnit, value ); bool abort = false; @@ -1094,14 +1094,14 @@ void PCB_EDIT_FRAME::Edit_Gap( wxDC* DC, MODULE* aModule ) gap_size = next_pad->GetPos0().x - pad->GetPos0().x - pad->GetSize().x; // Entrer the desired length of the gap. - msg = ReturnStringFromValue( g_UserUnit, gap_size ); + msg = StringFromValue( g_UserUnit, gap_size ); wxTextEntryDialog dlg( this, _( "Gap:" ), _( "Create Microwave Gap" ), msg ); if( dlg.ShowModal() != wxID_OK ) return; // cancelled by user msg = dlg.GetValue(); - gap_size = ReturnValueFromString( g_UserUnit, msg ); + gap_size = ValueFromString( g_UserUnit, msg ); // Updating sizes of pads forming the gap. int tw = GetBoard()->GetCurrentTrackWidth(); diff --git a/pcbnew/netlist.cpp b/pcbnew/netlist.cpp index 18d60f8cfd..258bea0c8f 100644 --- a/pcbnew/netlist.cpp +++ b/pcbnew/netlist.cpp @@ -28,7 +28,7 @@ */ #include -#include +#include #include #include #include @@ -172,7 +172,7 @@ void PCB_EDIT_FRAME::loadFootprints( NETLIST& aNetlist, REPORTER* aReporter ) MODULE* module = 0; MODULE* fpOnBoard; - if( aNetlist.IsEmpty() || m_footprintLibTable->IsEmpty() ) + if( aNetlist.IsEmpty() || FootprintLibs()->IsEmpty() ) return; aNetlist.SortByFPID(); diff --git a/pcbnew/onleftclick.cpp b/pcbnew/onleftclick.cpp index 00b313d784..78390e52ba 100644 --- a/pcbnew/onleftclick.cpp +++ b/pcbnew/onleftclick.cpp @@ -354,8 +354,9 @@ void PCB_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition ) if( (DrawStruct == NULL) || (DrawStruct->GetFlags() == 0) ) { m_canvas->MoveCursorToCrossHair(); - DrawStruct = (BOARD_ITEM*) LoadModuleFromLibrary( wxEmptyString, m_footprintLibTable, - true, aDC ); + DrawStruct = (BOARD_ITEM*) LoadModuleFromLibrary( + wxEmptyString, FootprintLibs(), true, aDC ); + SetCurItem( DrawStruct ); if( DrawStruct ) diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index 37d53b3795..7f2a3d51fb 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -971,7 +971,7 @@ static wxMenu* Append_Track_Width_List( BOARD* aBoard ) for( unsigned ii = 0; ii < aBoard->m_TrackWidthList.size(); ii++ ) { - value = ReturnStringFromValue( g_UserUnit, aBoard->m_TrackWidthList[ii], true ); + value = StringFromValue( g_UserUnit, aBoard->m_TrackWidthList[ii], true ); msg.Printf( _( "Track %s" ), GetChars( value ) ); if( ii == 0 ) @@ -984,9 +984,9 @@ static wxMenu* Append_Track_Width_List( BOARD* aBoard ) for( unsigned ii = 0; ii < aBoard->m_ViasDimensionsList.size(); ii++ ) { - value = ReturnStringFromValue( g_UserUnit, aBoard->m_ViasDimensionsList[ii].m_Diameter, + value = StringFromValue( g_UserUnit, aBoard->m_ViasDimensionsList[ii].m_Diameter, true ); - wxString drill = ReturnStringFromValue( g_UserUnit, + wxString drill = StringFromValue( g_UserUnit, aBoard->m_ViasDimensionsList[ii].m_Drill, true ); diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 105362f83c..6f79a2c5c3 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -463,7 +463,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer ) if( m_pcbSettings->m_padNumbers ) { textpos.y = -textpos.y; - aPad->ReturnStringPadName( buffer ); + aPad->StringPadName( buffer ); int len = buffer.Length(); double tsize = padsize.x / std::max( len, MIN_CHAR_COUNT ); tsize = std::min( tsize, size ); diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 62dab6ff16..cf0c61731e 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -30,7 +30,8 @@ */ #include -#include +#include +#include #include #include #include @@ -299,11 +300,9 @@ END_EVENT_TABLE() #define PCB_EDIT_FRAME_NAME wxT( "PcbFrame" ) -PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, - const wxPoint& pos, const wxSize& size, - long style ) : - PCB_BASE_FRAME( parent, PCB_FRAME_TYPE, title, pos, size, - style, PCB_EDIT_FRAME_NAME ) +PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : + PCB_BASE_FRAME( aKiway, aParent, PCB_FRAME_TYPE, wxT( "Pcbnew" ), wxDefaultPosition, + wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, PCB_EDIT_FRAME_NAME ) { m_FrameName = PCB_EDIT_FRAME_NAME; m_showBorderAndTitleBlock = true; // true to display sheet references @@ -321,8 +320,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, m_microWaveToolBar = NULL; m_useCmpFileForFpNames = true; - m_footprintLibTable = NULL; - m_globalFootprintTable = NULL; m_rotationAngle = 900; #ifdef KICAD_SCRIPTING_WXPYTHON @@ -370,7 +367,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, // LoadSettings() *after* creating m_LayersManager, because LoadSettings() // initialize parameters in m_LayersManager - LoadSettings(); + LoadSettings( config() ); // Be sure options are updated m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill; @@ -486,34 +483,6 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( wxWindow* parent, const wxString& title, m_auimgr.Update(); - if( m_globalFootprintTable == NULL ) - { - try - { - m_globalFootprintTable = new FP_LIB_TABLE(); - - if( !FP_LIB_TABLE::LoadGlobalTable( *m_globalFootprintTable ) ) - { - DisplayInfoMessage( this, wxT( "You have run Pcbnew for the first time using the " - "new footprint library table method for finding " - "footprints. Pcbnew has either copied the default " - "table or created an empty table in your home " - "folder. You must first configure the library " - "table to include all footprint libraries not " - "included with KiCad. See the \"Footprint Library " - "Table\" section of the CvPcb documentation for " - "more information." ) ); - } - } - catch( IO_ERROR ioe ) - { - wxString msg; - msg.Printf( _( "An error occurred attempting to load the global footprint library " - "table:\n\n%s" ), GetChars( ioe.errorText ) ); - DisplayError( this, msg ); - } - } - setupTools(); } @@ -527,9 +496,6 @@ PCB_EDIT_FRAME::~PCB_EDIT_FRAME() m_Macros[i].m_Record.clear(); delete m_drc; - - delete m_footprintLibTable; - delete m_globalFootprintTable; } @@ -705,7 +671,7 @@ void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) msg.Printf( _( "The auto save file <%s> could not be removed!" ), GetChars( fn.GetFullPath() ) ); - wxMessageBox( msg, wxGetApp().GetAppName(), wxOK | wxICON_ERROR, this ); + wxMessageBox( msg, Pgm().App().GetAppName(), wxOK | wxICON_ERROR, this ); } // Delete board structs and undo/redo lists, to avoid crash on exit @@ -738,7 +704,7 @@ void PCB_EDIT_FRAME::Show3D_Frame( wxCommandEvent& event ) return; } - m_Draw3DFrame = new EDA_3D_FRAME( this, _( "3D Viewer" ) ); + m_Draw3DFrame = new EDA_3D_FRAME( &Kiway(), this, _( "3D Viewer" ) ); m_Draw3DFrame->SetDefaultFileName( GetBoard()->GetFileName() ); m_Draw3DFrame->Show( true ); } @@ -793,62 +759,55 @@ void PCB_EDIT_FRAME::ShowDesignRulesEditor( wxCommandEvent& event ) } -void PCB_EDIT_FRAME::LoadSettings() +void PCB_EDIT_FRAME::LoadSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); + PCB_BASE_FRAME::LoadSettings( aCfg ); - if( config == NULL ) - return; - - // The configuration setting that used to be mixed in with the project file settings. - wxGetApp().ReadCurrentSetupValues( GetConfigurationSettings() ); - - PCB_BASE_FRAME::LoadSettings(); + wxConfigLoadSetups( aCfg, GetConfigurationSettings() ); double dtmp; - config->Read( OPTKEY_DEFAULT_LINEWIDTH_VALUE, &dtmp, 0.1 ); // stored in mm + aCfg->Read( OPTKEY_DEFAULT_LINEWIDTH_VALUE, &dtmp, 0.1 ); // stored in mm + if( dtmp < 0.01 ) dtmp = 0.01; + if( dtmp > 5.0 ) dtmp = 5.0; + g_DrawDefaultLineThickness = Millimeter2iu( dtmp ); + long tmp; - config->Read( PCB_SHOW_FULL_RATSNET_OPT, &tmp ); + + aCfg->Read( PCB_SHOW_FULL_RATSNET_OPT, &tmp ); GetBoard()->SetElementVisibility(RATSNEST_VISIBLE, tmp); - config->Read( PCB_MAGNETIC_PADS_OPT, &g_MagneticPadOption ); - config->Read( PCB_MAGNETIC_TRACKS_OPT, &g_MagneticTrackOption ); - config->Read( SHOW_MICROWAVE_TOOLS, &m_show_microwave_tools ); - config->Read( SHOW_LAYER_MANAGER_TOOLS, &m_show_layer_manager_tools ); + aCfg->Read( PCB_MAGNETIC_PADS_OPT, &g_MagneticPadOption ); + aCfg->Read( PCB_MAGNETIC_TRACKS_OPT, &g_MagneticTrackOption ); + aCfg->Read( SHOW_MICROWAVE_TOOLS, &m_show_microwave_tools ); + aCfg->Read( SHOW_LAYER_MANAGER_TOOLS, &m_show_layer_manager_tools ); // WxWidgets 2.9.1 seems call setlocale( LC_NUMERIC, "" ) - // when reading doubles in config, + // when reading doubles in cfg, // but forget to back to current locale. So we call SetLocaleTo_Default SetLocaleTo_Default( ); } -void PCB_EDIT_FRAME::SaveSettings() +void PCB_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg ) { - wxConfig* config = wxGetApp().GetSettings(); + PCB_BASE_FRAME::SaveSettings( aCfg ); - if( config == NULL ) - return; - - // The configuration setting that used to be mixed in with the project file settings. - wxGetApp().SaveCurrentSetupValues( GetConfigurationSettings() ); - - PCB_BASE_FRAME::SaveSettings(); + wxConfigSaveSetups( aCfg, GetConfigurationSettings() ); // This value is stored in mm ) - config->Write( OPTKEY_DEFAULT_LINEWIDTH_VALUE, + aCfg->Write( OPTKEY_DEFAULT_LINEWIDTH_VALUE, MM_PER_IU * g_DrawDefaultLineThickness ); long tmp = GetBoard()->IsElementVisible(RATSNEST_VISIBLE); - config->Write( PCB_SHOW_FULL_RATSNET_OPT, tmp ); - config->Write( PCB_MAGNETIC_PADS_OPT, (long) g_MagneticPadOption ); - config->Write( PCB_MAGNETIC_TRACKS_OPT, (long) g_MagneticTrackOption ); - config->Write( SHOW_MICROWAVE_TOOLS, (long) m_show_microwave_tools ); - config->Write( SHOW_LAYER_MANAGER_TOOLS, (long)m_show_layer_manager_tools ); + aCfg->Write( PCB_SHOW_FULL_RATSNET_OPT, tmp ); + aCfg->Write( PCB_MAGNETIC_PADS_OPT, (long) g_MagneticPadOption ); + aCfg->Write( PCB_MAGNETIC_TRACKS_OPT, (long) g_MagneticTrackOption ); + aCfg->Write( SHOW_MICROWAVE_TOOLS, (long) m_show_microwave_tools ); + aCfg->Write( SHOW_LAYER_MANAGER_TOOLS, (long)m_show_layer_manager_tools ); } @@ -1070,12 +1029,14 @@ void PCB_EDIT_FRAME::SetLanguage( wxCommandEvent& event ) { EDA_DRAW_FRAME::SetLanguage( event ); m_Layers->SetLayersManagerTabsText(); + wxAuiPaneInfo& pane_info = m_auimgr.GetPane( m_Layers ); + pane_info.Caption( _( "Visibles" ) ); m_auimgr.Update(); ReFillLayerWidget(); - FOOTPRINT_EDIT_FRAME * moduleEditFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); + FOOTPRINT_EDIT_FRAME* moduleEditFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor( this ); if( moduleEditFrame ) moduleEditFrame->EDA_DRAW_FRAME::SetLanguage( event ); } @@ -1128,10 +1089,8 @@ void PCB_EDIT_FRAME::SVG_Print( wxCommandEvent& event ) void PCB_EDIT_FRAME::UpdateTitle() { - wxString title; - wxFileName fileName = GetBoard()->GetFileName(); - - title.Printf( wxT( "Pcbnew %s " ), GetChars( GetBuildVersion() ) ); + wxFileName fileName = GetBoard()->GetFileName(); + wxString title = wxString::Format( wxT( "Pcbnew %s " ), GetChars( GetBuildVersion() ) ); if( fileName.IsOk() && fileName.FileExists() ) { @@ -1179,24 +1138,29 @@ void PCB_EDIT_FRAME::OnSelectAutoPlaceMode( wxCommandEvent& aEvent ) switch( aEvent.GetId() ) { - case ID_TOOLBARH_PCB_MODE_MODULE: - if( aEvent.IsChecked() && - m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_TRACKS ) ) - m_mainToolBar->ToggleTool( ID_TOOLBARH_PCB_MODE_TRACKS, false ); - break; - - case ID_TOOLBARH_PCB_MODE_TRACKS: - if( aEvent.IsChecked() && - m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_MODULE ) ) - m_mainToolBar->ToggleTool( ID_TOOLBARH_PCB_MODE_MODULE, false ); - break; + case ID_TOOLBARH_PCB_MODE_MODULE: + if( aEvent.IsChecked() && + m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_TRACKS ) ) + { + m_mainToolBar->ToggleTool( ID_TOOLBARH_PCB_MODE_TRACKS, false ); } + break; + + case ID_TOOLBARH_PCB_MODE_TRACKS: + if( aEvent.IsChecked() && + m_mainToolBar->GetToolToggled( ID_TOOLBARH_PCB_MODE_MODULE ) ) + { + m_mainToolBar->ToggleTool( ID_TOOLBARH_PCB_MODE_MODULE, false ); + } + break; + } } void PCB_EDIT_FRAME::ToPlotter( wxCommandEvent& event ) { DIALOG_PLOT dlg( this ); + dlg.ShowModal(); } @@ -1208,3 +1172,4 @@ void PCB_EDIT_FRAME::SetRotationAngle( int aRotationAngle ) m_rotationAngle = aRotationAngle; } + diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 37e0d12057..4d8e06a2cf 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -29,11 +29,12 @@ */ #ifdef KICAD_SCRIPTING -#include -#include + #include + #include #endif #include -#include +#include +#include #include #include #include @@ -52,68 +53,327 @@ #include #include #include +#include <3d_viewer.h> +#include +#include +#include // Colors for layers and items COLORS_DESIGN_SETTINGS g_ColorsSettings; -bool g_Drc_On = true; -bool g_AutoDeleteOldTrack = true; -bool g_Show_Module_Ratsnest; -bool g_Raccord_45_Auto = true; -bool g_Alternate_Track_Posture = false; -bool g_Track_45_Only_Allowed = true; // True to allow horiz, vert. and 45deg only tracks -bool g_Segments_45_Only; // True to allow horiz, vert. and 45deg only graphic segments -bool g_TwoSegmentTrackBuild = true; +bool g_Drc_On = true; +bool g_AutoDeleteOldTrack = true; +bool g_Show_Module_Ratsnest; +bool g_Raccord_45_Auto = true; +bool g_Alternate_Track_Posture = false; +bool g_Track_45_Only_Allowed = true; // True to allow horiz, vert. and 45deg only tracks +bool g_Segments_45_Only; // True to allow horiz, vert. and 45deg only graphic segments +bool g_TwoSegmentTrackBuild = true; -LAYER_NUM g_Route_Layer_TOP; -LAYER_NUM g_Route_Layer_BOTTOM; -int g_MaxLinksShowed; -int g_MagneticPadOption = capture_cursor_in_track_tool; -int g_MagneticTrackOption = capture_cursor_in_track_tool; +LAYER_NUM g_Route_Layer_TOP; +LAYER_NUM g_Route_Layer_BOTTOM; +int g_MaxLinksShowed; +int g_MagneticPadOption = capture_cursor_in_track_tool; +int g_MagneticTrackOption = capture_cursor_in_track_tool; -wxPoint g_Offset_Module; /* Distance to offset module trace when moving. */ +wxPoint g_Offset_Module; /* Distance to offset module trace when moving. */ /* Name of the document footprint list * usually located in share/modules/footprints_doc * this is of the responsibility to users to create this file * if they want to have a list of footprints */ -wxString g_DocModulesFileName = wxT( "footprints_doc/footprints.pdf" ); +wxString g_DocModulesFileName = wxT( "footprints_doc/footprints.pdf" ); // wxWindow* DoPythonStuff(wxWindow* parent); // declaration -IMPLEMENT_APP( EDA_APP ) +namespace PCB { -/* MacOSX: Needed for file association - * http://wiki.wxwidgets.org/WxMac-specific_topics - */ -void EDA_APP::MacOpenFile( const wxString& aFileName ) +static struct IFACE : public KIFACE_I { - PCB_EDIT_FRAME* frame = ( (PCB_EDIT_FRAME*) GetTopWindow() ); - wxFileName filename = aFileName; + // Of course all are virtual overloads, implementations of the KIFACE. - if( !filename.FileExists() ) - return; + IFACE( const char* aName, KIWAY::FACE_T aType ) : + KIFACE_I( aName, aType ) + {} - frame->LoadOnePcbFile( aFileName, false ); + bool OnKifaceStart( PGM_BASE* aProgram ); + + void OnKifaceEnd(); + + wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) + { + switch( aClassId ) + { + + case PCB_FRAME_TYPE: + { + PCB_EDIT_FRAME* frame = new PCB_EDIT_FRAME( aKiway, aParent ); + + frame->Zoom_Automatique( true ); + +#ifdef KICAD_SCRIPTING + // give the scripting helpers access to our frame + ScriptingSetPcbEditFrame( frame ); +#endif + + // @todo temporarily here + CreateServer( frame, KICAD_PCB_PORT_SERVICE_NUMBER ); + + return frame; + } + break; + + case MODULE_EDITOR_FRAME_TYPE: + { + // yuck: + PCB_EDIT_FRAME* editor = dynamic_cast( aParent ); + wxASSERT( editor ); + + FOOTPRINT_EDIT_FRAME* frame = new FOOTPRINT_EDIT_FRAME( aKiway, editor ); + + frame->Zoom_Automatique( true ); + + /* Read a default config file in case no project given on command line. + frame->LoadProjectFile( wxEmptyString, true ); + */ + + return frame; + } + break; + + case MODULE_VIEWER_FRAME_TYPE: + { + // yuck: + PCB_BASE_FRAME* editor = dynamic_cast( aParent ); + wxASSERT( editor ); + + FOOTPRINT_VIEWER_FRAME* frame = new FOOTPRINT_VIEWER_FRAME( aKiway, editor ); + + frame->Zoom_Automatique( true ); + + /* Read a default config file in case no project given on command line. + frame->LoadProjectFile( wxEmptyString, true ); + */ + + return frame; + } + break; + + default: + ; + } + + return NULL; + } + + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) + { + return NULL; + } + +} kiface( "pcbnew", KIWAY::FACE_PCB ); + +} // namespace + +using namespace PCB; + + +static PGM_BASE* process; + + +KIFACE_I& Kiface() { return kiface; } + + +// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h. +// KIFACE_GETTER will not have name mangling due to declaration in kiway.h. +MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram ) +{ + process = (PGM_BASE*) aProgram; + return &kiface; } -bool EDA_APP::OnInit() +PGM_BASE& Pgm() { - wxFileName fn; - PCB_EDIT_FRAME* frame = NULL; - wxString msg; + wxASSERT( process ); // KIFACE_GETTER has already been called. + return *process; +} - InitEDA_Appl( wxT( "Pcbnew" ), APP_PCBNEW_T ); + +/** + * Function set3DShapesPath + * attempts to set the environment variable given by aKiSys3Dmod to a valid path. + * (typically "KISYS3DMOD" ) + * If the environment variable is already set, + * then it left as is to respect the wishes of the user. + * + * The path is determined by attempting to find the path modules/packages3d + * files in kicad tree. + * This may or may not be the best path but it provides the best solution for + * backwards compatibility with the previous 3D shapes search path implementation. + * + * @note This must be called after #SetBinDir() is called at least on Windows. + * Otherwise, the kicad path is not known (Windows specific) + * + * @param aKiSys3Dmod = the value of environment variable, typically "KISYS3DMOD" + * @return false if the aKiSys3Dmod path is not valid. + */ +bool set3DShapesPath( const wxString& aKiSys3Dmod ) +{ + wxString path; + + // Set the KISYS3DMOD environment variable for the current process, + // if it is not already defined in the user's environment and valid. + if( wxGetEnv( aKiSys3Dmod, &path ) && wxFileName::DirExists( path ) ) + return true; + + // Attempt to determine where the 3D shape libraries were installed using the + // legacy path: + // on Unix: /usr/local/kicad/share/modules/packages3d + // or /usr/share/kicad/modules/packages3d + // On Windows: bin../share/modules/packages3d + wxString relpath( wxT( "modules/packages3d" ) ); + +// Apple MacOSx +#ifdef __WXMAC__ + path = wxT("/Library/Application Support/kicad/modules/packages3d/"); + + if( wxFileName::DirExists( path ) ) + { + wxSetEnv( aKiSys3Dmod, path ); + return true; + } + + path = wxString( wxGetenv( wxT( "HOME" ) ) ) + wxT("/Library/Application Support/kicad/modules/packages3d/"); + + if( wxFileName::DirExists( path ) ) + { + wxSetEnv( aKiSys3Dmod, path ); + return true; + } + +#elif defined(__UNIX__) // Linux and non-Apple Unix + // Try the home directory: + path.Empty(); + wxGetEnv( wxT("HOME"), &path ); + path += wxT("/kicad/share/") + relpath; + + if( wxFileName::DirExists( path ) ) + { + wxSetEnv( aKiSys3Dmod, path ); + return true; + } + + // Try the standard install path: + path = wxT("/usr/local/kicad/share/") + relpath; + + if( wxFileName::DirExists( path ) ) + { + wxSetEnv( aKiSys3Dmod, path ); + return true; + } + + // Try the official distrib standard install path: + path = wxT("/usr/share/kicad/") + relpath; + + if( wxFileName::DirExists( path ) ) + { + wxSetEnv( aKiSys3Dmod, path ); + return true; + } + +#else // Windows + // On Windows, the install path is given by the path of executables + wxFileName fn; + fn.AssignDir( Pgm().GetExecutablePath() ); + fn.RemoveLastDir(); + path = fn.GetPathWithSep() + wxT("share/") + relpath; + + if( wxFileName::DirExists( path ) ) + { + wxSetEnv( aKiSys3Dmod, path ); + return true; + } +#endif + + return false; +} + + +/// The global footprint library table. This is not dynamically allocated because +/// in a multiple project environment we must keep its address constant (since it is +/// the fallback table for multiple projects). +FP_LIB_TABLE GFootprintTable; + + +bool IFACE::OnKifaceStart( PGM_BASE* aProgram ) +{ + // This is process level, not project level, initialization of the DSO. + + // Do nothing in here pertinent to a project! + + start_common(); + + // Must be called before creating the main frame in order to + // display the real hotkeys in menus or tool tips + ReadHotkeyConfig( wxT( "PcbFrame" ), g_Board_Editor_Hokeys_Descr ); + + // Set 3D shape path from environment variable KISYS3DMOD + set3DShapesPath( wxT(KISYS3DMOD) ); + + g_DrawBgColor = BLACK; + + try + { + // The global table is not related to a specific project. All projects + // will use the same global table. So the KIFACE::OnKifaceStart() contract + // of avoiding anything project specific is not violated here. + + if( !FP_LIB_TABLE::LoadGlobalTable( GFootprintTable ) ) + { + DisplayInfoMessage( NULL, wxT( + "You have run Pcbnew for the first time using the " + "new footprint library table method for finding " + "footprints. Pcbnew has either copied the default " + "table or created an empty table in your home " + "folder. You must first configure the library " + "table to include all footprint libraries not " + "included with KiCad. See the \"Footprint Library " + "Table\" section of the CvPcb documentation for " + "more information." ) ); + } + } + catch( const IO_ERROR& ioe ) + { + wxString msg = wxString::Format( _( + "An error occurred attempting to load the global footprint library " + "table:\n\n%s" ), + GetChars( ioe.errorText ) + ); + DisplayError( NULL, msg ); + return false; + } #ifdef KICAD_SCRIPTING - msg.Empty(); -#ifdef __WINDOWS__ + wxString path_frag; + + #ifdef __MINGW32__ // force python environment under Windows: - const wxString python_us("python27_us"); + const wxString python_us( "python27_us" ); // Build our python path inside kicad wxString kipython = m_BinDir + python_us; @@ -122,6 +382,7 @@ bool EDA_APP::OnInit() if( wxDirExists( kipython ) ) { wxString ppath; + if( !wxGetEnv( wxT( "PYTHONPATH" ), &ppath ) || !ppath.Contains( python_us ) ) { ppath << kipython << wxT("/pylib;"); @@ -149,193 +410,35 @@ bool EDA_APP::OnInit() // which are ( [KICAD_PATH] is an environment variable to define) // [KICAD_PATH]/scripting/plugins // Add this default search path: - msg = wxGetApp().GetExecutablePath() + wxT("scripting/plugins"); -#else + path_frag = Pgm().GetExecutablePath() + wxT( "scripting/plugins" ); + #else // Add this default search path: - msg = wxT("/usr/local/kicad/bin/scripting/plugins"); -#endif + path_fag = wxT( "/usr/local/kicad/bin/scripting/plugins" ); + #endif + // On linux and osx, 2 others paths are // [HOME]/.kicad_plugins/ // [HOME]/.kicad/scripting/plugins/ - if ( !pcbnewInitPythonScripting( TO_UTF8(msg) ) ) + if( !pcbnewInitPythonScripting( TO_UTF8( path_frag ) ) ) { - wxMessageBox( wxT( "pcbnewInitPythonScripting() fails" ) ); + wxLogSysError( wxT( "pcbnewInitPythonScripting() failed." ) ); return false; } #endif - if( argc > 1 ) - { - fn = argv[1]; - - // Be sure the filename is absolute, to avoid issues - // when the filename is relative, - // for instance when stored in history list without path, - // and when building the config filename ( which should have a path ) - if( fn.IsRelative() ) - fn.MakeAbsolute(); - - if( fn.GetExt() != PcbFileExtension && fn.GetExt() != LegacyPcbFileExtension ) - { - msg.Printf( _( "Pcbnew file <%s> has a wrong extension.\n" - "Changing extension to .%s." ), - GetChars( fn.GetFullPath() ), - GetChars( PcbFileExtension ) ); - fn.SetExt( PcbFileExtension ); - wxMessageBox( msg ); - } - - if( !wxGetApp().LockFile( fn.GetFullPath() ) ) - { - DisplayError( NULL, _( "This file is already open." ) ); - return false; - } - } - - if( m_Checker && m_Checker->IsAnotherRunning() ) - { - if( !IsOK( NULL, _( "Pcbnew is already running, Continue?" ) ) ) - return false; - } - - // read current setup and reopen last directory if no filename to open in command line - bool reopenLastUsedDirectory = argc == 1; - GetSettings( reopenLastUsedDirectory ); - - if( fn.IsOk() && fn.DirExists() ) - wxSetWorkingDirectory( fn.GetPath() ); - - g_DrawBgColor = BLACK; - - /* Must be called before creating the main frame in order to - * display the real hotkeys in menus or tool tips */ - ReadHotkeyConfig( wxT( "PcbFrame" ), g_Board_Editor_Hokeys_Descr ); - - // Set any environment variables before loading FP_LIB_TABLE - SetFootprintLibTablePath(); - - frame = new PCB_EDIT_FRAME( NULL, wxT( "Pcbnew" ), wxPoint( 0, 0 ), wxSize( 600, 400 ) ); - -#ifdef KICAD_SCRIPTING - ScriptingSetPcbEditFrame(frame); /* give the scripting helpers access to our frame */ -#endif - - frame->UpdateTitle(); - - SetTopWindow( frame ); - frame->Show( true ); - - CreateServer( frame, KICAD_PCB_PORT_SERVICE_NUMBER ); - - frame->Zoom_Automatique( true ); - - // Load config and default values before loading a board file - // Some will be overwritten after loading the board file - frame->LoadProjectSettings( fn.GetFullPath() ); - - /* Load file specified in the command line. */ - if( fn.IsOk() ) - { - /* Note the first time Pcbnew is called after creating a new project - * the board file may not exist so we load settings only. - * However, because legacy board files are named *.brd, - * and new files are named *.kicad_pcb, - * for all previous projects ( before 2012, december 14 ), - * because KiCad manager ask to load a .kicad_pcb file - * if this file does not exist, it is certainly useful - * to test if a legacy file is existing, - * under the same name, and therefore if the user want to load it - */ - bool file_exists = false; - - if( fn.FileExists() ) - { - file_exists = true; - frame->LoadOnePcbFile( fn.GetFullPath() ); - } - else if( fn.GetExt() == KiCadPcbFileExtension ) - { - // Try to find a legacy file with the same name: - wxFileName fn_legacy = fn; - fn_legacy.SetExt( LegacyPcbFileExtension ); - - if( fn_legacy.FileExists() ) - { - msg.Printf( _( "File <%s> does not exist.\n" - "However a legacy file <%s> exists.\n" - "Do you want to load it?\n" - "It will be saved under the new file format." ), - GetChars( fn.GetFullPath() ), - GetChars( fn_legacy.GetFullPath() ) ); - - if( IsOK( frame, msg ) ) - { - file_exists = true; - frame->LoadOnePcbFile( fn_legacy.GetFullPath() ); - wxString filename = fn.GetFullPath(); - filename.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); - frame->GetBoard()->SetFileName( filename ); - frame->UpdateTitle(); - frame->OnModify(); // Ready to save the board under the new format - } - } - } - - if( ! file_exists ) - { - // File does not exists: prepare an empty board - if( ! fn.GetPath().IsEmpty() ) - wxSetWorkingDirectory( fn.GetPath() ); - - frame->GetBoard()->SetFileName( fn.GetFullPath( wxPATH_UNIX ) ); - frame->UpdateTitle(); - frame->UpdateFileHistory( frame->GetBoard()->GetFileName() ); - frame->OnModify(); // Ready to save the new empty board - - msg.Printf( _( "File <%s> does not exist.\nThis is normal for a new project" ), - GetChars( frame->GetBoard()->GetFileName() ) ); - wxMessageBox( msg ); - } - } - - else - // No file to open: initialize a new empty board - // using default values for design settings: - frame->Clear_Pcb( false ); - - // update the layer names in the listbox - frame->ReCreateLayerBox( false ); - - /* For an obscure reason the focus is lost after loading a board file - * when starting (i.e. only at this point) - * (seems due to the recreation of the layer manager after loading the file) - * give focus to main window and Drawpanel - * must be done for these 2 windows (for an obscure reason ...) - * Linux specific - * This is more a workaround than a fix. - */ - frame->SetFocus(); - frame->GetCanvas()->SetFocus(); - return true; } -#if 0 -// for some reason KiCad classes do not implement OnExit -// if I add it in the declaration, I need to fix it in every application -// so for now make a note TODO TODO -// we need to clean up python when the application exits -int EDA_APP::OnExit() +void IFACE::OnKifaceEnd() { - // Restore the thread state and tell Python to cleanup after itself. - // wxPython will do its own cleanup as part of that process. This is done - // in OnExit instead of ~MyApp because OnExit is only called if OnInit is - // successful. + end_common(); + #if KICAD_SCRIPTING_WXPYTHON + // Restore the thread state and tell Python to cleanup after itself. + // wxPython will do its own cleanup as part of that process. + // This should only be called if python was setup correctly. pcbnewFinishPythonScripting(); #endif - return 0; } -#endif diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 50ab5bbc59..48e31a6570 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -29,7 +29,9 @@ */ #include -#include +//#include +#include +#include #include #include #include @@ -84,21 +86,24 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) case ID_PCB_LIB_TABLE_EDIT: { bool tableChanged = false; - int r = InvokePcbLibTableEditor( this, m_globalFootprintTable, m_footprintLibTable ); + int r = InvokePcbLibTableEditor( this, &GFootprintTable, FootprintLibs() ); if( r & 1 ) { try { FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() ); - m_globalFootprintTable->Format( &sf, 0 ); + + GFootprintTable.Format( &sf, 0 ); tableChanged = true; } catch( IO_ERROR& ioe ) { - wxString msg; - msg.Printf( _( "Error occurred saving the global footprint library " - "table:\n\n%s" ), ioe.errorText.GetData() ); + wxString msg = wxString::Format( _( + "Error occurred saving the global footprint library " + "table:\n\n%s" ), + GetChars( ioe.errorText.GetData() ) + ); wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } @@ -111,7 +116,7 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) try { - m_footprintLibTable->Save( fn ); + FootprintLibs()->Save( fn ); tableChanged = true; } catch( IO_ERROR& ioe ) @@ -123,9 +128,11 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) } } - if( tableChanged && FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer() != NULL ) + FOOTPRINT_VIEWER_FRAME* viewer; + + if( tableChanged && (viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer( this )) != NULL ) { - FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer()->ReCreateLibraryList(); + viewer->ReCreateLibraryList(); } } break; @@ -211,19 +218,15 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) bool PCB_EDIT_FRAME::LoadProjectSettings( const wxString& aProjectFileName ) { - wxLogDebug( wxT( "Loading project <%s> settings." ), GetChars( aProjectFileName ) ); + wxLogDebug( wxT( "Loading project '%s' settings." ), GetChars( aProjectFileName ) ); - wxFileName fn = aProjectFileName; + wxFileName fn = aProjectFileName; if( fn.GetExt() != ProjectFileExtension ) fn.SetExt( ProjectFileExtension ); - wxGetApp().RemoveLibraryPath( g_UserLibDirBuffer ); - - wxGetApp().ReadProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters(), false ); - - // User library path takes precedent over default library search paths. - wxGetApp().InsertLibraryPath( g_UserLibDirBuffer, 1 ); + // was: wxGetApp().ReadProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters(), false ); + Prj().ConfigLoad( Kiface().KifaceSearch(), fn.GetFullPath(), GROUP, GetProjectFileParameters(), false ); // Dick 5-Feb-2012: I don't agree with this, the BOARD contents should dictate // what is visible or not, even initially. And since PCB_EDIT_FRAME projects settings @@ -246,36 +249,19 @@ bool PCB_EDIT_FRAME::LoadProjectSettings( const wxString& aProjectFileName ) fn = GetBoard()->GetFileName(); - // Check if a project footprint table is defined and load it. If no project footprint - // table is defined, then the global library table is the footprint library table. - FP_LIB_TABLE::SetProjectPathEnvVariable( fn ); + wxFileName projectFpLibTableFileName = FP_LIB_TABLE::GetProjectTableFileName( fn.GetFullPath() ); - delete m_footprintLibTable; - - wxFileName projectFpLibTableFileName; - - projectFpLibTableFileName = FP_LIB_TABLE::GetProjectFileName( fn ); - m_footprintLibTable = new FP_LIB_TABLE(); + FootprintLibs()->Clear(); try { - m_footprintLibTable->Load( projectFpLibTableFileName, m_globalFootprintTable ); + FootprintLibs()->Load( projectFpLibTableFileName, &GFootprintTable ); } catch( IO_ERROR ioe ) { DisplayError( this, ioe.errorText ); } - FOOTPRINT_EDIT_FRAME* editFrame = FOOTPRINT_EDIT_FRAME::GetActiveFootprintEditor(); - - if( editFrame ) - editFrame->SetFootprintLibTable( m_footprintLibTable ); - - FOOTPRINT_VIEWER_FRAME* viewFrame = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer(); - - if( viewFrame ) - viewFrame->SetFootprintLibTable( m_footprintLibTable ); - // Load the page layout decr file, from the filename stored in // BASE_SCREEN::m_PageLayoutDescrFileName, read in config project file // If empty, the default descr is loaded @@ -302,11 +288,12 @@ void PCB_EDIT_FRAME::SaveProjectSettings( bool aAskForSave ) if( dlg.ShowModal() == wxID_CANCEL ) return; - wxGetApp().WriteProjectConfig( dlg.GetPath(), GROUP, GetProjectFileParameters() ); + fn = dlg.GetPath(); } - else - wxGetApp().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters() ); + SEARCH_STACK& search = Kiface().KifaceSearch(); + + Prj().ConfigSave( search, fn.GetFullPath(), GROUP, GetProjectFileParameters() ); } diff --git a/pcbnew/pcbnew_config.h b/pcbnew/pcbnew_config.h index 7f430b2a88..a0b0006bbd 100644 --- a/pcbnew/pcbnew_config.h +++ b/pcbnew/pcbnew_config.h @@ -6,7 +6,7 @@ #ifndef _PCBNEW_CONFIG_H_ #define _PCBNEW_CONFIG_H_ -#include +#include #include #define GROUP wxT( "/pcbnew" ) diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 5cc2e4fd5c..aa4dfc3860 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -66,7 +66,7 @@ EDA_COLOR_T BRDITEMS_PLOTTER::getColor( LAYER_NUM aLayer ) void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, EDA_COLOR_T aColor, EDA_DRAW_MODE_T aPlotMode ) { - wxPoint shape_pos = aPad->ReturnShapePos(); + wxPoint shape_pos = aPad->ShapePos(); // Set plot color (change WHITE to LIGHTGRAY because // the white items are not seen on a white paper or screen diff --git a/pcbnew/printout_controler.cpp b/pcbnew/printout_controler.cpp index 7be6b40d3c..80ecd43d86 100644 --- a/pcbnew/printout_controler.cpp +++ b/pcbnew/printout_controler.cpp @@ -32,7 +32,7 @@ #define wxTEST_POSTSCRIPT_IN_MSW 1 #include -#include +#include #include #include #include diff --git a/pcbnew/printout_controler.h b/pcbnew/printout_controler.h index a31ccad559..83745c70e1 100644 --- a/pcbnew/printout_controler.h +++ b/pcbnew/printout_controler.h @@ -34,6 +34,8 @@ #include #include +#include + #define DEFAULT_ORIENTATION_PAPER wxLANDSCAPE // other option is wxPORTRAIT @@ -98,7 +100,6 @@ public: * is a class derived from wxPrintout to handle the necessary information to control a printer * when printing a board */ - class BOARD_PRINTOUT_CONTROLLER : public wxPrintout { private: diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index 7f37c5c89d..ae3916f444 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -832,7 +832,7 @@ PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia ) LAYER_NUM topLayerNum; LAYER_NUM botLayerNum; - aVia->ReturnLayerPair( &topLayerNum, &botLayerNum ); + aVia->LayerPair( &topLayerNum, &botLayerNum ); int topLayer = kicadLayer2pcb[topLayerNum]; int botLayer = kicadLayer2pcb[botLayerNum]; diff --git a/pcbnew/swap_layers.cpp b/pcbnew/swap_layers.cpp index 73d3347efa..11180b107b 100644 --- a/pcbnew/swap_layers.cpp +++ b/pcbnew/swap_layers.cpp @@ -367,7 +367,7 @@ void PCB_EDIT_FRAME::Swap_Layers( wxCommandEvent& event ) LAYER_NUM top_layer, bottom_layer; - Via->ReturnLayerPair( &top_layer, &bottom_layer ); + Via->LayerPair( &top_layer, &bottom_layer ); if( New_Layer[bottom_layer] >= 0 && New_Layer[bottom_layer] < LAYER_NO_CHANGE ) bottom_layer = New_Layer[bottom_layer]; diff --git a/pcbnew/target_edit.cpp b/pcbnew/target_edit.cpp index dba25a86d2..46310d4aae 100644 --- a/pcbnew/target_edit.cpp +++ b/pcbnew/target_edit.cpp @@ -99,11 +99,11 @@ TARGET_PROPERTIES_DIALOG_EDITOR::TARGET_PROPERTIES_DIALOG_EDITOR( PCB_EDIT_FRAME // Size: m_staticTextSizeUnits->SetLabel( GetUnitsLabel( g_UserUnit ) ); - m_TargetSizeCtrl->SetValue( ReturnStringFromValue( g_UserUnit, m_Target->GetSize() ) ); + m_TargetSizeCtrl->SetValue( StringFromValue( g_UserUnit, m_Target->GetSize() ) ); // Thickness: m_staticTextThicknessUnits->SetLabel( GetUnitsLabel( g_UserUnit ) ); - m_TargetThicknessCtrl->SetValue( ReturnStringFromValue( g_UserUnit, m_Target->GetWidth() ) ); + m_TargetThicknessCtrl->SetValue( StringFromValue( g_UserUnit, m_Target->GetWidth() ) ); // Shape m_TargetShape->SetSelection( m_Target->GetShape() ? 1 : 0 ); @@ -137,10 +137,10 @@ void TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick( wxCommandEvent& event ) m_Target->SetFlags( IN_EDIT ); // set flag in edit to force // undo/redo/abort proper operation - int tmp = ReturnValueFromString( g_UserUnit, m_TargetThicknessCtrl->GetValue() ); + int tmp = ValueFromString( g_UserUnit, m_TargetThicknessCtrl->GetValue() ); m_Target->SetWidth( tmp ); - MireDefaultSize = ReturnValueFromString( g_UserUnit, m_TargetSizeCtrl->GetValue() ); + MireDefaultSize = ValueFromString( g_UserUnit, m_TargetSizeCtrl->GetValue() ); m_Target->SetSize( MireDefaultSize ); m_Target->SetShape( m_TargetShape->GetSelection() ? 1 : 0 ); diff --git a/pcbnew/toolbars_update_user_interface.cpp b/pcbnew/toolbars_update_user_interface.cpp index 23d850d2b1..1c214f4240 100644 --- a/pcbnew/toolbars_update_user_interface.cpp +++ b/pcbnew/toolbars_update_user_interface.cpp @@ -30,7 +30,7 @@ */ #include -#include +#include #include #include #include <3d_viewer.h> diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index fbd2aee6f6..784e54c710 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -447,7 +447,7 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const { // For vias it is enough if only one of layers is visible LAYER_NUM top, bottom; - static_cast( aItem )->ReturnLayerPair( &top, &bottom ); + static_cast( aItem )->LayerPair( &top, &bottom ); return board->IsLayerVisible( top ) || board->IsLayerVisible( bottom ); } diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index babfc4818f..19f26cd1d9 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -496,7 +496,7 @@ void DIALOG_EXCHANGE_MODULE::BrowseAndSelectFootprint( wxCommandEvent& event ) wxString newname; newname = m_parent->SelectFootprint( m_parent, wxEmptyString, wxEmptyString, wxEmptyString, - m_parent->GetFootprintLibraryTable() ); + m_parent->FootprintLibs() ); if( newname != wxEmptyString ) m_NewModule->SetValue( newname ); diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 19dcfe5f2a..d147aada99 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -29,7 +29,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -553,21 +554,25 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) zone->SetNetNameFromNetCode( ); } double tmp = ZONE_THERMAL_RELIEF_GAP_MIL; - wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp ); + + wxConfigBase* cfg = Kiface().KifaceSettings(); + + cfg->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp ); + zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS); tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL; - wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, + cfg->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_CLEARANCE_MIL; - wxGetApp().GetSettings()->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, + cfg->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_THICKNESS_MIL; - wxGetApp().GetSettings()->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, + cfg->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS ); diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp index 61324cb6c7..1b81e200a6 100644 --- a/pcbnew/zones_by_polygon_fill_functions.cpp +++ b/pcbnew/zones_by_polygon_fill_functions.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/pcbnew/zones_convert_to_polygons_aux_functions.cpp b/pcbnew/zones_convert_to_polygons_aux_functions.cpp index f570ebdd4b..b9b5b9389b 100644 --- a/pcbnew/zones_convert_to_polygons_aux_functions.cpp +++ b/pcbnew/zones_convert_to_polygons_aux_functions.cpp @@ -235,7 +235,7 @@ void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer, RotatePoint( &ptTest[i], fAngle ); // translate point - ptTest[i] += pad->ReturnShapePos(); + ptTest[i] += pad->ShapePos(); if( aZone->HitTestFilledArea( ptTest[i] ) ) continue; @@ -280,7 +280,7 @@ void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer, { wxPoint cpos = corners_buffer[ic]; RotatePoint( &cpos, fAngle ); // Rotate according to module orientation - cpos += pad->ReturnShapePos(); // Shift origin to position + cpos += pad->ShapePos(); // Shift origin to position CPolyPt corner; corner.x = cpos.x; corner.y = cpos.y; diff --git a/pcbnew/zones_functions_for_undo_redo.cpp b/pcbnew/zones_functions_for_undo_redo.cpp index 52166bc5db..20519f4c45 100644 --- a/pcbnew/zones_functions_for_undo_redo.cpp +++ b/pcbnew/zones_functions_for_undo_redo.cpp @@ -43,7 +43,7 @@ */ #include -#include +#include #include #include diff --git a/pcbnew/zones_non_copper_type_functions.cpp b/pcbnew/zones_non_copper_type_functions.cpp index f6b2594bff..a8420eaaa2 100644 --- a/pcbnew/zones_non_copper_type_functions.cpp +++ b/pcbnew/zones_non_copper_type_functions.cpp @@ -3,7 +3,8 @@ */ #include -#include +//#include +#include #include #include #include @@ -77,7 +78,7 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::Init() SetReturnCode( ZONE_ABORT ); // Will be changed on button click AddUnitSymbol( *m_MinThicknessValueTitle, g_UserUnit ); - wxString msg = ReturnStringFromValue( g_UserUnit, m_settings.m_ZoneMinThickness ); + wxString msg = StringFromValue( g_UserUnit, m_settings.m_ZoneMinThickness ); m_ZoneMinThicknessCtrl->SetValue( msg ); if( m_settings.m_Zone_45_Only ) @@ -127,7 +128,7 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::OnOkClick( wxCommandEvent& event ) { wxString txtvalue = m_ZoneMinThicknessCtrl->GetValue(); - m_settings.m_ZoneMinThickness = ReturnValueFromString( g_UserUnit, txtvalue ); + m_settings.m_ZoneMinThickness = ValueFromString( g_UserUnit, txtvalue ); if( m_settings.m_ZoneMinThickness < 10 ) { @@ -153,11 +154,10 @@ void DIALOG_NON_COPPER_ZONES_EDITOR::OnOkClick( wxCommandEvent& event ) break; } - if( wxGetApp().GetSettings() ) - { - wxGetApp().GetSettings()->Write( ZONE_NET_OUTLINES_HATCH_OPTION_KEY, - (long) m_settings.m_Zone_HatchingStyle ); - } + wxConfigBase* cfg = Kiface().KifaceSettings(); + wxASSERT( cfg ); + + cfg->Write( ZONE_NET_OUTLINES_HATCH_OPTION_KEY, (long) m_settings.m_Zone_HatchingStyle ); if( m_OrientEdgesOpt->GetSelection() == 0 ) m_settings.m_Zone_45_Only = false; diff --git a/pcbnew/zones_polygons_test_connections.cpp b/pcbnew/zones_polygons_test_connections.cpp index ccc91634e2..108a554794 100644 --- a/pcbnew/zones_polygons_test_connections.cpp +++ b/pcbnew/zones_polygons_test_connections.cpp @@ -171,7 +171,7 @@ void BOARD::Test_Connections_To_Copper_Areas( int aNetcode ) // the pad position, because the zones are connected // to the center of the shape, not the pad position // (this is important for pads with thermal relief) - pos1 = pos2 = ( (D_PAD*) item )->ReturnShapePos(); + pos1 = pos2 = ( (D_PAD*) item )->ShapePos(); } else if( item->Type() == PCB_VIA_T ) { diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index eaa8a7f4d5..67c4cc363f 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -77,57 +77,3 @@ target_link_libraries( property_tree ${wxWidgets_LIBRARIES} ) - -#-------------------------------------------------- - -# The small launcher, it sets up wxWidgets library and loads a MODULE by the same name -# but with extension ${KIFACE_SUFFIX}. - -set( PAIR_BASE kiway_test ) - -add_executable( ${PAIR_BASE} WIN32 MACOSX_BUNDLE - EXCLUDE_FROM_ALL - ../common/single_top.cpp - ) -target_link_libraries( ${PAIR_BASE} - common - ${wxWidgets_LIBRARIES} - ) -if( APPLE ) - set_target_properties( ${PAIR_BASE} PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - ) -endif() - - -# make a KIFACE top level DLL/DSO -add_library( ${PAIR_BASE}_kiface MODULE - EXCLUDE_FROM_ALL - kiface_test.cpp - ) -target_link_libraries( ${PAIR_BASE}_kiface - common - ${wxWidgets_LIBRARIES} - ) -set_target_properties( ${PAIR_BASE}_kiface PROPERTIES - OUTPUT_NAME ${PAIR_BASE} - PREFIX ${KIFACE_PREFIX} - SUFFIX ${KIFACE_SUFFIX} - ) - -# if you build ${PAIR_BASE}, then also build ${PAIR_BASE}_kiface if out of date. -add_dependencies( ${PAIR_BASE} ${PAIR_BASE}_kiface ) - -if( MAKE_LINK_MAPS ) - - # generate a link maps with cross reference - - set_target_properties( ${PAIR_BASE}_kiface PROPERTIES - LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=${KIFACE_PREFIX}${PAIR_BASE}${KIFACE_SUFFIX}.map" - ) - - set_target_properties( ${PAIR_BASE} PROPERTIES - LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=${PAIR_BASE}.map" - ) - -endif() diff --git a/tools/kiface_test.cpp b/tools/kiface_test.cpp deleted file mode 100644 index a7a5d89797..0000000000 --- a/tools/kiface_test.cpp +++ /dev/null @@ -1,60 +0,0 @@ - -#include -#include -#include - - -// test static initialization, and translation in the DSO: -wxString GlobalTitle = _( "Some Translatable Window Title Text" ); - -/// Implement a KIFACE, and create a static instance of one. -static struct SCH_FACE : public KIFACE -{ - wxWindow* CreateWindow( int aClassId, KIWAY* aKIWAY, int aCtlBits = 0 ) - { - switch( aClassId ) - { - // for now, I have no class: - default: - return new wxFrame( NULL, 0, GlobalTitle, wxPoint( 0, 0 ), wxSize( 600, 400 ) ); - } - } - - /** - * Function IfaceOrAddress - * return a pointer to the requested object. The safest way to use this - * is to retrieve a pointer to a static instance of an interface, similar to - * how the KIFACE interface is exported. But if you know what you are doing - * use it to retrieve anything you want. - * - * @param aDataId identifies which object you want the address of. - * - * @return void* - and must be cast into the known type. - */ - void* IfaceOrAddress( int aDataId ) - { - return NULL; - } - -} kiface_impl; - - -static wxApp* app; - -extern "C" KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, wxApp* aProcess ); - -MY_API( KIFACE* ) KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, wxApp* aProcess ) -{ - // record the app's address. - app = aProcess; - - // return a pointer to the KIFACE implementation. - return &kiface_impl; -} - - -wxApp& wxGetApp() -{ - return *app; -} - From 141f3fed45226ba8e1ba68e5e180fb5c0ccab0f1 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Thu, 20 Mar 2014 09:18:32 -0500 Subject: [PATCH 25/46] some doxygen fixes, comment fixes --- include/bin_mod.h | 2 +- include/kiface_i.h | 2 +- include/kiway.h | 2 +- include/kiway_player.h | 6 ++- kicad/kicad.cpp | 91 +++--------------------------------------- 5 files changed, 13 insertions(+), 90 deletions(-) diff --git a/include/bin_mod.h b/include/bin_mod.h index c834f2cd7c..edfc9cf8e7 100644 --- a/include/bin_mod.h +++ b/include/bin_mod.h @@ -54,7 +54,7 @@ struct BIN_MOD const char* m_name; ///< name of this binary module, static C string. - wxConfigBase* m_config; ///< maybe from $HOME/. + wxConfigBase* m_config; ///< maybe from $HOME/.${m_name} wxFileHistory m_history; wxString m_help_file; diff --git a/include/kiface_i.h b/include/kiface_i.h index b0b455f971..23f89dffbf 100644 --- a/include/kiface_i.h +++ b/include/kiface_i.h @@ -71,7 +71,7 @@ public: * * @param aKifaceName should point to a C string in permanent storage, * which contains the name of the DSO. Examples: "eeschema", "pcbnew", etc. - * This controls the name of the wxConfigBase established in m_kiway_settings, + * This controls the name of the wxConfigBase established in m_bm, * so it should be lowercase. */ KIFACE_I( const char* aKifaceName, KIWAY::FACE_T aId ) : diff --git a/include/kiway.h b/include/kiway.h index dd83cc93f7..7cf4b7786b 100644 --- a/include/kiway.h +++ b/include/kiway.h @@ -194,7 +194,7 @@ struct KIFACE * * @param aKIWAY tells the window which KIWAY (and PROJECT) it is a participant in. * - * @param aCtlBits consists of bit flags from the set of KFCTL_* #defines above. + * @param aCtlBits consists of bit flags from the set of KFCTL_* \#defines above. * * @return wxWindow* - and if not NULL, should be cast into the known type using * dynamic_cast<>(). diff --git a/include/kiway_player.h b/include/kiway_player.h index 1798b1ba56..2ffab5acb6 100644 --- a/include/kiway_player.h +++ b/include/kiway_player.h @@ -65,7 +65,7 @@ public: * Function Prj * returns a reference to the PROJECT "associated with" this KIWAY. */ - PROJECT& Prj() const; // coded in kiface_i.cpp for now + PROJECT& Prj() const; /** * Function SetKiway @@ -76,7 +76,7 @@ public: * * @param aKiway is often from a parent window, or from KIFACE::CreateWindow(). */ - void SetKiway( wxWindow* aDest, KIWAY* aKiway ); // in kiface_i.cpp for now + void SetKiway( wxWindow* aDest, KIWAY* aKiway ); private: // private, all setting is done through SetKiway(). @@ -142,6 +142,8 @@ public: * according to the knowledge in the derived wxFrame. In almost every case, * the list will have only a single file in it. * + * @param aCtl is a set of bit flags ORed together from the set of KICTL_* \#defined above. + * * @return bool - true if all requested files were opened OK, else false. */ virtual bool OpenProjectFiles( const std::vector& aFileList, int aCtl = 0 ) diff --git a/kicad/kicad.cpp b/kicad/kicad.cpp index 4fc1831a5f..742121c781 100644 --- a/kicad/kicad.cpp +++ b/kicad/kicad.cpp @@ -199,8 +199,9 @@ void PGM_KICAD::destroy() /** * Class KIWAY_MGR - * is container for all (KIWAYS and PROJECTS). This class needs to work both for a C++ - * project manager and an a wxPython one (after being moved into a header later). + * is a container for all KIWAYS [and PROJECTS]. This class needs to work both + * for a C++ project manager and an a wxPython one (after being moved into a + * header later). */ class KIWAY_MGR { @@ -220,7 +221,8 @@ public: private: - // KIWAYs may not be moved once doled out. + // KIWAYs may not be moved once doled out, since window DNA depends on the + // pointer being good forever. // boost_ptr::vector however never moves the object pointed to. typedef boost::ptr_vector KIWAYS; @@ -280,6 +282,7 @@ PROJECT& Prj() bool KIWAY_MGR::OnStart( wxApp* aProcess ) { // The C++ project manager supports only one open PROJECT + // We should need no copy constructor for KIWAY to push a pointer. m_kiways.push_back( new KIWAY() ); return true; @@ -289,85 +292,3 @@ bool KIWAY_MGR::OnStart( wxApp* aProcess ) void KIWAY_MGR::OnEnd() { } - - -/* -static bool init( KICAD_PGM* aProcess, const wxString& aName ) -{ - m_Id = aId; - m_Checker = new wxSingleInstanceChecker( aName.Lower() + wxT( "-" ) + wxGetUserId() ); - - // Init KiCad environment - // the environment variable KICAD (if exists) gives the kicad path: - // something like set KICAD=d:\kicad - bool isDefined = wxGetEnv( wxT( "KICAD" ), &m_KicadEnv ); - - if( isDefined ) // ensure m_KicadEnv ends by "/" - { - m_KicadEnv.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); - - if( !m_KicadEnv.IsEmpty() && m_KicadEnv.Last() != '/' ) - m_KicadEnv += UNIX_STRING_DIR_SEP; - } - - // Prepare On Line Help. Use only lower case for help file names, in order to - // avoid problems with upper/lower case file names under windows and unix. -#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML - m_HelpFileName = aName.Lower() + wxT( ".html" ); -#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF - m_HelpFileName = aName.Lower() + wxT( ".pdf" ); -#else - #error Help files format not defined -#endif - - // Init parameters for configuration - SetVendorName( wxT( "KiCad" ) ); - SetAppName( aName.Lower() ); - SetTitle( aName ); - - m_settings = new wxConfig(); - - wxASSERT( m_settings != NULL ); - - m_commonSettings = new wxConfig( CommonConfigPath ); - wxASSERT( m_commonSettings != NULL ); - - // Install some image handlers, mainly for help - wxImage::AddHandler( new wxPNGHandler ); - wxImage::AddHandler( new wxGIFHandler ); - wxImage::AddHandler( new wxJPEGHandler ); - wxFileSystem::AddHandler( new wxZipFSHandler ); - - // Analyze the command line & init binary path - SetBinDir(); - SetDefaultSearchPaths(); - SetLanguagePath(); - ReadPdfBrowserInfos(); - - // Internationalization: loading the kicad suitable Dictionary - wxString languageSel; - m_commonSettings->Read( languageCfgKey, &languageSel); - - setLanguageId( wxLANGUAGE_DEFAULT ); - - // Search for the current selection - for( unsigned ii = 0; ii < DIM( s_Languages ); ii++ ) - { - if( s_Languages[ii].m_Lang_Label == languageSel ) - { - setLanguageId( s_Languages[ii].m_WX_Lang_Identifier ); - break; - } - } - - bool succes = SetLanguage( true ); - - if( !succes ) - { - } - - // Set locale option for separator used in float numbers - SetLocaleTo_Default(); -} -*/ - From 223419a8f6e881b6270ffdc35aa0165694f9842e Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Thu, 20 Mar 2014 11:32:34 -0500 Subject: [PATCH 26/46] documentation clarity --- common/kiway.cpp | 12 +++++------- include/kiway.h | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/common/kiway.cpp b/common/kiway.cpp index 01197f64c5..577f118e66 100644 --- a/common/kiway.cpp +++ b/common/kiway.cpp @@ -35,10 +35,11 @@ wxDynamicLibrary KIWAY::s_pcb_dso; KIWAY::KIWAY() { - memset( &m_dso_players, 0, sizeof( m_dso_players ) ); + memset( &m_kiface, 0, sizeof( m_kiface ) ); } +/* const wxString KIWAY::dso_name( FACE_T aFaceId ) { switch( aFaceId ) @@ -51,6 +52,7 @@ const wxString KIWAY::dso_name( FACE_T aFaceId ) return wxEmptyString; } } +*/ PROJECT& KIWAY::Prj() const @@ -65,10 +67,8 @@ KIFACE* KIWAY::KiFACE( FACE_T aFaceId, bool doLoad ) { case FACE_SCH: case FACE_PCB: - //case FACE_LIB: - //case FACE_MOD: - if( m_dso_players[aFaceId] ) - return m_dso_players[aFaceId]; + if( m_kiface[aFaceId] ) + return m_kiface[aFaceId]; default: wxASSERT_MSG( 0, wxT( "caller has a bug, passed a bad aFaceId" ) ); @@ -86,8 +86,6 @@ KIFACE* KIWAY::KiFACE( FACE_T aFaceId, bool doLoad ) case FACE_PCB: break; - //case FACE_LIB: - //case FACE_MOD: default: ; } diff --git a/include/kiway.h b/include/kiway.h index 7cf4b7786b..b13f8b88e4 100644 --- a/include/kiway.h +++ b/include/kiway.h @@ -159,7 +159,7 @@ struct KIFACE * should do process level initialization here, not project specific since there * will be multiple projects open eventually. * - * @param aProcess is the process block: PGM_BASE* + * @param aProgram is the process block: PGM_BASE* * * @return bool - true if DSO initialized OK, false if not. When returning * false, the loader may optionally decide to terminate the process or not, @@ -173,8 +173,6 @@ struct KIFACE * Function OnKifaceEnd * is called just once just before the DSO is to be unloaded. It is called * before static C++ destructors are called. A default implementation is supplied. - * - * @param aProcess is the process block: PGM_BASE* */ VTBL_ENTRY void OnKifaceEnd() = 0; @@ -197,7 +195,8 @@ struct KIFACE * @param aCtlBits consists of bit flags from the set of KFCTL_* \#defines above. * * @return wxWindow* - and if not NULL, should be cast into the known type using - * dynamic_cast<>(). + * and old school cast. dynamic_cast is problemenatic since it needs typeinfo probably + * not contained in the caller's link image. */ VTBL_ENTRY wxWindow* CreateWindow( wxWindow* aParent, int aClassId, KIWAY* aKIWAY, int aCtlBits = 0 ) = 0; @@ -232,7 +231,7 @@ struct KIFACE * are used to hold function pointers and eliminate the need to link to specific * object code libraries, speeding development and encouraging clearly defined * interface design. Unlike Microsoft COM, which is a multi-vendor design supporting - * DLL's built at various points in time. The KIWAY alchemy is single project, with + * DLL's built at various points in time, the KIWAY alchemy is single project, with * all components being built at the same time. So one should expect solid compatibility * between all KiCad components, as long at they are compiled at the same time. *

@@ -290,15 +289,17 @@ public: private: + /* /// Get the name of the DSO holding the requested FACE_T. static const wxString dso_name( FACE_T aFaceId ); + */ // one for each FACE_T static wxDynamicLibrary s_sch_dso; static wxDynamicLibrary s_pcb_dso; //static wxDynamicLibrary s_cvpcb_dso; // will get merged into pcbnew - KIFACE* m_dso_players[FACE_COUNT]; + KIFACE* m_kiface[FACE_COUNT]; PROJECT m_project; // do not assume this is here, use Prj(). }; @@ -308,19 +309,18 @@ private: * Function Pointer KIFACE_GETTER_FUNC * points to the one and only KIFACE export. The export's address * is looked up via symbolic string and should be extern "C" to avoid name - * mangling. That function can also implement process initialization functionality, - * things to do once per process that is DSO resident. This function will only be - * called one time. The DSO itself however may be asked to support multiple - * Top windows, i.e. multiple projects within its lifetime. + * mangling. This function will only be called one time. The DSO itself however + * may be asked to support multiple Top windows, i.e. multiple projects + * within its lifetime. * * @param aKIFACEversion is where to put the API version implemented by the KIFACE. * @param aKIWAYversion tells the KIFACE what KIWAY version will be available. - * @param aProcess is a pointer to the PGM_BASE for this process. - * @return KIFACE* - unconditionally. + * @param aProgram is a pointer to the PGM_BASE for this process. + * @return KIFACE* - unconditionally, cannot fail. */ typedef KIFACE* KIFACE_GETTER_FUNC( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram ); -/// No name mangling. Each TOPMOD will implement this once. +/// No name mangling. Each KIFACE (DSO/DLL) will implement this once. extern "C" KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKIWAYversion, PGM_BASE* aProgram ); #endif // KIWAY_H_ From 34dda6a1b09d5aad02d973d21af470884ae0d577 Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Thu, 20 Mar 2014 14:07:19 -0400 Subject: [PATCH 27/46] Fix windows build error for missing path separator definitions. * Use wxFileName::GetPathSeparator() instead of redefining them. --- common/systemdirsappend.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/systemdirsappend.cpp b/common/systemdirsappend.cpp index 65f7bfc2c0..0aefd88502 100644 --- a/common/systemdirsappend.cpp +++ b/common/systemdirsappend.cpp @@ -45,7 +45,8 @@ void SystemDirsAppend( SEARCH_STACK* aSearchStack ) // bin_dir uses unix path separator. So to parse with wxFileName // use windows separator, especially important for server inclusion: // like: \\myserver\local_path . - bin_dir.Replace( UNIX_STRING_DIR_SEP, WIN_STRING_DIR_SEP ); + bin_dir.Replace( wxFileName::GetPathSeparator( wxPATH_UNIX ), + wxFileName::GetPathSeparator( wxPATH_WIN ) ); #endif wxFileName bin_fn( bin_dir, wxEmptyString ); From a7f1939203b8053a2db2382fe338ce891471871d Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Thu, 20 Mar 2014 20:24:35 -0500 Subject: [PATCH 28/46] simplify and fix the technique used to get the project fp-lib-table --- common/fp_lib_table.cpp | 84 +++++++--------------------------------- common/project.cpp | 43 ++++++++++++++++++++ cvpcb/cfg.cpp | 7 +--- cvpcb/cvframe.cpp | 38 +++++++++--------- cvpcb/readwrite_dlgs.cpp | 20 +++++----- include/fp_lib_table.h | 19 +++++---- include/project.h | 7 ++++ pcbnew/basepcbframe.cpp | 4 ++ pcbnew/files.cpp | 22 +++++------ pcbnew/pcbnew.cpp | 3 ++ pcbnew/pcbnew_config.cpp | 66 +++++++++++++++---------------- 11 files changed, 160 insertions(+), 153 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 9bbb47c692..8c0d6f5a29 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -24,6 +24,7 @@ */ +#include #include // wxExpandEnvVars() #include #include @@ -45,19 +46,6 @@ using namespace FP_LIB_TABLE_T; -/** - * Definition for enabling and disabling footprint library trace output. See the - * wxWidgets documentation on using the WXTRACE environment variable. - */ -static const wxString traceFpLibTable( wxT( "KicadFpLibTable" ) ); - - -/// The footprint library table name used when no project file is passed to Pcbnew or CvPcb. -/// This is used temporarily to store the project specific library table until the project -/// file being edited is saved. It is then moved to the file fp-lib-table in the folder where -/// the project file is saved. -static const wxChar templateProjectFileName[] = wxT( "prj-fp-lib-table" ); - static const wxChar global_tbl_name[] = wxT( "fp-lib-table" ); @@ -408,19 +396,6 @@ void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const ); } - -void FP_LIB_TABLE::Save( const wxFileName& aPath ) const throw( IO_ERROR ) -{ - wxFileName fn = GetProjectTableFileName( aPath.GetFullPath() ); - - wxLogTrace( traceFpLibTable, wxT( "Saving footprint libary table <%s>." ), - GetChars( fn.GetFullPath() ) ); - - FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); - Format( &sf, 0 ); -} - - #define OPT_SEP '|' ///< options separator character PROPERTIES* FP_LIB_TABLE::ParseOptions( const std::string& aOptionsList ) @@ -842,34 +817,6 @@ const wxString FP_LIB_TABLE::GlobalPathEnvVariableName() } -wxString FP_LIB_TABLE::GetProjectTableFileName( const wxString& aProjectFullName ) -{ - wxFileName fn = aProjectFullName; - wxString path = fn.GetPath(); - - // Set $KICAD_PRJ_PATH to user's configuration path if aPath is not set or does not exist. - - if( !fn.IsOk() || !wxFileName::IsDirReadable( path ) ) - { - fn.AssignDir( wxStandardPaths::Get().GetUserConfigDir() ); - -#if defined( __WINDOWS__ ) - fn.AppendDir( wxT( "kicad" ) ); -#endif - fn.SetName( templateProjectFileName ); - } - else - { - fn.SetName( global_tbl_name ); - } - - wxLogTrace( traceFpLibTable, wxT( "Project footprint lib table file '%s'." ), - GetChars( fn.GetFullPath() ) ); - - return fn.GetFullPath(); -} - - bool FP_LIB_TABLE::LoadGlobalTable( FP_LIB_TABLE& aTable ) throw (IO_ERROR, PARSE_ERROR ) { bool tableExists = true; @@ -911,39 +858,38 @@ wxString FP_LIB_TABLE::GetGlobalTableFileName() { wxFileName fn; + // This is possibly problematic with an uncertain wxApp title, which is now + // the case. We'll need a better technique soon. fn.SetPath( wxStandardPaths::Get().GetUserConfigDir() ); #if defined( __WINDOWS__ ) fn.AppendDir( wxT( "kicad" ) ); #endif - fn.SetName( GetFileName() ); - - wxLogTrace( traceFpLibTable, wxT( "Global footprint library table file '%s'." ), - GetChars( fn.GetFullPath() ) ); + fn.SetName( global_tbl_name ); return fn.GetFullPath(); } +// prefer wxString filename so it can be seen in a debugger easier than wxFileName. -const wxString FP_LIB_TABLE::GetFileName() -{ - return global_tbl_name; -} - - -void FP_LIB_TABLE::Load( const wxFileName& aFileName, FP_LIB_TABLE* aFallBackTable ) +void FP_LIB_TABLE::Load( const wxString& aFileName ) throw( IO_ERROR ) { - fallBack = aFallBackTable; - // Empty footprint library tables are valid. - if( aFileName.IsOk() && aFileName.FileExists() ) + if( wxFileName::IsFileReadable( aFileName ) ) { - FILE_LINE_READER reader( aFileName.GetFullPath() ); + FILE_LINE_READER reader( aFileName ); FP_LIB_TABLE_LEXER lexer( &reader ); Parse( &lexer ); } } + +void FP_LIB_TABLE::Save( const wxString& aFileName ) const throw( IO_ERROR ) +{ + FILE_OUTPUTFORMATTER sf( aFileName ); + Format( &sf, 0 ); +} + diff --git a/common/project.cpp b/common/project.cpp index 48514ffd2a..b69926e574 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -82,6 +82,49 @@ const wxString PROJECT::GetProjectFullName() const } +const wxString PROJECT::FootprintLibTblName() const +{ + wxFileName fn = GetProjectFullName(); + wxString path = fn.GetPath(); + + // DBG(printf( "path:'%s' fn:'%s'\n", TO_UTF8(path), TO_UTF8(fn.GetFullPath()) );) + + // if there's no path to the project name, or the name as a whole is bogus or its not + // write-able then use a template file. + if( !fn.GetDirCount() || !fn.IsOk() || !wxFileName::IsDirWritable( path ) ) + { + // return a template filename now. + + // this next line is likely a problem now, since it relies on an + // application title which is no longer constant or known. This next line needs + // to be re-thought out. + + fn.AssignDir( wxStandardPaths::Get().GetUserConfigDir() ); + +#if defined( __WINDOWS__ ) + fn.AppendDir( wxT( "kicad" ) ); +#endif + + /* + The footprint library table name used when no project file is passed + to Pcbnew or CvPcb. This is used temporarily to store the project + specific library table until the project file being edited is saved. + It is then moved to the file fp-lib-table in the folder where the + project file is saved. + */ + fn.SetName( wxT( "prj-fp-lib-table" ) ); + } + else // normal path. + { + fn.SetName( wxT( "fp-lib-table" ) ); + } + + fn.ClearExt(); + + return fn.GetFullPath(); +} + + RETAINED_PATH& PROJECT::RPath( RETPATH_T aIndex ) { unsigned ndx = unsigned( aIndex ); diff --git a/cvpcb/cfg.cpp b/cvpcb/cfg.cpp index 28c9d9816e..c7b5986362 100644 --- a/cvpcb/cfg.cpp +++ b/cvpcb/cfg.cpp @@ -93,14 +93,11 @@ void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName ) prj.SetProjectFullName( fn.GetFullPath() ); */ - wxFileName projectFpLibTableFileName = FP_LIB_TABLE::GetProjectTableFileName( fn.GetFullPath() ); + wxString projectFpLibTableFileName = prj.FootprintLibTblName(); try { - // Stack the project specific FP_LIB_TABLE overlay on top of the global table. - // ~FP_LIB_TABLE() will not touch the fallback table, so multiple projects may - // stack this way, all using the same global fallback table. - FootprintLibs()->Load( projectFpLibTableFileName, &GFootprintTable ); + FootprintLibs()->Load( projectFpLibTableFileName ); } catch( const IO_ERROR& ioe ) { diff --git a/cvpcb/cvframe.cpp b/cvpcb/cvframe.cpp index e02774d814..ae14ead1f2 100644 --- a/cvpcb/cvframe.cpp +++ b/cvpcb/cvframe.cpp @@ -210,6 +210,9 @@ FP_LIB_TABLE* CVPCB_MAINFRAME::FootprintLibs() const if( !tbl ) { + // Stack the project specific FP_LIB_TABLE overlay on top of the global table. + // ~FP_LIB_TABLE() will not touch the fallback table, so multiple projects may + // stack this way, all using the same global fallback table. tbl = new FP_LIB_TABLE( &GFootprintTable ); prj.Elem( PROJECT::FPTBL, tbl ); } @@ -499,46 +502,45 @@ void CVPCB_MAINFRAME::ConfigCvpcb( wxCommandEvent& event ) void CVPCB_MAINFRAME::OnEditFootprintLibraryTable( wxCommandEvent& aEvent ) { - bool tableChanged = false; - int r = InvokePcbLibTableEditor( this, &GFootprintTable, FootprintLibs() ); + bool tableChanged = false; + int r = InvokePcbLibTableEditor( this, &GFootprintTable, FootprintLibs() ); if( r & 1 ) { + wxString fileName = FP_LIB_TABLE::GetGlobalTableFileName(); + try { - FILE_OUTPUTFORMATTER sf( FP_LIB_TABLE::GetGlobalTableFileName() ); - - GFootprintTable.Format( &sf, 0 ); + GFootprintTable.Save( fileName ); tableChanged = true; } catch( const IO_ERROR& ioe ) { wxString msg = wxString::Format( _( - "Error occurred saving the global footprint library " - "table:\n\n%s" ), - GetChars( ioe.errorText ) ); - + "Error occurred saving the global footprint library table:\n'%s'\n%s" ), + GetChars( fileName ), + GetChars( ioe.errorText ) + ); wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } if( r & 2 ) { - wxFileName fn = m_NetlistFileName; - fn.SetName( FP_LIB_TABLE::GetFileName() ); - fn.SetExt( wxEmptyString ); + wxString fileName = Prj().FootprintLibTblName(); try { - FILE_OUTPUTFORMATTER sf( fn.GetFullPath() ); - FootprintLibs()->Format( &sf, 0 ); + FootprintLibs()->Save( fileName ); tableChanged = true; } - catch( IO_ERROR& ioe ) + catch( const IO_ERROR& ioe ) { - wxString msg; - msg.Printf( _( "Error occurred saving the global footprint library " - "table:\n\n%s" ), ioe.errorText.GetData() ); + wxString msg = wxString::Format( _( + "Error occurred saving the project footprint library table:\n'%s'\n%s" ), + GetChars( fileName ), + GetChars( ioe.errorText ) + ); wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } diff --git a/cvpcb/readwrite_dlgs.cpp b/cvpcb/readwrite_dlgs.cpp index d55a79df14..6c07864ae0 100644 --- a/cvpcb/readwrite_dlgs.cpp +++ b/cvpcb/readwrite_dlgs.cpp @@ -317,25 +317,25 @@ int CVPCB_MAINFRAME::SaveCmpLinkFile( const wxString& aFullFileName ) // Save the project specific footprint library table. if( !FootprintLibs()->IsEmpty( false ) ) { - wxFileName fpLibFileName = fn; - fpLibFileName.ClearExt(); - fpLibFileName.SetName( FP_LIB_TABLE::GetFileName() ); + wxString fp_lib_tbl = Prj().FootprintLibTblName(); - if( fpLibFileName.FileExists() + if( wxFileName::FileExists( fp_lib_tbl ) && IsOK( this, _( "A footprint library table already exists in this path.\n\nDo " "you want to overwrite it?" ) ) ) { try { - FootprintLibs()->Save( fpLibFileName ); + FootprintLibs()->Save( fp_lib_tbl ); } catch( const IO_ERROR& ioe ) { - DisplayError( this, - wxString::Format( _( "An error occurred attempting to save the " - "footprint library table <%s>\n\n%s" ), - GetChars( fpLibFileName.GetFullPath() ), - GetChars( ioe.errorText ) ) ); + wxString msg = wxString::Format( _( + "An error occurred attempting to save the " + "footprint library table '%s'\n\n%s" ), + GetChars( fp_lib_tbl ), + GetChars( ioe.errorText ) + ); + DisplayError( this, msg ); } } } diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index a4c7c020d7..e4f589e53d 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -357,8 +357,6 @@ public: */ void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); - void Save( const wxFileName& aPath ) const throw( IO_ERROR ); - /** * Function GetLogicalLibs * returns the logical library names, all of them that are pertinent to @@ -544,11 +542,13 @@ public: */ static wxString GetGlobalTableFileName(); +#if 0 /** * Function GetFileName * @return the footprint library file name. */ static const wxString GetFileName(); +#endif /** * Function GlobalPathEnvVarVariableName @@ -560,19 +560,24 @@ public: */ static const wxString GlobalPathEnvVariableName(); - static wxString GetProjectTableFileName( const wxString& aProjectFullName ); - /** * Function Load * loads the footprint library table using the path defined in \a aFileName with * \a aFallBackTable. * - * @param aFileName contains the path and possible the file name and extension. - * @param aFallBackTable the fall back footprint library table which can be NULL. + * @param aFileName contains the full path to the s-expression file. + * * @throw IO_ERROR if an error occurs attempting to load the footprint library * table. */ - void Load( const wxFileName& aFileName, FP_LIB_TABLE* aFallBackTable ) throw( IO_ERROR ); + void Load( const wxString& aFileName ) throw( IO_ERROR ); + + /** + * Function Save + * writes this table to aFileName in s-expression form. + * @param aFileName is the name of the file to write to. + */ + void Save( const wxString& aFileName ) const throw( IO_ERROR ); protected: diff --git a/include/project.h b/include/project.h index a187aa5491..202d957eb8 100644 --- a/include/project.h +++ b/include/project.h @@ -82,6 +82,13 @@ public: */ VTBL_ENTRY const wxString GetProjectFullName() const; + /** + * Function FootprintLibTblName + * returns the path and filename of this project's fp-lib-table, + * i.e. the project specific one, not the global one. + */ + VTBL_ENTRY const wxString FootprintLibTblName() const; + /** * Function ConfigSave * saves the current "project" parameters into the wxConfigBase* derivative. diff --git a/pcbnew/basepcbframe.cpp b/pcbnew/basepcbframe.cpp index bc893a7a05..1afb7e71c6 100644 --- a/pcbnew/basepcbframe.cpp +++ b/pcbnew/basepcbframe.cpp @@ -181,7 +181,11 @@ FP_LIB_TABLE* PCB_BASE_FRAME::FootprintLibs() const if( !tbl ) { + // Stack the project specific FP_LIB_TABLE overlay on top of the global table. + // ~FP_LIB_TABLE() will not touch the fallback table, so multiple projects may + // stack this way, all using the same global fallback table. tbl = new FP_LIB_TABLE( &GFootprintTable ); + prj.Elem( PROJECT::FPTBL, tbl ); } diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index c62010d22c..d95a13df2c 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -605,25 +605,25 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupF // Save the project specific footprint library table. if( !FootprintLibs()->IsEmpty( false ) ) { - wxFileName fn = pcbFileName; - fn.ClearExt(); - fn.SetName( FP_LIB_TABLE::GetFileName() ); + wxString fp_lib_tbl = Prj().FootprintLibTblName(); - if( fn.FileExists() + if( wxFileName::FileExists( fp_lib_tbl ) && IsOK( this, _( "A footprint library table already exists in this path.\n\nDo " "you want to overwrite it?" ) ) ) { try { - FootprintLibs()->Save( fn ); + FootprintLibs()->Save( fp_lib_tbl ); } - catch( IO_ERROR& ioe ) + catch( const IO_ERROR& ioe ) { - DisplayError( this, - wxString::Format( _( "An error occurred attempting to save the " - "footprint library table '%s'\n\n%s" ), - GetChars( fn.GetFullPath() ), - GetChars( ioe.errorText ) ) ); + wxString msg = wxString::Format( _( + "An error occurred attempting to save the " + "footprint library table '%s'\n\n%s" ), + GetChars( fp_lib_tbl ), + GetChars( ioe.errorText ) + ); + DisplayError( this, msg ); } } } diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 59946a6c08..25ae74fa72 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -478,6 +478,9 @@ void IFACE::OnKifaceEnd() // wxPython will do its own cleanup as part of that process. // This should only be called if python was setup correctly. +/* bring this in, but without a linker error: pcbnewFinishPythonScripting(); +*/ + #endif } diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 8046ff7a45..0a8934f528 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -82,13 +82,13 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) case ID_MENU_PCB_SHOW_HIDE_MUWAVE_TOOLBAR: m_show_microwave_tools = ! m_show_microwave_tools; m_auimgr.GetPane( wxT( "m_microWaveToolBar" ) ).Show( m_show_microwave_tools ); - m_auimgr.Update(); + m_auimgr.Update(); GetMenuBar()->SetLabel( ID_MENU_PCB_SHOW_HIDE_MUWAVE_TOOLBAR, m_show_microwave_tools ? _( "Hide Microwave Toolbar" ): _( "Show Microwave Toolbar" )); break; - + case ID_PCB_LAYERS_SETUP: InstallDialogLayerSetup(); @@ -108,7 +108,7 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) GFootprintTable.Format( &sf, 0 ); tableChanged = true; } - catch( IO_ERROR& ioe ) + catch( const IO_ERROR& ioe ) { wxString msg = wxString::Format( _( "Error occurred saving the global footprint library " @@ -123,18 +123,20 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) // is kept in memory and created in the path when the new board is saved. if( (r & 2) && !GetBoard()->GetFileName().IsEmpty() ) { - wxFileName fn = GetBoard()->GetFileName(); + wxString tblName = Prj().FootprintLibTblName(); try { - FootprintLibs()->Save( fn ); + FootprintLibs()->Save( tblName ); tableChanged = true; } - catch( IO_ERROR& ioe ) + catch( const IO_ERROR& ioe ) { - wxString msg; - msg.Printf( _( "Error occurred saving project specific footprint library " - "table:\n\n%s" ), ioe.errorText.GetData() ); + wxString msg = wxString::Format( _( + "Error occurred saving project specific footprint library " + "table:\n\n%s" ), + GetChars( ioe.errorText ) + ); wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); } } @@ -171,27 +173,27 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) break; case ID_CONFIG_READ: - { - fn = GetBoard()->GetFileName(); - fn.SetExt( ProjectFileExtension ); - - wxFileDialog dlg( this, _( "Read Project File" ), fn.GetPath(), - fn.GetFullName(), ProjectFileWildcard, - wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR ); - - if( dlg.ShowModal() == wxID_CANCEL ) - break; - - if( !wxFileExists( dlg.GetPath() ) ) { - wxString msg; - msg.Printf( _( "File %s not found" ), GetChars( dlg.GetPath() ) ); - DisplayError( this, msg ); - break; - } + fn = GetBoard()->GetFileName(); + fn.SetExt( ProjectFileExtension ); - LoadProjectSettings( dlg.GetPath() ); - } + wxFileDialog dlg( this, _( "Read Project File" ), fn.GetPath(), + fn.GetFullName(), ProjectFileWildcard, + wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR ); + + if( dlg.ShowModal() == wxID_CANCEL ) + break; + + if( !wxFileExists( dlg.GetPath() ) ) + { + wxString msg; + msg.Printf( _( "File %s not found" ), GetChars( dlg.GetPath() ) ); + DisplayError( this, msg ); + break; + } + + LoadProjectSettings( dlg.GetPath() ); + } break; // Hotkey IDs @@ -258,17 +260,15 @@ bool PCB_EDIT_FRAME::LoadProjectSettings( const wxString& aProjectFileName ) SetElementVisibility( RATSNEST_VISIBLE, showRats ); #endif - fn = GetBoard()->GetFileName(); - - wxFileName projectFpLibTableFileName = FP_LIB_TABLE::GetProjectTableFileName( fn.GetFullPath() ); + wxString projectFpLibTableFileName = Prj().FootprintLibTblName(); FootprintLibs()->Clear(); try { - FootprintLibs()->Load( projectFpLibTableFileName, &GFootprintTable ); + FootprintLibs()->Load( projectFpLibTableFileName ); } - catch( IO_ERROR ioe ) + catch( const IO_ERROR& ioe ) { DisplayError( this, ioe.errorText ); } From ab30fba0ab429e228b9cd7a3c5d2b601645c639e Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Fri, 21 Mar 2014 12:50:04 +0100 Subject: [PATCH 29/46] CvPcb: Fix crashes when starting cvPcb (could be Windows Specific) and after closing the footprint viewer. --- cvpcb/class_DisplayFootprintsFrame.cpp | 11 ++------ cvpcb/class_DisplayFootprintsFrame.h | 2 ++ cvpcb/class_footprints_listbox.cpp | 2 +- cvpcb/cvframe.cpp | 38 ++++++++++++++++---------- cvpcb/cvpcb_mainframe.h | 6 +++- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/cvpcb/class_DisplayFootprintsFrame.cpp b/cvpcb/class_DisplayFootprintsFrame.cpp index 8c3054c6c0..f320465c8b 100644 --- a/cvpcb/class_DisplayFootprintsFrame.cpp +++ b/cvpcb/class_DisplayFootprintsFrame.cpp @@ -70,15 +70,13 @@ BEGIN_EVENT_TABLE( DISPLAY_FOOTPRINTS_FRAME, PCB_BASE_FRAME ) DISPLAY_FOOTPRINTS_FRAME::OnUpdateLineDrawMode ) END_EVENT_TABLE() -#define DISPLAY_FOOTPRINTS_FRAME_NAME wxT( "CmpFrame" ) - DISPLAY_FOOTPRINTS_FRAME::DISPLAY_FOOTPRINTS_FRAME( KIWAY* aKiway, CVPCB_MAINFRAME* aParent ) : - PCB_BASE_FRAME( aKiway, aParent, CVPCB_DISPLAY_FRAME_TYPE, _( "Module" ), + PCB_BASE_FRAME( aKiway, aParent, CVPCB_DISPLAY_FRAME_TYPE, _( "Footprint Viewer" ), wxDefaultPosition, wxDefaultSize, - KICAD_DEFAULT_DRAWFRAME_STYLE, DISPLAY_FOOTPRINTS_FRAME_NAME ) + KICAD_DEFAULT_DRAWFRAME_STYLE, FOOTPRINTVIEWER_FRAME_NAME ) { - m_FrameName = DISPLAY_FOOTPRINTS_FRAME_NAME; + m_FrameName = FOOTPRINTVIEWER_FRAME_NAME; m_showAxis = true; // true to draw axis. // Give an icon @@ -147,9 +145,6 @@ DISPLAY_FOOTPRINTS_FRAME::~DISPLAY_FOOTPRINTS_FRAME() { delete GetScreen(); SetScreen( NULL ); // Be sure there is no double deletion - - // a crash would be better than this uncommented: - // ( (CVPCB_MAINFRAME*) Pgm().GetTopWindow() )->m_DisplayFootprintFrame = NULL; } diff --git a/cvpcb/class_DisplayFootprintsFrame.h b/cvpcb/class_DisplayFootprintsFrame.h index 5c36fa6ef4..b26f372565 100644 --- a/cvpcb/class_DisplayFootprintsFrame.h +++ b/cvpcb/class_DisplayFootprintsFrame.h @@ -29,6 +29,8 @@ #include +// The name (for wxWidgets) of the footprint viewer frame +#define FOOTPRINTVIEWER_FRAME_NAME wxT( "FootprintViewerFrame" ) class CVPCB_MAINFRAME; diff --git a/cvpcb/class_footprints_listbox.cpp b/cvpcb/class_footprints_listbox.cpp index 7c1ab079e4..d09cee580b 100644 --- a/cvpcb/class_footprints_listbox.cpp +++ b/cvpcb/class_footprints_listbox.cpp @@ -207,7 +207,7 @@ void FOOTPRINTS_LISTBOX::OnLeftClick( wxListEvent& event ) return; // If the footprint view window is displayed, update the footprint. - if( GetParent()->m_DisplayFootprintFrame ) + if( GetParent()->GetFpViewerFrame() ) GetParent()->CreateScreenCmp(); GetParent()->DisplayStatus(); diff --git a/cvpcb/cvframe.cpp b/cvpcb/cvframe.cpp index ae14ead1f2..256e12c641 100644 --- a/cvpcb/cvframe.cpp +++ b/cvpcb/cvframe.cpp @@ -114,7 +114,6 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ) : m_ListCmp = NULL; m_FootprintList = NULL; m_LibraryList = NULL; - m_DisplayFootprintFrame = NULL; m_mainToolBar = NULL; m_modified = false; m_isEESchemaNetlist = false; @@ -315,8 +314,8 @@ void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& Event ) } // Close module display frame - if( m_DisplayFootprintFrame ) - m_DisplayFootprintFrame->Close( true ); + if( GetFpViewerFrame() ) + GetFpViewerFrame()->Close( true ); m_modified = false; @@ -562,7 +561,7 @@ void CVPCB_MAINFRAME::OnKeepOpenOnSave( wxCommandEvent& event ) void CVPCB_MAINFRAME::DisplayModule( wxCommandEvent& event ) { CreateScreenCmp(); - m_DisplayFootprintFrame->RedrawScreen( wxPoint( 0, 0 ), false ); + GetFpViewerFrame()->RedrawScreen( wxPoint( 0, 0 ), false ); } @@ -601,7 +600,9 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event ) m_FootprintList->SetFootprints( m_footprints, libraryName, component, filter ); // Tell AuiMgr that objects are changed ! - m_auimgr.Update(); + if( m_auimgr.GetManagedWindow() ) // Be sure Aui Manager is initialized + // (could be not the case when starting CvPcb + m_auimgr.Update(); if( component == NULL ) return; @@ -640,7 +641,7 @@ void CVPCB_MAINFRAME::OnSelectComponent( wxListEvent& event ) if ( ii >= 0 ) m_FootprintList->SetSelection( ii, false ); - if( m_DisplayFootprintFrame ) + if( GetFpViewerFrame() ) { CreateScreenCmp(); } @@ -919,15 +920,17 @@ bool CVPCB_MAINFRAME::WriteComponentLinkFile( const wxString& aFullFileName ) void CVPCB_MAINFRAME::CreateScreenCmp() { - if( !m_DisplayFootprintFrame ) + DISPLAY_FOOTPRINTS_FRAME* fpframe = GetFpViewerFrame(); + + if( !fpframe ) { - m_DisplayFootprintFrame = new DISPLAY_FOOTPRINTS_FRAME( &Kiway(), this ); - m_DisplayFootprintFrame->Show( true ); + fpframe = new DISPLAY_FOOTPRINTS_FRAME( &Kiway(), this ); + fpframe->Show( true ); } else { - if( m_DisplayFootprintFrame->IsIconized() ) - m_DisplayFootprintFrame->Iconize( false ); + if( fpframe->IsIconized() ) + fpframe->Iconize( false ); // The display footprint window might be buried under some other // windows, so CreateScreenCmp() on an existing window would not @@ -935,11 +938,11 @@ void CVPCB_MAINFRAME::CreateScreenCmp() // So we want to put it to front, second after our CVPCB_MAINFRAME. // We do this by a little dance of bringing it to front then the main // frame back. - m_DisplayFootprintFrame->Raise(); // Make sure that is visible. - Raise(); // .. but still we want the focus. + fpframe->Raise(); // Make sure that is visible. + Raise(); // .. but still we want the focus. } - m_DisplayFootprintFrame->InitDisplay(); + fpframe->InitDisplay(); } @@ -1049,3 +1052,10 @@ COMPONENT* CVPCB_MAINFRAME::GetSelectedComponent() return NULL; } + + +DISPLAY_FOOTPRINTS_FRAME* CVPCB_MAINFRAME::GetFpViewerFrame() +{ + // returns the Footprint Viewer frame, if exists, or NULL + return (DISPLAY_FOOTPRINTS_FRAME*) wxWindow::FindWindowByName( FOOTPRINTVIEWER_FRAME_NAME ); +} diff --git a/cvpcb/cvpcb_mainframe.h b/cvpcb/cvpcb_mainframe.h index 6a7e00efaa..8cd8f5c322 100644 --- a/cvpcb/cvpcb_mainframe.h +++ b/cvpcb/cvpcb_mainframe.h @@ -63,7 +63,6 @@ public: FOOTPRINTS_LISTBOX* m_FootprintList; LIBRARY_LISTBOX* m_LibraryList; COMPONENTS_LISTBOX* m_ListCmp; - DISPLAY_FOOTPRINTS_FRAME* m_DisplayFootprintFrame; wxAuiToolBar* m_mainToolBar; wxFileName m_NetlistFileName; wxArrayString m_ModuleLibNames; @@ -95,6 +94,11 @@ public: */ FP_LIB_TABLE* FootprintLibs() const; + /** + * @return a pointer on the Footprint Viewer frame, if exists, or NULL + */ + DISPLAY_FOOTPRINTS_FRAME* GetFpViewerFrame(); + /** * Function OnSelectComponent * Called when clicking on a component in component list window From 8fc1e3827149d56865de7f983a625cfc21d5cfc5 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Fri, 21 Mar 2014 07:20:54 -0500 Subject: [PATCH 30/46] Enable GITHUB as default, include typeinfo into kiway_holder.cpp --- CMakeLists.txt | 2 +- common/kiway_holder.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f3f114390..f2d3d8f19d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ mark_as_advanced( KICAD_SKIP_BOOST ) # Normal builders should build Boost. # when not defined by user, the default is python.exe under Windows and python2 for others # python binary file should be is exec path. -option( BUILD_GITHUB_PLUGIN "Build the GITHUB_PLUGIN for pcbnew." OFF ) +option( BUILD_GITHUB_PLUGIN "Build the GITHUB_PLUGIN for pcbnew." ON ) # This can be set to a custom name to brag about a particular branch in the "About" dialog: set( KICAD_REPO_NAME "product" CACHE STRING "Name of the tree from which this build came." ) diff --git a/common/kiway_holder.cpp b/common/kiway_holder.cpp index 8679254d82..a0a2dcfe76 100644 --- a/common/kiway_holder.cpp +++ b/common/kiway_holder.cpp @@ -2,6 +2,10 @@ #include #include +#if defined(DEBUG) + #include +#endif + PROJECT& KIWAY_HOLDER::Prj() const { @@ -26,4 +30,3 @@ void KIWAY_HOLDER::SetKiway( wxWindow* aDest, KIWAY* aKiway ) m_kiway = aKiway; } - From 4a39fcdd8fc3436f20f43f7fda5ce9b56ed7e4be Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Fri, 21 Mar 2014 11:59:19 -0500 Subject: [PATCH 31/46] single_top.c logic, improved OpenProjectFiles() documentation. --- common/single_top.cpp | 87 ++++++++++++++++-------------------------- include/kiway_player.h | 11 +++++- 2 files changed, 41 insertions(+), 57 deletions(-) diff --git a/common/single_top.cpp b/common/single_top.cpp index 22da93aacd..ce9fe38202 100644 --- a/common/single_top.cpp +++ b/common/single_top.cpp @@ -353,76 +353,54 @@ bool PGM_SINGLE_TOP::OnPgmInit( wxApp* aWxApp ) if( argc > 1 ) { + /* + gerbview handles multiple project data files, i.e. gerber files on + cmd line. Others currently do not, they handle only one. For common + code simplicity we simply pass all the arguments in however, each + program module can do with them what they want, ignore, complain + whatever. We don't establish policy here, as this is a multi-purpose + launcher. + */ -#if defined(TOP_FRAME) && TOP_FRAME==GERBER_FRAME_TYPE - // gerbview handles multiple project data files, i.e. gerber files on cmd line. - - std::vector fileSet; - - // Load all files specified on the command line. + std::vector argSet; for( int i=1; iOpenProjectFiles( fileSet ) ) - { - // OpenProjectFiles() API asks that it report failure to the UI. - // Nothing further to say here. - - // Fail the process startup if the file could not be opened, - // although this is an optional choice, one that can be reversed - // also in the KIFACE specific OpenProjectFiles() return value. - return false; - } - -#else - - wxFileName fn( argv[1] ); - - if( !fn.IsOk() ) - { - return false; - } - #if defined(PGM_DATA_FILE_EXT) - // PGM_DATA_FILE_EXT is different for each compile, it may come from CMake - // on the compiler command line, or not. - if( !fn.GetExt() ) - fn.SetExt( wxT( PGM_DATA_FILE_EXT ) ); -#endif + // PGM_DATA_FILE_EXT is different for each compile, it may come + // from CMake on the compiler command line, often does not. + // This facillity is mostly useful only for those program modules + // supporting a single argv[1]. + if( !argv1.GetExt() ) + argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) ); - if( !Pgm().LockFile( fn.GetFullPath() ) ) - { - wxLogSysError( _( "This file is already open." ) ); - return false; + argSet[0] = argv1.GetFullPath(); +#endif + if( !Pgm().LockFile( argSet[0] ) ) + { + wxLogSysError( _( "This file is already open." ) ); + return false; + } } - if( fn.GetPath().size() ) + // @todo: setting CWD is taboo in a multi-project environment, this + // will not be possible soon. + if( argv1.GetPath().size() ) // path only { - // wxSetWorkingDirectory does not like empty paths - wxSetWorkingDirectory( fn.GetPath() ); - - // @todo: setting CWD is taboo in a multi-project environment + // wxSetWorkingDirectory() does not like empty paths + wxSetWorkingDirectory( argv1.GetPath() ); } // Use the KIWAY_PLAYER::OpenProjectFiles() API function: - if( !frame->OpenProjectFiles( std::vector( 1, fn.GetFullPath() ) ) ) + if( !frame->OpenProjectFiles( argSet ) ) { // OpenProjectFiles() API asks that it report failure to the UI. // Nothing further to say here. @@ -432,7 +410,6 @@ bool PGM_SINGLE_TOP::OnPgmInit( wxApp* aWxApp ) // also in the KIFACE specific OpenProjectFiles() return value. return false; } -#endif } else { diff --git a/include/kiway_player.h b/include/kiway_player.h index 2ffab5acb6..b61b6f195c 100644 --- a/include/kiway_player.h +++ b/include/kiway_player.h @@ -129,8 +129,15 @@ public: * KIWAY_PLAYER is precluded. *

* Each derived class should handle this in a way specific to its needs. - * No prompting is done inside here for any file or project. There is no - * need to call this with aFileList which is empty. + * No prompting is done inside here for any file or project. There should be + * need to call this with aFileList which is empty. However, calling it with + * a single filename which does not exist should indicate to the implementor + * that a new session is being started and that the given name is the desired + * name for the data file at time of save. + *

+ * Therefore, one of the first things an implementation should do is test for + * existence of the first file in the list, and if it does not exist, treat + * it as a new session, possibly with a UI notification to that effect. *

* After loading the window should update its Title as part of this operation. * If the KIWAY_PLAYER needs to, it can load the *.pro file as part of this operation. From 262ec8920a435aad2012437bc6099bb584d483a7 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 22 Mar 2014 09:28:39 +0100 Subject: [PATCH 32/46] Minor fixes for Windows: move resources from dso to .exe, to have the application icon in executable, and therefore shown in shortcuts. pcb_calculator: minor coding style fix. --- cvpcb/CMakeLists.txt | 3 ++- eeschema/CMakeLists.txt | 3 ++- gerbview/CMakeLists.txt | 3 ++- pagelayout_editor/CMakeLists.txt | 9 ++++---- pcb_calculator/CMakeLists.txt | 3 ++- pcb_calculator/pcb_calculator.h | 6 +++--- pcb_calculator/pcb_calculator_frame.cpp | 14 ++++++------- pcb_calculator/transline_dlg_funct.cpp | 18 +++++++--------- pcb_calculator/transline_ident.cpp | 26 +++++++++++------------ pcb_calculator/transline_ident.h | 28 ++++++++++++------------- pcbnew/CMakeLists.txt | 3 ++- pcbnew/pcbnew.cpp | 7 ++++++- 12 files changed, 66 insertions(+), 57 deletions(-) diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index a5942f0f5d..de080fbf89 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -73,6 +73,7 @@ if( USE_KIWAY_DLLS ) add_executable( cvpcb WIN32 MACOSX_BUNDLE ../common/single_top.cpp ../common/pgm_base.cpp + ${CVPCB_RESOURCES} ) set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=CVPCB_FRAME_TYPE;PGM_DATA_FILE_EXT=\"net\";BUILD_KIWAY_DLL" @@ -94,7 +95,7 @@ if( USE_KIWAY_DLLS ) cvpcb.cpp ${CVPCB_SRCS} ${CVPCB_DIALOGS} - ${CVPCB_RESOURCES} +# ${CVPCB_RESOURCES} ) set_target_properties( cvpcb_kiface PROPERTIES OUTPUT_NAME cvpcb diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index ecbddd5014..9ae138f429 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -242,6 +242,7 @@ if( USE_KIWAY_DLLS ) add_executable( eeschema WIN32 MACOSX_BUNDLE ../common/single_top.cpp ../common/pgm_base.cpp + ${EESCHEMA_RESOURCES} ) set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=SCHEMATIC_FRAME_TYPE;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL" @@ -258,7 +259,7 @@ if( USE_KIWAY_DLLS ) add_library( eeschema_kiface MODULE ${EESCHEMA_SRCS} ${EESCHEMA_COMMON_SRCS} - ${EESCHEMA_RESOURCES} +# ${EESCHEMA_RESOURCES} ) target_link_libraries( eeschema_kiface common diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index 124a8d0c56..82e27ca1aa 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -91,6 +91,7 @@ if( USE_KIWAY_DLLS ) add_executable( gerbview WIN32 MACOSX_BUNDLE ../common/single_top.cpp ../common/pgm_base.cpp + ${GERBVIEW_RESOURCES} ) set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=GERBER_FRAME_TYPE;BUILD_KIWAY_DLL" @@ -113,7 +114,7 @@ if( USE_KIWAY_DLLS ) ${GERBVIEW_SRCS} ${DIALOGS_SRCS} ${GERBVIEW_EXTRA_SRCS} - ${GERBVIEW_RESOURCES} +# ${GERBVIEW_RESOURCES} ) set_target_properties( gerbview_kiface PROPERTIES OUTPUT_NAME gerbview diff --git a/pagelayout_editor/CMakeLists.txt b/pagelayout_editor/CMakeLists.txt index 3d25ce7ac3..e59bde050e 100644 --- a/pagelayout_editor/CMakeLists.txt +++ b/pagelayout_editor/CMakeLists.txt @@ -49,10 +49,11 @@ endif() if( USE_KIWAY_DLLS ) - # a very small program launcher for pcbnew_kiface + # a very small program launcher for pl_editor_kiface add_executable( pl_editor WIN32 MACOSX_BUNDLE ../common/single_top.cpp ../common/pgm_base.cpp + ${PL_EDITOR_RESOURCES} ) set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=PL_EDITOR_FRAME_TYPE;PGM_DATA_FILE_EXT=\"kicad_wks\";BUILD_KIWAY_DLL" @@ -69,13 +70,13 @@ if( USE_KIWAY_DLLS ) LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=pl_editor.map" ) endif() - # the main pcbnew program, in DSO form. + # the main pl_editor program, in DSO form. add_library( pl_editor_kiface MODULE pl_editor.cpp ${PL_EDITOR_SRCS} ${DIALOGS_SRCS} ${PL_EDITOR_EXTRA_SRCS} - ${PL_EDITOR_RESOURCES} +# ${PL_EDITOR_RESOURCES} ) target_link_libraries( pl_editor_kiface common @@ -99,7 +100,7 @@ if( USE_KIWAY_DLLS ) LINK_FLAGS "${TO_LINKER},-cref ${TO_LINKER},-Map=_pl_editor.kiface.map" ) endif() - # if building pcbnew, then also build pcbnew_kiface if out of date. + # if building pl_editor, then also build pl_editor_kiface if out of date. add_dependencies( pl_editor pl_editor_kiface ) # these 2 binaries are a matched set, keep them together: diff --git a/pcb_calculator/CMakeLists.txt b/pcb_calculator/CMakeLists.txt index 74be8fe1d7..51f1e21c66 100644 --- a/pcb_calculator/CMakeLists.txt +++ b/pcb_calculator/CMakeLists.txt @@ -72,6 +72,7 @@ if( USE_KIWAY_DLLS ) add_executable( pcb_calculator WIN32 MACOSX_BUNDLE ../common/single_top.cpp ../common/pgm_base.cpp + ${PCB_CALCULATOR_RESOURCES} ) set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=0;BUILD_KIWAY_DLL" @@ -92,7 +93,7 @@ if( USE_KIWAY_DLLS ) add_library( pcb_calculator_kiface MODULE pcb_calculator.cpp ${PCB_CALCULATOR_SRCS} - ${PCB_CALCULATOR_RESOURCES} +# ${PCB_CALCULATOR_RESOURCES} ) set_target_properties( pcb_calculator_kiface PROPERTIES OUTPUT_NAME pcb_calculator diff --git a/pcb_calculator/pcb_calculator.h b/pcb_calculator/pcb_calculator.h index 808b5da208..0c3633a5ca 100644 --- a/pcb_calculator/pcb_calculator.h +++ b/pcb_calculator/pcb_calculator.h @@ -29,7 +29,7 @@ private: wxSize m_FrameSize; wxPoint m_FramePos; wxConfig * m_Config; - enum transline_type_id m_currTransLineType; + enum TRANSLINE_TYPE_ID m_currTransLineType; TRANSLINE * m_currTransLine; // a pointer to the active transline // List of translines: ordered like in dialog menu list std::vector m_transline_list; @@ -153,9 +153,9 @@ private: * Update all values, labels and tool tips of parameters needed * by the new transline * Irrelevant parameters texts are blanked. - * @param aType = the transline_type_id of the new selected transline + * @param aType = the TRANSLINE_TYPE_ID of the new selected transline */ - void TranslineTypeSelection( enum transline_type_id aType ); + void TranslineTypeSelection( enum TRANSLINE_TYPE_ID aType ); /** * Function TransfDlgDataToTranslineParams diff --git a/pcb_calculator/pcb_calculator_frame.cpp b/pcb_calculator/pcb_calculator_frame.cpp index 9482a6ee83..7981201e25 100644 --- a/pcb_calculator/pcb_calculator_frame.cpp +++ b/pcb_calculator/pcb_calculator_frame.cpp @@ -58,17 +58,17 @@ PCB_CALCULATOR_FRAME::PCB_CALCULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) : SetKiway( this, aKiway ); m_currTransLine = NULL; - m_currTransLineType = default_type; + m_currTransLineType = DEFAULT_TYPE; m_currAttenuator = NULL; m_RegulatorListChanged = false; m_Config = new wxConfig(); // Populate transline list ordered like in dialog menu list - const static transline_type_id tltype_list[8] = + const static TRANSLINE_TYPE_ID tltype_list[8] = { - microstrip_type, cpw_type, grounded_cpw_type, - rectwaveguide_type, coax_type, c_microstrip_type, - stripline_type, twistedpair_type + MICROSTRIP_TYPE, CPW_TYPE, GROUNDED_CPW_TYPE, + RECTWAVEGUIDE_TYPE, COAX_TYPE, C_MICROSTRIP_TYPE, + STRIPLINE_TYPE, TWISTEDPAIR_TYPE }; for( int ii = 0; ii < 8; ii++ ) @@ -177,8 +177,8 @@ void PCB_CALCULATOR_FRAME::ReadConfig() m_Config->Read( KEYWORD_FRAME_POSY, &m_FramePos.y, -1 ); m_Config->Read( KEYWORD_FRAME_SIZEX, &m_FrameSize.x, -1 ); m_Config->Read( KEYWORD_FRAME_SIZEY, &m_FrameSize.y, -1 ); - m_Config->Read( KEYWORD_TRANSLINE_SELECTION, <mp, (long) default_type ); - m_currTransLineType = (enum transline_type_id) ltmp; + m_Config->Read( KEYWORD_TRANSLINE_SELECTION, <mp, (long) DEFAULT_TYPE ); + m_currTransLineType = (enum TRANSLINE_TYPE_ID) ltmp; m_Config->Read( KEYWORD_PAGE_SELECTION, <mp, 0 ); m_Notebook->ChangeSelection( ltmp ); m_Config->Read( KEYWORD_COLORCODE_SELECTION, <mp, 1 ); diff --git a/pcb_calculator/transline_dlg_funct.cpp b/pcb_calculator/transline_dlg_funct.cpp index 50ee7ea4fa..f6ca6a4208 100644 --- a/pcb_calculator/transline_dlg_funct.cpp +++ b/pcb_calculator/transline_dlg_funct.cpp @@ -33,9 +33,7 @@ extern double DoubleFromString( const wxString& TextValue ); -/* - * these values come from QucsStudio ( by Michael Margraf ) - */ +// these values come from QucsStudio ( by Michael Margraf ) // Display a selection of usual Er, TanD, Rho values // format is @@ -143,16 +141,16 @@ struct DLG_PRM_DATA * Irrelevant parameters texts are blanked. * @param aType = the transline_type_id of the new selected transline */ -void PCB_CALCULATOR_FRAME::TranslineTypeSelection( enum transline_type_id aType ) +void PCB_CALCULATOR_FRAME::TranslineTypeSelection( enum TRANSLINE_TYPE_ID aType ) { wxString msg; #define DOUBLE_TO_CTLR( dlg_item, value ) { msg.Printf( wxT( "%g" ), value );\ dlg_item->SetValue( msg ); } m_currTransLineType = aType; - if( (m_currTransLineType < start_of_list_type ) - || ( m_currTransLineType >= end_of_list_type ) ) - m_currTransLineType = default_type; + if( (m_currTransLineType < START_OF_LIST_TYPE ) + || ( m_currTransLineType >= END_OF_LIST_TYPE ) ) + m_currTransLineType = DEFAULT_TYPE; TRANSLINE_IDENT* tr_ident = m_transline_list[m_currTransLineType]; m_currTransLine = tr_ident->m_TLine; @@ -348,8 +346,8 @@ void PCB_CALCULATOR_FRAME::TranslineTypeSelection( enum transline_type_id aType /** * Function TransfDlgDataToTranslineParams - * Read values entered in dialog frame, and transfert these - * values in current transline parameters, converted in normalized units + * Read values entered in dialog frame, and copy these values + * in current transline parameters, converted in normalized units */ void PCB_CALCULATOR_FRAME::TransfDlgDataToTranslineParams() { @@ -378,7 +376,7 @@ void PCB_CALCULATOR_FRAME::TransfDlgDataToTranslineParams() */ void PCB_CALCULATOR_FRAME::OnTranslineSelection( wxCommandEvent& event ) { - enum transline_type_id id = (enum transline_type_id) event.GetSelection(); + enum TRANSLINE_TYPE_ID id = (enum TRANSLINE_TYPE_ID) event.GetSelection(); TranslineTypeSelection( id ); diff --git a/pcb_calculator/transline_ident.cpp b/pcb_calculator/transline_ident.cpp index 48369d0c03..fc74e0d27b 100644 --- a/pcb_calculator/transline_ident.cpp +++ b/pcb_calculator/transline_ident.cpp @@ -100,7 +100,7 @@ double TRANSLINE_PRM::FromUserUnit() * A class to handle a list of parameters of a given transline */ -TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) +TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) { m_Type = aType; // The type of transline handled m_Icon = NULL; // An xpm icon to display in dialogs @@ -129,7 +129,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) switch( m_Type ) { - case microstrip_type: // microstrip + case MICROSTRIP_TYPE: // microstrip m_TLine = new MICROSTRIP(); m_Icon = new wxBitmap( microstrip_xpm ); @@ -165,7 +165,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; - case cpw_type: // coplanar waveguide + case CPW_TYPE: // coplanar waveguide m_TLine = new COPLANAR(); m_Icon = new wxBitmap( cpw_xpm ); m_HasPrmSelection = true; @@ -197,7 +197,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; - case grounded_cpw_type: // grounded coplanar waveguide + case GROUNDED_CPW_TYPE: // grounded coplanar waveguide m_TLine = new GROUNDEDCOPLANAR(); m_Icon = new wxBitmap( cpw_back_xpm ); m_HasPrmSelection = true; @@ -230,7 +230,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) break; - case rectwaveguide_type: // rectangular waveguide + case RECTWAVEGUIDE_TYPE: // rectangular waveguide m_TLine = new RECTWAVEGUIDE(); m_Icon = new wxBitmap( rectwaveguide_xpm ); m_HasPrmSelection = true; @@ -264,7 +264,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "Ang_l" ), _( "Electrical Length" ), 0, true ) ); break; - case coax_type: // coaxial cable + case COAX_TYPE: // coaxial cable m_TLine = new COAX(); m_Icon = new wxBitmap( coax_xpm ); m_HasPrmSelection = true; @@ -295,7 +295,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; - case c_microstrip_type: // coupled microstrip + case C_MICROSTRIP_TYPE: // coupled microstrip m_TLine = new C_MICROSTRIP(); m_Icon = new wxBitmap( c_microstrip_xpm ); m_HasPrmSelection = true; @@ -328,14 +328,14 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_E_PRM, - _( "Z0e" ), _( "Even-Mode Impedance" ), 50.0, true ) ); + _( "Z0e (Zdiff)" ), _( "Even-Mode impedance (diff impedance)" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_O_PRM, - _( "Z0o" ), _( "Odd-Mode Impedance" ), 50.0, true ) ); + _( "Z0o (Z0)" ), _( "Odd-Mode impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); + _( "Ang_l" ), _( "Electrical length" ), 0.0, true ) ); break; - case stripline_type: // stripline + case STRIPLINE_TYPE: // stripline m_TLine = new STRIPLINE(); m_Icon = new wxBitmap( stripline_xpm ); @@ -367,7 +367,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "Ang_l" ), _( "Electrical Length" ), 0, true ) ); break; - case twistedpair_type: // twisted pair + case TWISTEDPAIR_TYPE: // twisted pair m_TLine = new TWISTEDPAIR(); m_Icon = new wxBitmap( twistedpair_xpm ); m_HasPrmSelection = true; @@ -399,7 +399,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum transline_type_id aType ) _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; - case end_of_list_type: // Not really used + case END_OF_LIST_TYPE: // Not really used break; } } diff --git a/pcb_calculator/transline_ident.h b/pcb_calculator/transline_ident.h index 45854a7877..d0805b04c7 100644 --- a/pcb_calculator/transline_ident.h +++ b/pcb_calculator/transline_ident.h @@ -12,18 +12,18 @@ #include // An enum to handle muwave shapes: -enum transline_type_id { - start_of_list_type = 0, - default_type = start_of_list_type, - microstrip_type = default_type, - cpw_type, - grounded_cpw_type, - rectwaveguide_type, - coax_type, - c_microstrip_type, - stripline_type, - twistedpair_type, - end_of_list_type +enum TRANSLINE_TYPE_ID { + START_OF_LIST_TYPE = 0, + DEFAULT_TYPE = START_OF_LIST_TYPE, + MICROSTRIP_TYPE = DEFAULT_TYPE, + CPW_TYPE, + GROUNDED_CPW_TYPE, + RECTWAVEGUIDE_TYPE, + COAX_TYPE, + C_MICROSTRIP_TYPE, + STRIPLINE_TYPE, + TWISTEDPAIR_TYPE, + END_OF_LIST_TYPE }; // A Class to handle parameters @@ -66,7 +66,7 @@ public: TRANSLINE_PRM( PRM_TYPE aType, PRMS_ID aId, class TRANSLINE_IDENT { public: - enum transline_type_id m_Type; // The type of transline handled + enum TRANSLINE_TYPE_ID m_Type; // The type of transline handled wxBitmap * m_Icon; // An icon to display in dialogs TRANSLINE* m_TLine; // The TRANSLINE itself wxArrayString m_Messages; // messages for results @@ -75,7 +75,7 @@ public: private: std::vector m_prms_List; -public: TRANSLINE_IDENT( enum transline_type_id aType ); +public: TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ); ~TRANSLINE_IDENT(); // Add a new param in list diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 768f76b161..d4fe33441d 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -505,6 +505,7 @@ if( USE_KIWAY_DLLS ) add_executable( pcbnew WIN32 MACOSX_BUNDLE ../common/single_top.cpp ../common/pgm_base.cpp + ${PCBNEW_RESOURCES} ) set_source_files_properties( ../common/single_top.cpp PROPERTIES COMPILE_DEFINITIONS "TOP_FRAME=PCB_FRAME_TYPE;PGM_DATA_FILE_EXT=\"kicad_pcb\";BUILD_KIWAY_DLL" @@ -527,7 +528,7 @@ if( USE_KIWAY_DLLS ) ${PCBNEW_SRCS} ${PCBNEW_COMMON_SRCS} ${PCBNEW_SCRIPTING_SRCS} - ${PCBNEW_RESOURCES} +# ${PCBNEW_RESOURCES} ) set_target_properties( pcbnew_kiface PROPERTIES # Decorate OUTPUT_NAME with PREFIX and SUFFIX, creating something like diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 25ae74fa72..32b1569589 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -325,7 +326,11 @@ static bool scriptingSetup() const wxString python_us( "python27_us" ); // Build our python path inside kicad - wxString kipython = m_BinDir + python_us; + wxString kipython = FindKicadFile( python_us + wxT("/python.exe") ); + + //we need only the path: + wxFileName fn( kipython ); + kipython = fn.GetPath(); // If our python install is existing inside kicad, use it if( wxDirExists( kipython ) ) From 1c232f5608ad737c32f9db8aeaac2b33a59c7c14 Mon Sep 17 00:00:00 2001 From: Marco Serantoni Date: Sat, 22 Mar 2014 12:35:33 +0100 Subject: [PATCH 33/46] [MacOSX] Support for kiface in bundles, workaround for some cairo issues --- CMakeModules/download_cairo.cmake | 7 ++++--- cvpcb/CMakeLists.txt | 9 +++++++++ eeschema/CMakeLists.txt | 9 +++++++++ gerbview/CMakeLists.txt | 9 +++++++++ pcb_calculator/CMakeLists.txt | 9 +++++++++ pcbnew/CMakeLists.txt | 9 +++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/CMakeModules/download_cairo.cmake b/CMakeModules/download_cairo.cmake index 26ab53e3e9..2d8b30eb98 100644 --- a/CMakeModules/download_cairo.cmake +++ b/CMakeModules/download_cairo.cmake @@ -103,6 +103,7 @@ ExternalProject_Add( cairo ) # match these with whatever FindCairo.cmake sets -set( CAIRO_FOUND true ) -set( CAIRO_INCLUDE_DIR ${PREFIX}/include ) -set( CAIRO_CAIRO_LIBRARIES ${PREFIX}/lib ) +# Dick i'vent set it because /lib and /lib64 issue in non multiarch binaries OSs +#set( CAIRO_FOUND true ) +set( CAIRO_INCLUDE_DIR ${CAIRO_ROOT}/include ) +set( CAIRO_LIBRARIES ${CAIRO_ROOT}/lib ) diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index de080fbf89..aa04eb2f5c 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -171,6 +171,15 @@ if( USE_KIWAY_DLLS ) COMPONENT binary ) + if( APPLE ) + # copies kiface into the bundle + add_custom_target( _cvpcb_kiface_copy ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/cvpcb/_cvpcb.kiface "${CMAKE_BINARY_DIR}/cvpcb/cvpcb.app/Contents/MacOS/" + DEPENDS cvpcb_kiface + COMMENT "Copying kiface into cvpcb" + ) + endif() + else() add_executable( cvpcb WIN32 MACOSX_BUNDLE diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 9ae138f429..bd04eebb7d 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -312,6 +312,15 @@ if( USE_KIWAY_DLLS ) COMPONENT binary ) + if( APPLE ) + # copies kiface into the bundle + add_custom_target( _eeschema_kiface_copy ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/eeschema/_eeschema.kiface "${CMAKE_BINARY_DIR}/eeschema/eeschema.app/Contents/MacOS/" + DEPENDS eeschema_kiface + COMMENT "Copying kiface into eeschema" + ) + endif() + else() add_executable( eeschema WIN32 MACOSX_BUNDLE ../common/single_top.cpp diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index 82e27ca1aa..685c826a1d 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -151,6 +151,15 @@ if( USE_KIWAY_DLLS ) COMPONENT binary ) + if( APPLE ) + # copies kiface into the bundle + add_custom_target( _gerbview_kiface_copy ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/gerbview/_gerbview.kiface "${CMAKE_BINARY_DIR}/gerbview/gerbview.app/Contents/MacOS/" + DEPENDS gerbview_kiface + COMMENT "Copying kiface into gerbview" + ) + endif() + else() add_executable( gerbview WIN32 MACOSX_BUNDLE diff --git a/pcb_calculator/CMakeLists.txt b/pcb_calculator/CMakeLists.txt index 51f1e21c66..fb8e189859 100644 --- a/pcb_calculator/CMakeLists.txt +++ b/pcb_calculator/CMakeLists.txt @@ -134,6 +134,15 @@ if( USE_KIWAY_DLLS ) ) endif() + if( APPLE ) + # copies kiface into the bundle + add_custom_target( _pcb_calculator_kiface_copy ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/pcb_calculator/_pcb_calculator.kiface "${CMAKE_BINARY_DIR}/pcb_calculator/pcb_calculator.app/Contents/MacOS/" + DEPENDS pcb_calculator_kiface + COMMENT "Copying kiface into pcb_calculator" + ) + endif() + else() add_executable( pcb_calculator WIN32 MACOSX_BUNDLE diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index d4fe33441d..ca49ce6f64 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -580,6 +580,15 @@ if( USE_KIWAY_DLLS ) COMPONENT binary ) + if( APPLE ) + # copies kiface into the bundle + add_custom_target( _pcbnew_kiface_copy ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/pcbnew/_pcbnew.kiface "${CMAKE_BINARY_DIR}/pcbnew/pcbnew.app/Contents/MacOS/" + DEPENDS pcbnew_kiface + COMMENT "Copying kiface into pcbnew" + ) + endif() + else() # milestone A) kills this off: add_executable( pcbnew WIN32 MACOSX_BUNDLE From 2db6c2c929a9870e36a1b2a7eb126fc951ac354e Mon Sep 17 00:00:00 2001 From: Marco Serantoni Date: Sun, 23 Mar 2014 02:50:33 +0100 Subject: [PATCH 34/46] [MacOSX] forgot pl_editor, thanks Jean-Paul for pointing it --- pagelayout_editor/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pagelayout_editor/CMakeLists.txt b/pagelayout_editor/CMakeLists.txt index e59bde050e..95ce1af27f 100644 --- a/pagelayout_editor/CMakeLists.txt +++ b/pagelayout_editor/CMakeLists.txt @@ -113,6 +113,14 @@ if( USE_KIWAY_DLLS ) COMPONENT binary ) + if( APPLE ) + # copies kiface into the bundle + add_custom_target( _pleditor_kiface_copy ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/pagelayout_editor/_pl_editor.kiface "${CMAKE_BINARY_DIR}/pagelayout_editor/pl_editor.app/Contents/MacOS/" + DEPENDS pl_editor_kiface + COMMENT "Copying kiface into pleditor" + ) + endif() else() From f1ee6de0251901a9622dfdc8197a8ae24178d7fc Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sun, 23 Mar 2014 07:44:15 +0100 Subject: [PATCH 35/46] Eeschema: does not close when the schematic file given in command line to run Eeschema is not found (i.e. when starting a new project). Otherwise one cannot start a new schematic project. --- eeschema/files-io.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 8e83cdc524..f7c91d6570 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -376,7 +376,9 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in msg.Printf( _( "File '%s' not found." ), GetChars( g_RootSheet->GetScreen()->GetFileName() ) ); DisplayInfoMessage( this, msg ); - return false; +// return false; + return true; // do not close Eeschema if the file if not found: + // we may have to create a new schematic file. } // load the project. @@ -392,7 +394,9 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in SetSheetNumberAndCount(); m_canvas->Refresh( true ); - return diag; +// return diag; + return true; // do not close Eeschema if the file if not found: + // we may have to create a new schematic file. } From 34c593916c6fcbaf43696def8bd52e9ccc573cce Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Thu, 27 Mar 2014 18:45:05 +0100 Subject: [PATCH 36/46] Pcbnew: Fix bug #1296649 (Text on flipped modules incorrectly placed). Dialog Freeroute: if freeroute.jar is find in kicad binaries, it is run as a standard java application, not as web applcation Very minor other fixes FPC_(SMD_type)_footprintwizard.py wizard finished. --- include/wxPcbStruct.h | 14 ++- pcbnew/class_module.cpp | 2 +- pcbnew/dialogs/dialog_freeroute_exchange.cpp | 95 ++++++++++++++++--- pcbnew/dialogs/dialog_freeroute_exchange.h | 3 +- pcbnew/scripting/pcbnew_footprint_wizards.cpp | 2 + .../plugins/FPC_(SMD_type)_footprintwizard.py | 79 +++++++++++++-- pcbnew/specctra_export.cpp | 9 +- scripting/wx_python_helpers.cpp | 6 ++ 8 files changed, 184 insertions(+), 26 deletions(-) diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index df6116ccfb..6498d7f0f3 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -972,12 +972,20 @@ public: /** * Function ExporttoSPECCTRA - * will export the current BOARD to a specctra dsn file. See - * See http://www.autotraxeda.com/docs/SPECCTRA/SPECCTRA.pdf for the - * specification. + * Ask for a filename and call ExportSpecctraFile to export the current BOARD + * to a specctra dsn file. */ void ExportToSpecctra( wxCommandEvent& event ); + /** + * Function ExportSpecctraFile + * will export the current BOARD to a specctra dsn file. + * See http://www.autotraxeda.com/docs/SPECCTRA/SPECCTRA.pdf for the + * specification. + * @return true if OK + */ + bool ExportSpecctraFile( const wxString& aFullFilename ); + /** * Function ImportSpecctraSession * will import a specctra *.ses file and use it to relocate MODULEs and diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index b8b4853b46..26527c095a 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -892,7 +892,7 @@ void MODULE::Flip( const wxPoint& aCentre ) case PCB_MODULE_TEXT_T: text = (TEXTE_MODULE*) item; text->m_Pos.y -= m_Pos.y; - NEGATE( text->m_Pos0.y ); + NEGATE( text->m_Pos.y ); text->m_Pos.y += m_Pos.y; NEGATE( text->m_Pos0.y ); NEGATE_AND_NORMALIZE_ANGLE_POS( text->m_Orient ); diff --git a/pcbnew/dialogs/dialog_freeroute_exchange.cpp b/pcbnew/dialogs/dialog_freeroute_exchange.cpp index 81608d3276..fa765b7dcd 100644 --- a/pcbnew/dialogs/dialog_freeroute_exchange.cpp +++ b/pcbnew/dialogs/dialog_freeroute_exchange.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include <../common/dialogs/dialog_display_info_HTML_base.h> @@ -76,6 +77,7 @@ void DIALOG_FREEROUTE::MyInit() { SetFocus(); m_FreeRouteSetupChanged = false; + m_freeRouterIsLocal = false; wxString msg; @@ -87,6 +89,14 @@ void DIALOG_FREEROUTE::MyInit() m_FreerouteURLName->SetValue( wxT( "http://www.freerouting.net/" ) ); else m_FreerouteURLName->SetValue( msg ); + + wxFileName fileName( FindKicadFile( wxT( "freeroute.jar" ) ), wxPATH_UNIX ); + + if( fileName.FileExists() ) + { + m_freeRouterIsLocal = true; + m_buttonLaunchFreeroute->SetLabel( _("Create .dsn File and Launch FreeRouter") ); + } } const char * s_FreeRouteHelpInfo = @@ -116,7 +126,7 @@ void DIALOG_FREEROUTE::OnImportButtonClick( wxCommandEvent& event ) { m_Parent->ImportSpecctraSession( event ); - /* Connectivity inf must be rebuild. + /* Connectivity must be rebuild. * because for large board it can take some time, this is made only on demand */ if( IsOK( this, _("Do you want to rebuild connectivity data ?" ) ) ) @@ -128,13 +138,23 @@ void DIALOG_FREEROUTE::OnImportButtonClick( wxCommandEvent& event ) */ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) { + wxString javaCommand; + + if( m_freeRouterIsLocal ) + { + javaCommand = CmdRunFreeRouterLocal(); + + if( javaCommand.IsEmpty() ) // Something is wrong + return; + } + else + javaCommand = wxT( "javaws" ); + wxString url; - wxString command; wxFileName fileName( FindKicadFile( wxT( "freeroute.jnlp" ) ), wxPATH_UNIX ); - if( fileName.FileExists() ) + if( m_freeRouterIsLocal || fileName.FileExists() ) { - wxString javaWebStartCommand = wxT( "javaws" ); // Find the Java web start application on Windows. #ifdef __WINDOWS__ @@ -145,13 +165,20 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) // Windows and the build version of KiCad. // This key works for 32 bit Java on 32 bit Windows and 64 bit Java on 64 bit Windows. - wxRegKey key( wxRegKey::HKLM, wxT( "SOFTWARE\\JavaSoft\\Java Web Start" ), + wxString keyName = m_freeRouterIsLocal ? wxT( "SOFTWARE\\JavaSoft\\Java Runtime Environment" ) + : wxT( "SOFTWARE\\JavaSoft\\Java Web Start" ); + wxRegKey key( wxRegKey::HKLM, keyName, wxIsPlatform64Bit() ? wxRegKey::WOW64ViewMode_64 : wxRegKey::WOW64ViewMode_Default ); // It's possible that 32 bit Java is installed on 64 bit Windows. if( !key.Exists() && wxIsPlatform64Bit() ) - key.SetName( wxRegKey::HKLM, wxT( "SOFTWARE\\Wow6432Node\\JavaSoft\\Java Web Start" ) ); + { + keyName = m_freeRouterIsLocal ? + wxT( "SOFTWARE\\Wow6432Node\\JavaSoft\\Java Runtime Environment" ) + : wxT( "SOFTWARE\\Wow6432Node\\JavaSoft\\Java Web Start" ); + key.SetName( wxRegKey::HKLM, keyName ); + } if( !key.Exists() ) { @@ -168,17 +195,24 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) wxString value; key.QueryValue( wxT( "CurrentVersion" ), value ); key.SetName( key.GetName() + wxT( "\\" ) + value ); - key.QueryValue( wxT( "Home" ), value ); - javaWebStartCommand = value + wxFileName::GetPathSeparator() + javaWebStartCommand; + + key.QueryValue( m_freeRouterIsLocal ? wxT( "JavaHome" ) : wxT( "Home" ), value ); + wxString javaCommandPath = value + wxFileName::GetPathSeparator(); #else #warning Kicad needs wxWidgets >= 2.9.4. version 2.8 is only supported for testing purposes #endif // wxCHECK_VERSION( 2, 9, 0 ) #endif // __WINDOWS__ - // Wrap FullFileName in double quotes in case it has C:\Program Files in it. - // The space is interpreted as an argument separator. - command << javaWebStartCommand << wxChar( ' ' ) << wxChar( '"' ) - << fileName.GetFullPath() << wxChar( '"' ); + wxString command = javaCommandPath; + + if( m_freeRouterIsLocal ) + command << wxT("bin\\") << javaCommand; + else + // Wrap FullFileName in double quotes in case it has C:\Program Files in it. + // The space is interpreted as an argument separator. + command << javaCommand << wxChar( ' ' ) << wxChar( '"' ) + << fileName.GetFullPath() << wxChar( '"' ); + ProcessExecute( command ); return; } @@ -188,6 +222,43 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) wxLaunchDefaultBrowser( url ); } +wxString DIALOG_FREEROUTE::CmdRunFreeRouterLocal() +{ + wxString fullFileName = m_Parent->GetBoard()->GetFileName(); + wxString path; + wxString name; + wxString ext; + wxString dsn_ext = wxT( ".dsn" ); + wxString mask = wxT( "*" ) + dsn_ext; + + wxFileName::SplitPath( fullFileName, &path, &name, &ext ); + + name += dsn_ext; + + fullFileName = EDA_FileSelector( _( "Specctra DSN file:" ), + path, + name, // name.ext without path! + dsn_ext, + mask, + this, + wxFD_SAVE, + false + ); + + if( fullFileName == wxEmptyString ) + return fullFileName; + + if( ! m_Parent->ExportSpecctraFile( fullFileName ) ) // the file was not created + return fullFileName; + + wxFileName jarfileName( FindKicadFile( wxT( "freeroute.jar" ) ), wxPATH_UNIX ); + + wxString command = wxT("java -jar "); + command << wxChar( '"' ) << jarfileName.GetFullPath() << wxT( "\" -de " ); + command << wxChar( '"' ) << fullFileName << wxChar( '"' ); + + return command; +} /* wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BUTTON */ diff --git a/pcbnew/dialogs/dialog_freeroute_exchange.h b/pcbnew/dialogs/dialog_freeroute_exchange.h index 0f1e6f97ff..e9646060f0 100644 --- a/pcbnew/dialogs/dialog_freeroute_exchange.h +++ b/pcbnew/dialogs/dialog_freeroute_exchange.h @@ -16,6 +16,7 @@ class DIALOG_FREEROUTE : public DIALOG_FREEROUTE_BASE private: PCB_EDIT_FRAME* m_Parent; bool m_FreeRouteSetupChanged; + bool m_freeRouterIsLocal; private: // Virtual event handlers @@ -28,7 +29,7 @@ private: void OnCancelButtonClick( wxCommandEvent& event ); void OnTextEditFrUrlUpdated( wxCommandEvent& event ); void MyInit ( ); - + wxString CmdRunFreeRouterLocal(); public: DIALOG_FREEROUTE( PCB_EDIT_FRAME* parent ); diff --git a/pcbnew/scripting/pcbnew_footprint_wizards.cpp b/pcbnew/scripting/pcbnew_footprint_wizards.cpp index 8b74d4ac70..70e2238d34 100644 --- a/pcbnew/scripting/pcbnew_footprint_wizards.cpp +++ b/pcbnew/scripting/pcbnew_footprint_wizards.cpp @@ -81,7 +81,9 @@ PyObject* PYTHON_FOOTPRINT_WIZARD::CallMethod( const char* aMethod, PyObject* aA } if( pFunc ) + { Py_XDECREF( pFunc ); + } return NULL; } diff --git a/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py b/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py index 0cace0dfb1..f751c47f38 100644 --- a/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py +++ b/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py @@ -104,10 +104,13 @@ class FPCFootprintWizard(FootprintWizardPlugin): module.Add(pad) + # Mechanical shield pads: left pad and right pad xpos = -shl_to_pad-offsetX - pad_s0 = self.smdRectPad(module, size_shld, wxPoint(xpos,shl_from_top), "0") + pad_s0_pos = wxPoint(xpos,shl_from_top) + pad_s0 = self.smdRectPad(module, size_shld, pad_s0_pos, "0") xpos = (pads-1)*pad_pitch+shl_to_pad-offsetX - pad_s1 = self.smdRectPad(module, size_shld, wxPoint(xpos,shl_from_top), "0") + pad_s1_pos = wxPoint(xpos,shl_from_top) + pad_s1 = self.smdRectPad(module, size_shld, pad_s1_pos, "0") module.Add(pad_s0) module.Add(pad_s1) @@ -115,21 +118,81 @@ class FPCFootprintWizard(FootprintWizardPlugin): #add outline outline = EDGE_MODULE(module) linewidth = FromMM(0.2) - posy = -pad_height/2 - linewidth/2 -FromMM(0.2) - outline.SetStartEnd(wxPoint(pad_pitch * pads - pad_pitch*0.5-offsetX, posy), - wxPoint( - pad_pitch*0.5-offsetX, posy)) outline.SetWidth(linewidth) + margin = FromMM(0.2) + + # upper line + posy = -pad_height/2 - linewidth/2 - margin + xstart = - pad_pitch*0.5-offsetX + xend = pad_pitch * pads + xstart; + outline.SetStartEnd( wxPoint(xstart, posy), wxPoint( xend, posy) ) outline.SetLayer(SILKSCREEN_N_FRONT) #default: not needed outline.SetShape(S_SEGMENT) module.Add(outline) + # lower line outline1 = EDGE_MODULE(module) outline1.Copy(outline) #copy all settings from outline - posy = pad_height/2 + linewidth/2 +FromMM(0.2) - outline1.SetStartEnd(wxPoint(pad_pitch * pads - pad_pitch*0.5-offsetX, posy), - wxPoint( - pad_pitch*0.5-offsetX, posy)) + posy = pad_height/2 + linewidth/2 + margin + outline1.SetStartEnd(wxPoint(xstart, posy), wxPoint( xend, posy)) module.Add(outline1) + # around left mechanical pad (the outline around right pad is mirrored/y axix) + outline2 = EDGE_MODULE(module) # vertical segment + outline2.Copy(outline) + yend = pad_s0_pos.y + shl_height/2 + margin + outline2.SetStartEnd(wxPoint(xstart, posy), wxPoint( xstart, yend)) + module.Add(outline2) + outline2_d = EDGE_MODULE(module) # right pad side + outline2_d.Copy(outline2) + outline2_d.SetStartEnd(wxPoint(-xstart, posy), wxPoint( -xstart, yend)) + module.Add(outline2_d) + + outline3 = EDGE_MODULE(module) # horizontal segment below the pad + outline3.Copy(outline) + posy = yend + xend = pad_s0_pos.x - (shl_width/2 + linewidth + margin*2) + outline3.SetStartEnd(wxPoint(xstart, posy), wxPoint( xend, posy)) + module.Add(outline3) + outline3_d = EDGE_MODULE(module) # right pad side + outline3_d.Copy(outline3) + outline3_d.SetStartEnd(wxPoint(-xstart, posy), wxPoint( -xend, yend)) + module.Add(outline3_d) + + outline4 = EDGE_MODULE(module) # vertical segment at left of the pad + outline4.Copy(outline) + xstart = xend + yend = posy - (shl_height + linewidth + margin*2) + outline4.SetStartEnd(wxPoint(xstart, posy), wxPoint( xend, yend)) + module.Add(outline4) + outline4_d = EDGE_MODULE(module) # right pad side + outline4_d.Copy(outline4) + outline4_d.SetStartEnd(wxPoint(-xstart, posy), wxPoint( -xend, yend)) + module.Add(outline4_d) + + outline5 = EDGE_MODULE(module) # horizontal segment above the pad + outline5.Copy(outline) + xstart = xend + xend = - pad_pitch*0.5-offsetX + posy = yend + outline5.SetStartEnd(wxPoint(xstart, posy), wxPoint( xend, yend)) + module.Add(outline5) + outline5_d = EDGE_MODULE(module) # right pad side + outline5_d.Copy(outline5) + outline5_d.SetStartEnd(wxPoint(-xstart, posy), wxPoint( -xend, yend)) + module.Add(outline5_d) + + outline6 = EDGE_MODULE(module) # vertical segment above the pad + outline6.Copy(outline) + xstart = xend + yend = -pad_height/2 - linewidth/2 - margin + outline6.SetStartEnd(wxPoint(xstart, posy), wxPoint( xend, yend)) + module.Add(outline6) + outline6_d = EDGE_MODULE(module) # right pad side + outline6_d.Copy(outline6) + outline6_d.SetStartEnd(wxPoint(-xstart, posy), wxPoint( -xend, yend)) + module.Add(outline6_d) + # create our footprint wizard fpc_wizard = FPCFootprintWizard() diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index e348c45c82..c9a85591d6 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -132,6 +132,11 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) if( fullFileName == wxEmptyString ) return; + ExportSpecctraFile( fullFileName ); +} + +bool PCB_EDIT_FRAME::ExportSpecctraFile( const wxString& aFullFilename ) +{ SPECCTRA_DB db; bool ok = true; wxString errorText; @@ -152,7 +157,7 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) { GetBoard()->SynchronizeNetsAndNetClasses(); db.FromBOARD( GetBoard() ); - db.ExportPCB( fullFileName, true ); + db.ExportPCB( aFullFilename, true ); // if an exception is thrown by FromBOARD or ExportPCB(), then // ~SPECCTRA_DB() will close the file. @@ -184,6 +189,8 @@ void PCB_EDIT_FRAME::ExportToSpecctra( wxCommandEvent& event ) errorText += _( "Unable to export, please fix and try again." ); DisplayError( this, errorText ); } + + return ok; } diff --git a/scripting/wx_python_helpers.cpp b/scripting/wx_python_helpers.cpp index a97314b355..8ee7bba28b 100644 --- a/scripting/wx_python_helpers.cpp +++ b/scripting/wx_python_helpers.cpp @@ -102,10 +102,14 @@ wxString* newWxStringFromPy( PyObject* src ) } if( must_unref_str ) + { Py_DECREF( uni_str ); + } if( must_unref_obj ) + { Py_DECREF( obj ); + } #else // normal string (or object) to normal python string @@ -136,7 +140,9 @@ wxString* newWxStringFromPy( PyObject* src ) result = new wxString( str_ptr, str_size ); if( must_unref_str ) + { Py_DECREF( str ); + } #endif From 04492587611d2e7480bf220218d9db63dffab3a2 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Thu, 27 Mar 2014 19:28:10 +0100 Subject: [PATCH 37/46] Fix (temporary fix) a bug I created in dialog_freeroute_exchange.cpp in bzr rev 4769 --- pcbnew/dialogs/dialog_freeroute_exchange.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcbnew/dialogs/dialog_freeroute_exchange.cpp b/pcbnew/dialogs/dialog_freeroute_exchange.cpp index fa765b7dcd..e3835adfcf 100644 --- a/pcbnew/dialogs/dialog_freeroute_exchange.cpp +++ b/pcbnew/dialogs/dialog_freeroute_exchange.cpp @@ -139,6 +139,7 @@ void DIALOG_FREEROUTE::OnImportButtonClick( wxCommandEvent& event ) void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) { wxString javaCommand; + wxString command; if( m_freeRouterIsLocal ) { @@ -198,13 +199,12 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) key.QueryValue( m_freeRouterIsLocal ? wxT( "JavaHome" ) : wxT( "Home" ), value ); wxString javaCommandPath = value + wxFileName::GetPathSeparator(); + command = javaCommandPath; #else #warning Kicad needs wxWidgets >= 2.9.4. version 2.8 is only supported for testing purposes #endif // wxCHECK_VERSION( 2, 9, 0 ) #endif // __WINDOWS__ - wxString command = javaCommandPath; - if( m_freeRouterIsLocal ) command << wxT("bin\\") << javaCommand; else From 47b5bdcd4719789855e1f8c4384a5333da16d1a1 Mon Sep 17 00:00:00 2001 From: Jean-Samuel Reynaud Date: Fri, 28 Mar 2014 07:27:58 -0500 Subject: [PATCH 38/46] Fix a mismatch between method signature in scripting/python_scripting.cpp and scripting/python_scripting.h --- pcbnew/pcbnew.cpp | 2 -- scripting/python_scripting.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pcbnew/pcbnew.cpp b/pcbnew/pcbnew.cpp index 32b1569589..a8eac6b21a 100644 --- a/pcbnew/pcbnew.cpp +++ b/pcbnew/pcbnew.cpp @@ -483,9 +483,7 @@ void IFACE::OnKifaceEnd() // wxPython will do its own cleanup as part of that process. // This should only be called if python was setup correctly. -/* bring this in, but without a linker error: pcbnewFinishPythonScripting(); -*/ #endif } diff --git a/scripting/python_scripting.cpp b/scripting/python_scripting.cpp index 31a725d8e8..494195cf3d 100644 --- a/scripting/python_scripting.cpp +++ b/scripting/python_scripting.cpp @@ -172,7 +172,7 @@ bool pcbnewInitPythonScripting( const char * aUserPluginsPath ) } -void pcbnewFinishPythonScripting( char ) +void pcbnewFinishPythonScripting() { #ifdef KICAD_SCRIPTING_WXPYTHON wxPyEndAllowThreads( g_PythonMainTState ); From 44e1f4fa2d70def8884e44c5392d39f3a1962c0b Mon Sep 17 00:00:00 2001 From: cdelbegu Date: Fri, 28 Mar 2014 14:06:30 +0100 Subject: [PATCH 39/46] Pcbnew - GAL: fix bug #1296811 (The grid can't be enable/disable via the layer manager) --- pcbnew/class_pcb_layer_widget.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pcbnew/class_pcb_layer_widget.cpp b/pcbnew/class_pcb_layer_widget.cpp index 82ab8237f7..12f28370a5 100644 --- a/pcbnew/class_pcb_layer_widget.cpp +++ b/pcbnew/class_pcb_layer_widget.cpp @@ -49,6 +49,8 @@ #include #include +#include + /// This is a read only template that is copied and modified before adding to LAYER_WIDGET const LAYER_WIDGET::ROW PCB_LAYER_WIDGET::s_render_rows[] = { @@ -420,8 +422,13 @@ void PCB_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled ) EDA_DRAW_PANEL_GAL* galCanvas = myframe->GetGalCanvas(); if( galCanvas ) { - KIGFX::VIEW* view = galCanvas->GetView(); - view->SetLayerVisible( ITEM_GAL_LAYER( aId ), isEnabled ); + if( aId == GRID_VISIBLE ) + { + galCanvas->GetGAL()->SetGridVisibility( myframe->IsGridVisible() ); + galCanvas->GetView()->MarkTargetDirty( KIGFX::TARGET_NONCACHED ); + } + else + galCanvas->GetView()->SetLayerVisible( ITEM_GAL_LAYER( aId ), isEnabled ); } if( galCanvas && myframe->IsGalCanvasActive() ) From 36e62b1047df85364f369ebee88be7ec3bbc519d Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Fri, 28 Mar 2014 14:08:48 +0100 Subject: [PATCH 40/46] Eeschema: fix Bug #1298868 (Can't create new schematic from main toolbar icon) --- eeschema/files-io.cpp | 18 +++++++++++------- eeschema/schframe.cpp | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index f7c91d6570..54897bd5e5 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -368,20 +368,24 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in // Delete old caches. CMP_LIBRARY::RemoveCacheLibrary(); - libCacheExist = LoadCacheLibrary( g_RootSheet->GetScreen()->GetFileName() ); - - if( !wxFileExists( g_RootSheet->GetScreen()->GetFileName() ) && !libCacheExist ) + if( !wxFileExists( g_RootSheet->GetScreen()->GetFileName() ) ) { Zoom_Automatique( false ); - msg.Printf( _( "File '%s' not found." ), - GetChars( g_RootSheet->GetScreen()->GetFileName() ) ); - DisplayInfoMessage( this, msg ); -// return false; + + if( aCtl == 0 ) + { + msg.Printf( _( "File '%s' not found." ), + GetChars( g_RootSheet->GetScreen()->GetFileName() ) ); + DisplayInfoMessage( this, msg ); + return false; + } + return true; // do not close Eeschema if the file if not found: // we may have to create a new schematic file. } // load the project. + libCacheExist = LoadCacheLibrary( g_RootSheet->GetScreen()->GetFileName() ); g_RootSheet->SetScreen( NULL ); bool diag = g_RootSheet->Load( this ); SetScreen( m_CurrentSheet->LastScreen() ); diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp index 1a1995f5a5..fa7cb5c5df 100644 --- a/eeschema/schframe.cpp +++ b/eeschema/schframe.cpp @@ -730,13 +730,13 @@ void SCH_EDIT_FRAME::OnLoadCmpToFootprintLinkFile( wxCommandEvent& event ) void SCH_EDIT_FRAME::OnNewProject( wxCommandEvent& event ) { - wxFileDialog dlg( this, _( "Open Schematic" ), wxGetCwd(), + wxFileDialog dlg( this, _( "New Schematic" ), wxGetCwd(), wxEmptyString, SchematicFileWildcard, - wxFD_OPEN | wxFD_FILE_MUST_EXIST ); + wxFD_SAVE ); if( dlg.ShowModal() != wxID_CANCEL ) { - OpenProjectFiles( std::vector( 1, dlg.GetPath() ) ); + OpenProjectFiles( std::vector( 1, dlg.GetPath() ), 1 ); } } From beb33c75229172174b685b5e4573ab0df177aece Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Fri, 28 Mar 2014 14:23:26 +0100 Subject: [PATCH 41/46] Eeschema: fix Bug #1298868 (Can't create new schematic from main toolbar icon) - Fix a bug I created in rev 4773 --- eeschema/files-io.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 54897bd5e5..a94761d038 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -377,7 +377,6 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in msg.Printf( _( "File '%s' not found." ), GetChars( g_RootSheet->GetScreen()->GetFileName() ) ); DisplayInfoMessage( this, msg ); - return false; } return true; // do not close Eeschema if the file if not found: From 6d0c5555ea5e38d8f0591513281486c87b170eec Mon Sep 17 00:00:00 2001 From: Lorenzo Marcantonio Date: Sat, 29 Mar 2014 12:22:20 +0100 Subject: [PATCH 42/46] Indentation was completely broken (editor tabbing issue, maybe?) --- pcbnew/exporters/export_d356.cpp | 80 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/pcbnew/exporters/export_d356.cpp b/pcbnew/exporters/export_d356.cpp index b5d0b11d48..865986acc9 100644 --- a/pcbnew/exporters/export_d356.cpp +++ b/pcbnew/exporters/export_d356.cpp @@ -50,14 +50,14 @@ * Useful because 356A (when implemented) must be sorted before outputting it */ struct D356_RECORD { - bool smd; - bool hole; - wxString netname; - wxString refdes; - wxString pin; - bool midpoint; + bool smd; + bool hole; + wxString netname; + wxString refdes; + wxString pin; + bool midpoint; int drill; - bool mechanical; + bool mechanical; int access; // Access 0 is 'both sides' int soldermask; // All these in PCB units, will be output in decimils @@ -74,19 +74,19 @@ static int compute_pad_access_code( BOARD *aPcb, LAYER_MSK aLayerMask ) // Non-copper is not interesting here aLayerMask &= ALL_CU_LAYERS; if( aLayerMask == 0 ) - return -1; + return -1; // Traditional TH pad if( (aLayerMask & LAYER_FRONT) && (aLayerMask & LAYER_BACK) ) - return 0; + return 0; // Front SMD pad if( (aLayerMask & LAYER_FRONT) ) - return 1; + return 1; // Back SMD pad if( (aLayerMask & LAYER_BACK) ) - return aPcb->GetCopperLayerCount(); + return aPcb->GetCopperLayerCount(); // OK, we have an inner-layer only pad (and I have no idea about // what could be used for); anyway, find the first copper layer @@ -129,36 +129,36 @@ static void build_pad_testpoints( BOARD *aPcb, // It could be a mask only pad, we only handle pads with copper here if( rk.access != -1 ) { - rk.netname = pad->GetNetname(); - rk.refdes = module->GetReference(); - pad->StringPadName( rk.pin ); - rk.midpoint = false; // XXX MAYBE need to be computed (how?) - const wxSize& drill = pad->GetDrillSize(); - rk.drill = std::min( drill.x, drill.y ); - rk.hole = (rk.drill != 0); - rk.smd = pad->GetAttribute() == PAD_SMD; - rk.mechanical = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED); - rk.x_location = pad->GetPosition().x - origin.x; - rk.y_location = origin.y - pad->GetPosition().y; - rk.x_size = pad->GetSize().x; + rk.netname = pad->GetNetname(); + rk.refdes = module->GetReference(); + pad->StringPadName( rk.pin ); + rk.midpoint = false; // XXX MAYBE need to be computed (how?) + const wxSize& drill = pad->GetDrillSize(); + rk.drill = std::min( drill.x, drill.y ); + rk.hole = (rk.drill != 0); + rk.smd = pad->GetAttribute() == PAD_SMD; + rk.mechanical = (pad->GetAttribute() == PAD_HOLE_NOT_PLATED); + rk.x_location = pad->GetPosition().x - origin.x; + rk.y_location = origin.y - pad->GetPosition().y; + rk.x_size = pad->GetSize().x; - // Rule: round pads have y = 0 - if( pad->GetShape() == PAD_CIRCLE ) - rk.y_size = 0; - else - rk.y_size = pad->GetSize().y; + // Rule: round pads have y = 0 + if( pad->GetShape() == PAD_CIRCLE ) + rk.y_size = 0; + else + rk.y_size = pad->GetSize().y; - rk.rotation = -KiROUND( pad->GetOrientation() ) / 10; - if( rk.rotation < 0 ) rk.rotation += 360; + rk.rotation = -KiROUND( pad->GetOrientation() ) / 10; + if( rk.rotation < 0 ) rk.rotation += 360; - // the value indicates which sides are *not* accessible - rk.soldermask = 3; - if( pad->GetLayerMask() & SOLDERMASK_LAYER_FRONT) - rk.soldermask &= ~1; - if( pad->GetLayerMask() & SOLDERMASK_LAYER_BACK) - rk.soldermask &= ~2; + // the value indicates which sides are *not* accessible + rk.soldermask = 3; + if( pad->GetLayerMask() & SOLDERMASK_LAYER_FRONT) + rk.soldermask &= ~1; + if( pad->GetLayerMask() & SOLDERMASK_LAYER_BACK) + rk.soldermask &= ~2; - aRecords.push_back( rk ); + aRecords.push_back( rk ); } } } @@ -172,15 +172,15 @@ static int via_access_code( BOARD *aPcb, int top_layer, int bottom_layer ) // Easy case for through vias: top_layer is component, bottom_layer is // solder, access code is 0 if( (top_layer == LAYER_N_FRONT) && (bottom_layer == LAYER_N_BACK) ) - return 0; + return 0; // Blind via, reachable from front if( top_layer == LAYER_N_FRONT ) - return 1; + return 1; // Blind via, reachable from bottom if( bottom_layer == LAYER_N_BACK ) - return aPcb->GetCopperLayerCount(); + return aPcb->GetCopperLayerCount(); // It's a buried via, accessible from some inner layer // (maybe could be used for testing before laminating? no idea) From 121494d3d95aef960bf2e0059d538225118e1446 Mon Sep 17 00:00:00 2001 From: Lorenzo Marcantonio Date: Sat, 29 Mar 2014 18:34:13 +0100 Subject: [PATCH 43/46] Removed relic empty if --- common/pgm_base.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/common/pgm_base.cpp b/common/pgm_base.cpp index 36f573f097..e0af909af6 100644 --- a/common/pgm_base.cpp +++ b/common/pgm_base.cpp @@ -406,12 +406,7 @@ bool PGM_BASE::initPgm() loadCommonSettings(); - - bool succes = SetLanguage( true ); - - if( !succes ) - { - } + SetLanguage( true ); // Set locale option for separator used in float numbers SetLocaleTo_Default(); From 4e18b14f14fa7fb5b8020b732fd621ecaee7c888 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 29 Mar 2014 21:00:14 +0100 Subject: [PATCH 44/46] Finishing dialog_freeroute_exchange.cpp changes to run freeroute.jar if found in kicad binaries. Very minor other fix --- eeschema/class_netlist_object.cpp | 6 +++--- pcbnew/dialogs/dialog_freeroute_exchange.cpp | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/eeschema/class_netlist_object.cpp b/eeschema/class_netlist_object.cpp index 0b62b47dab..34c7333a47 100644 --- a/eeschema/class_netlist_object.cpp +++ b/eeschema/class_netlist_object.cpp @@ -259,7 +259,7 @@ void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItem i = busNumber.Find( '[' ); i++; - while( busNumber[i] != '.' && i < busNumber.Len() ) + while( i < busNumber.Len() && busNumber[i] != '.' ) { tmp.Append( busNumber[i] ); i++; @@ -267,12 +267,12 @@ void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItem tmp.ToLong( &begin ); - while( busNumber[i] == '.' && i < busNumber.Len() ) + while( i < busNumber.Len() && busNumber[i] == '.' ) i++; tmp.Empty(); - while( busNumber[i] != ']' && i < busNumber.Len() ) + while( i < busNumber.Len() && busNumber[i] != ']' ) { tmp.Append( busNumber[i] ); i++; diff --git a/pcbnew/dialogs/dialog_freeroute_exchange.cpp b/pcbnew/dialogs/dialog_freeroute_exchange.cpp index e3835adfcf..43755778d3 100644 --- a/pcbnew/dialogs/dialog_freeroute_exchange.cpp +++ b/pcbnew/dialogs/dialog_freeroute_exchange.cpp @@ -203,10 +203,14 @@ void DIALOG_FREEROUTE::OnLaunchButtonClick( wxCommandEvent& event ) #else #warning Kicad needs wxWidgets >= 2.9.4. version 2.8 is only supported for testing purposes #endif // wxCHECK_VERSION( 2, 9, 0 ) -#endif // __WINDOWS__ if( m_freeRouterIsLocal ) command << wxT("bin\\") << javaCommand; +#else // __WINDOWS__ + + if( m_freeRouterIsLocal ) + command << javaCommand; +#endif else // Wrap FullFileName in double quotes in case it has C:\Program Files in it. // The space is interpreted as an argument separator. @@ -254,7 +258,11 @@ wxString DIALOG_FREEROUTE::CmdRunFreeRouterLocal() wxFileName jarfileName( FindKicadFile( wxT( "freeroute.jar" ) ), wxPATH_UNIX ); wxString command = wxT("java -jar "); - command << wxChar( '"' ) << jarfileName.GetFullPath() << wxT( "\" -de " ); + // add "freeroute.jar" to command line: + command << wxChar( '"' ) << jarfileName.GetFullPath() << wxChar( '"' ); + // add option to load the .dsn file + command << wxT( " -de " ); + // add *.dsn full filename (quoted): command << wxChar( '"' ) << fullFileName << wxChar( '"' ); return command; From 4426d4c5391fdb83618933b2bac0547e2582ad6f Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Mon, 31 Mar 2014 20:14:01 +0200 Subject: [PATCH 45/46] Pcbnew: bug fix: sometimes (depending on a previous command) pcbnew could create an usual zone instead of a keepout zone when the" create keepout zone" tool is activated --- pcbnew/onrightclick.cpp | 6 +---- pcbnew/zones_by_polygon.cpp | 52 +++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index 59e6f3ff65..75d704a889 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -137,11 +137,7 @@ bool PCB_EDIT_FRAME::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu ) } item = GetCurItem(); - - if( item ) - flags = item->GetFlags(); - else - flags = 0; + flags = item ? item->GetFlags() : 0; // Add the context menu, which depends on the picked item: if( item ) diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index b92ddb7bf0..44f669fce8 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -206,8 +206,14 @@ static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC ) if( zone ) { zone->DrawWhileCreateOutline( Panel, DC, GR_XOR ); - zone->ClearFlags(); zone->RemoveAllContours(); + if( zone->IsNew() ) + { + delete zone; + pcbframe->GetBoard()->m_CurrentZoneContour = NULL; + } + else + zone->ClearFlags(); } pcbframe->SetCurItem( NULL ); @@ -512,21 +518,26 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) s_CurrentZone = NULL; } - // If no zone contour in progress, a new zone is being created: - if( !GetBoard()->m_CurrentZoneContour ) + ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour; + + // Verify if a new zone is allowed on this layer: + if( zone == NULL ) { - if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && - getActiveLayer() >= FIRST_NON_COPPER_LAYER ) + if( GetToolId() == ID_PCB_KEEPOUT_AREA_BUTT && !IsCopperLayer( getActiveLayer() ) ) { DisplayError( this, _( "Error: a keepout area is allowed only on copper layers" ) ); return 0; } - else - GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() ); } - ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour; + // If no zone contour in progress, a new zone is being created, + if( zone == NULL ) + { + zone = GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() ); + zone->SetFlags( IS_NEW ); + zone->SetTimeStamp( GetNewTimeStamp() ); + } if( zone->GetNumCorners() == 0 ) // Start a new contour: init zone params (net, layer ...) { @@ -546,30 +557,25 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) if( GetBoard()->GetHighLightNetCode() > 0 ) { zoneInfo.m_NetcodeSelection = GetBoard()->GetHighLightNetCode(); - zone->SetNetCode( zoneInfo.m_NetcodeSelection ); } + double tmp = ZONE_THERMAL_RELIEF_GAP_MIL; wxConfigBase* cfg = Kiface().KifaceSettings(); - cfg->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY, &tmp ); - zoneInfo.m_ThermalReliefGap = KiROUND( tmp * IU_PER_MILS); tmp = ZONE_THERMAL_RELIEF_COPPER_WIDTH_MIL; - cfg->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, - &tmp ); + cfg->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ThermalReliefCopperBridge = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_CLEARANCE_MIL; - cfg->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, - &tmp ); + cfg->Read( ZONE_CLEARANCE_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneClearance = KiROUND( tmp * IU_PER_MILS ); tmp = ZONE_THICKNESS_MIL; - cfg->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, - &tmp ); + cfg->Read( ZONE_MIN_THICKNESS_WIDTH_STRING_KEY, &tmp ); zoneInfo.m_ZoneMinThickness = KiROUND( tmp * IU_PER_MILS ); zoneInfo.m_CurrentZone_Layer = zone->GetLayer(); @@ -599,11 +605,14 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) m_canvas->SetIgnoreMouseEvents( false ); if( edited == ZONE_ABORT ) + { + GetBoard()->m_CurrentZoneContour = NULL; + delete zone; return 0; + } // Switch active layer to the selected zone layer setActiveLayer( zoneInfo.m_CurrentZone_Layer ); - SetZoneSettings( zoneInfo ); } else @@ -620,8 +629,8 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) } // Show the Net for zones on copper layers - if( zoneInfo.m_CurrentZone_Layer < FIRST_NON_COPPER_LAYER && - ! zoneInfo.GetIsKeepout() ) + if( IsCopperLayer( zoneInfo.m_CurrentZone_Layer ) && + !zoneInfo.GetIsKeepout() ) { if( s_CurrentZone ) { @@ -645,9 +654,6 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) // if first segment if( zone->GetNumCorners() == 0 ) { - zone->SetFlags( IS_NEW ); - zone->SetTimeStamp( GetNewTimeStamp() ); - zoneInfo.ExportSetting( *zone ); zone->Outline()->Start( zoneInfo.m_CurrentZone_Layer, From 4eec9fd013facaab9357dd500f24aa188e179b6b Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Mon, 31 Mar 2014 22:38:19 -0400 Subject: [PATCH 46/46] Fix OpenMP link error on MinGW. --- CMakeLists.txt | 7 +++++++ cvpcb/CMakeLists.txt | 1 + pcbnew/CMakeLists.txt | 2 ++ 3 files changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2d3d8f19d..e719d5c601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,10 +157,17 @@ if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) endif() find_package( OpenMP QUIET ) + if( OPENMP_FOUND ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" ) add_definitions( -DUSE_OPENMP ) + + # MinGW does not include the OpenMP link library and FindOpenMP.cmake does not + # set it either. Not sure this is the most elegant solution but it works. + if( MINGW ) + set( OPENMP_LIBRARIES gomp ) + endif() endif() if( MINGW ) diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index aa04eb2f5c..47a5c3c111 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -116,6 +116,7 @@ if( USE_KIWAY_DLLS ) ${GLEW_LIBRARIES} ${CAIRO_LIBRARIES} ${PIXMAN_LIBRARY} + ${OPENMP_LIBRARIES} ) # Only for win32 cross compilation using MXE diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index ca49ce6f64..5c1583d711 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -536,6 +536,7 @@ if( USE_KIWAY_DLLS ) OUTPUT_NAME pcbnew PREFIX ${KIFACE_PREFIX} SUFFIX ${KIFACE_SUFFIX} + COMPILE_FLAGS ${OpenMP_CXX_FLAGS} ) target_link_libraries( pcbnew_kiface 3d-viewer @@ -557,6 +558,7 @@ if( USE_KIWAY_DLLS ) ${PIXMAN_LIBRARY} ${Boost_LIBRARIES} # must follow GITHUB ${PCBNEW_EXTRA_LIBS} # -lrt must follow Boost + ${OPENMP_LIBRARIES} ) set_source_files_properties( pcbnew.cpp PROPERTIES # The KIFACE is in pcbnew.cpp, export it:

+^HZD2Y8kSBjj|G9f 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