You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
9.0 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <common.h>
  25. #include <page_info.h>
  26. #include <macros.h>
  27. #include <eda_units.h>
  28. #include <richio.h> // for OUTPUTFORMATTER and IO_ERROR
  29. // late arriving wxPAPER_A0, wxPAPER_A1
  30. #if wxABI_VERSION >= 20999
  31. #define PAPER_A0 wxPAPER_A0
  32. #define PAPER_A1 wxPAPER_A1
  33. #else
  34. #define PAPER_A0 wxPAPER_A2
  35. #define PAPER_A1 wxPAPER_A2
  36. #endif
  37. // Standard paper sizes nicknames.
  38. const wxChar PAGE_INFO::A5[] = wxT( "A5" );
  39. const wxChar PAGE_INFO::A4[] = wxT( "A4" );
  40. const wxChar PAGE_INFO::A3[] = wxT( "A3" );
  41. const wxChar PAGE_INFO::A2[] = wxT( "A2" );
  42. const wxChar PAGE_INFO::A1[] = wxT( "A1" );
  43. const wxChar PAGE_INFO::A0[] = wxT( "A0" );
  44. const wxChar PAGE_INFO::A[] = wxT( "A" );
  45. const wxChar PAGE_INFO::B[] = wxT( "B" );
  46. const wxChar PAGE_INFO::C[] = wxT( "C" );
  47. const wxChar PAGE_INFO::D[] = wxT( "D" );
  48. const wxChar PAGE_INFO::E[] = wxT( "E" );
  49. const wxChar PAGE_INFO::GERBER[] = wxT( "GERBER" );
  50. const wxChar PAGE_INFO::USLetter[] = wxT( "USLetter" );
  51. const wxChar PAGE_INFO::USLegal[] = wxT( "USLegal" );
  52. const wxChar PAGE_INFO::USLedger[] = wxT( "USLedger" );
  53. const wxChar PAGE_INFO::Custom[] = wxT( "User" );
  54. // Standard page sizes in mils, all constants
  55. // see: https://lists.launchpad.net/kicad-developers/msg07389.html
  56. // also see: wx/defs.h
  57. // local readability macro for millimeter wxSize
  58. #define MMsize( x, y ) VECTOR2D( EDA_UNIT_UTILS::Mm2mils( x ), EDA_UNIT_UTILS::Mm2mils( y ) )
  59. // All MUST be defined as landscape.
  60. const PAGE_INFO PAGE_INFO::pageA5( MMsize( 210, 148 ), wxT( "A5" ), wxPAPER_A5 );
  61. const PAGE_INFO PAGE_INFO::pageA4( MMsize( 297, 210 ), wxT( "A4" ), wxPAPER_A4 );
  62. const PAGE_INFO PAGE_INFO::pageA3( MMsize( 420, 297 ), wxT( "A3" ), wxPAPER_A3 );
  63. const PAGE_INFO PAGE_INFO::pageA2( MMsize( 594, 420 ), wxT( "A2" ), wxPAPER_A2 );
  64. const PAGE_INFO PAGE_INFO::pageA1( MMsize( 841, 594 ), wxT( "A1" ), PAPER_A1 );
  65. const PAGE_INFO PAGE_INFO::pageA0( MMsize( 1189, 841 ), wxT( "A0" ), PAPER_A0 );
  66. const PAGE_INFO PAGE_INFO::pageA( VECTOR2D( 11000, 8500 ), wxT( "A" ), wxPAPER_LETTER );
  67. const PAGE_INFO PAGE_INFO::pageB( VECTOR2D( 17000, 11000 ), wxT( "B" ), wxPAPER_TABLOID );
  68. const PAGE_INFO PAGE_INFO::pageC( VECTOR2D( 22000, 17000 ), wxT( "C" ), wxPAPER_CSHEET );
  69. const PAGE_INFO PAGE_INFO::pageD( VECTOR2D( 34000, 22000 ), wxT( "D" ), wxPAPER_DSHEET );
  70. const PAGE_INFO PAGE_INFO::pageE( VECTOR2D( 44000, 34000 ), wxT( "E" ), wxPAPER_ESHEET );
  71. const PAGE_INFO PAGE_INFO::pageGERBER( VECTOR2D( 32000, 32000 ), wxT( "GERBER" ), wxPAPER_NONE );
  72. const PAGE_INFO PAGE_INFO::pageUser( VECTOR2D( 17000, 11000 ), Custom, wxPAPER_NONE );
  73. // US paper sizes
  74. const PAGE_INFO PAGE_INFO::pageUSLetter( VECTOR2D( 11000, 8500 ), wxT( "USLetter" ), wxPAPER_LETTER );
  75. const PAGE_INFO PAGE_INFO::pageUSLegal( VECTOR2D( 14000, 8500 ), wxT( "USLegal" ), wxPAPER_LEGAL );
  76. const PAGE_INFO PAGE_INFO::pageUSLedger( VECTOR2D( 17000, 11000 ), wxT( "USLedger" ),
  77. wxPAPER_TABLOID );
  78. // Custom paper size for next instantiation of type "User"
  79. double PAGE_INFO::s_user_width = 17000;
  80. double PAGE_INFO::s_user_height = 11000;
  81. inline void PAGE_INFO::updatePortrait()
  82. {
  83. // update m_portrait based on orientation of m_size.x and m_size.y
  84. m_portrait = ( m_size.y > m_size.x );
  85. }
  86. PAGE_INFO::PAGE_INFO( const VECTOR2D& aSizeMils, const wxString& aType, wxPaperSize aPaperId ) :
  87. m_type( aType ), m_size( aSizeMils ), m_paper_id( aPaperId )
  88. {
  89. updatePortrait();
  90. // This constructor is protected, and only used by const PAGE_INFO's known
  91. // only to class implementation, so no further changes to "this" object are
  92. // expected.
  93. }
  94. PAGE_INFO::PAGE_INFO( const wxString& aType, bool aIsPortrait )
  95. {
  96. SetType( aType, aIsPortrait );
  97. }
  98. bool PAGE_INFO::SetType( const wxString& aType, bool aIsPortrait )
  99. {
  100. bool rc = true;
  101. // all are landscape initially
  102. if( aType == pageA5.GetType() )
  103. *this = pageA5;
  104. else if( aType == pageA4.GetType() )
  105. *this = pageA4;
  106. else if( aType == pageA3.GetType() )
  107. *this = pageA3;
  108. else if( aType == pageA2.GetType() )
  109. *this = pageA2;
  110. else if( aType == pageA1.GetType() )
  111. *this = pageA1;
  112. else if( aType == pageA0.GetType() )
  113. *this = pageA0;
  114. else if( aType == pageA.GetType() )
  115. *this = pageA;
  116. else if( aType == pageB.GetType() )
  117. *this = pageB;
  118. else if( aType == pageC.GetType() )
  119. *this = pageC;
  120. else if( aType == pageD.GetType() )
  121. *this = pageD;
  122. else if( aType == pageE.GetType() )
  123. *this = pageE;
  124. else if( aType == pageGERBER.GetType() )
  125. *this = pageGERBER;
  126. else if( aType == pageUSLetter.GetType() )
  127. *this = pageUSLetter;
  128. else if( aType == pageUSLegal.GetType() )
  129. *this = pageUSLegal;
  130. else if( aType == pageUSLedger.GetType() )
  131. *this = pageUSLedger;
  132. else if( aType == pageUser.GetType() )
  133. {
  134. // pageUser is const, and may not and does not hold the custom size,
  135. // so customize *this later
  136. *this = pageUser;
  137. // customize:
  138. m_size.x = s_user_width;
  139. m_size.y = s_user_height;
  140. updatePortrait();
  141. }
  142. else
  143. rc = false;
  144. if( aIsPortrait )
  145. {
  146. // all private PAGE_INFOs are landscape, must swap x and y
  147. std::swap( m_size.y, m_size.x );
  148. updatePortrait();
  149. }
  150. return rc;
  151. }
  152. bool PAGE_INFO::IsCustom() const
  153. {
  154. return m_type == Custom;
  155. }
  156. void PAGE_INFO::SetPortrait( bool aIsPortrait )
  157. {
  158. if( m_portrait != aIsPortrait )
  159. {
  160. // swap x and y in m_size
  161. std::swap( m_size.y, m_size.x );
  162. m_portrait = aIsPortrait;
  163. // margins are not touched, do that if you want
  164. }
  165. }
  166. static double clampWidth( double aWidthInMils )
  167. {
  168. /* was giving EESCHEMA single component SVG plotter grief
  169. However a minimal test is made to avoid values that crashes Kicad
  170. if( aWidthInMils < 4000 ) // 4" is about a baseball card
  171. aWidthInMils = 4000;
  172. else if( aWidthInMils > 44000 ) //44" is plotter size
  173. aWidthInMils = 44000;
  174. */
  175. if( aWidthInMils < 10 )
  176. aWidthInMils = 10;
  177. return aWidthInMils;
  178. }
  179. static double clampHeight( double aHeightInMils )
  180. {
  181. /* was giving EESCHEMA single component SVG plotter grief
  182. clamping is best done at the UI, i.e. dialog, levels
  183. However a minimal test is made to avoid values that crashes Kicad
  184. if( aHeightInMils < 4000 )
  185. aHeightInMils = 4000;
  186. else if( aHeightInMils > 44000 )
  187. aHeightInMils = 44000;
  188. */
  189. if( aHeightInMils < 10.0 )
  190. aHeightInMils = 10.0;
  191. return aHeightInMils;
  192. }
  193. void PAGE_INFO::SetCustomWidthMils( double aWidthInMils )
  194. {
  195. s_user_width = clampWidth( aWidthInMils );
  196. }
  197. void PAGE_INFO::SetCustomHeightMils( double aHeightInMils )
  198. {
  199. s_user_height = clampHeight( aHeightInMils );
  200. }
  201. void PAGE_INFO::SetWidthMils( double aWidthInMils )
  202. {
  203. if( m_size.x != aWidthInMils )
  204. {
  205. m_size.x = clampWidth( aWidthInMils );
  206. m_type = Custom;
  207. m_paper_id = wxPAPER_NONE;
  208. updatePortrait();
  209. }
  210. }
  211. void PAGE_INFO::SetHeightMils( double aHeightInMils )
  212. {
  213. if( m_size.y != aHeightInMils )
  214. {
  215. m_size.y = clampHeight( aHeightInMils );
  216. m_type = Custom;
  217. m_paper_id = wxPAPER_NONE;
  218. updatePortrait();
  219. }
  220. }
  221. void PAGE_INFO::Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const
  222. {
  223. aFormatter->Print( aNestLevel, "(paper %s", aFormatter->Quotew( GetType() ).c_str() );
  224. // The page dimensions are only required for user defined page sizes.
  225. // Internally, the page size is in mils
  226. if( GetType() == PAGE_INFO::Custom )
  227. aFormatter->Print( 0, " %g %g",
  228. GetWidthMils() * 25.4 / 1000.0,
  229. GetHeightMils() * 25.4 / 1000.0 );
  230. if( !IsCustom() && IsPortrait() )
  231. aFormatter->Print( 0, " portrait" );
  232. aFormatter->Print( 0, ")\n" );
  233. }