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.

365 lines
9.4 KiB

14 years ago
14 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file common.cpp
  27. */
  28. #include <fctsys.h>
  29. #include <wxstruct.h>
  30. #include <base_struct.h>
  31. #include <common.h>
  32. #include <macros.h>
  33. #include <base_units.h>
  34. #include <reporter.h>
  35. #include <wx/process.h>
  36. #include <wx/config.h>
  37. #include <wx/utils.h>
  38. #include <wx/stdpaths.h>
  39. #include <pgm_base.h>
  40. using KIGFX::COLOR4D;
  41. /**
  42. * Global variables definitions.
  43. *
  44. * TODO: All of these variables should be moved into the class were they
  45. * are defined and used. Most of them probably belong in the
  46. * application class.
  47. */
  48. EDA_UNITS_T g_UserUnit;
  49. COLOR4D g_GhostColor;
  50. /* Class LOCALE_IO
  51. * is a class that can be instantiated within a scope in which you are expecting
  52. * exceptions to be thrown. Its constructor sets a "C" locale, to read/print files
  53. * with fp numbers.
  54. * Its destructor insures that the default locale is restored if an exception
  55. * is thrown, or not.
  56. */
  57. std::atomic<unsigned int> LOCALE_IO::m_c_count(0);
  58. LOCALE_IO::LOCALE_IO()
  59. {
  60. // use thread safe, atomic operation
  61. if( m_c_count++ == 0 )
  62. {
  63. // Store the user locale name, to restore this locale later, in dtor
  64. m_user_locale = setlocale( LC_ALL, 0 );
  65. // Switch the locale to C locale, to read/write files with fp numbers
  66. setlocale( LC_ALL, "C" );
  67. }
  68. }
  69. LOCALE_IO::~LOCALE_IO()
  70. {
  71. // use thread safe, atomic operation
  72. if( --m_c_count == 0 )
  73. {
  74. // revert to the user locale
  75. setlocale( LC_ALL, m_user_locale.c_str() );
  76. }
  77. }
  78. wxSize GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
  79. {
  80. wxCoord width;
  81. wxCoord height;
  82. {
  83. wxClientDC dc( aWindow );
  84. dc.SetFont( aWindow->GetFont() );
  85. dc.GetTextExtent( aSingleLine, &width, &height );
  86. }
  87. return wxSize( width, height );
  88. }
  89. bool EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
  90. {
  91. wxWindow* window = aCtrl->GetParent();
  92. if( !window )
  93. window = aCtrl;
  94. wxString ctrlText;
  95. if( !aString )
  96. {
  97. ctrlText = aCtrl->GetValue();
  98. aString = &ctrlText;
  99. }
  100. wxSize textz = GetTextSize( *aString, window );
  101. wxSize ctrlz = aCtrl->GetSize();
  102. if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
  103. {
  104. ctrlz.SetWidth( textz.GetWidth() + 10 );
  105. aCtrl->SetSizeHints( ctrlz );
  106. return true;
  107. }
  108. return false;
  109. }
  110. void wxStringSplit( const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
  111. {
  112. wxString tmp;
  113. for( unsigned ii = 0; ii < aText.Length(); ii++ )
  114. {
  115. if( aText[ii] == aSplitter )
  116. {
  117. aStrings.Add( tmp );
  118. tmp.Clear();
  119. }
  120. else
  121. tmp << aText[ii];
  122. }
  123. if( !tmp.IsEmpty() )
  124. {
  125. aStrings.Add( tmp );
  126. }
  127. }
  128. int ProcessExecute( const wxString& aCommandLine, int aFlags, wxProcess *callback )
  129. {
  130. return wxExecute( aCommandLine, aFlags, callback );
  131. }
  132. time_t GetNewTimeStamp()
  133. {
  134. static time_t oldTimeStamp;
  135. time_t newTimeStamp;
  136. newTimeStamp = time( NULL );
  137. if( newTimeStamp <= oldTimeStamp )
  138. newTimeStamp = oldTimeStamp + 1;
  139. oldTimeStamp = newTimeStamp;
  140. return newTimeStamp;
  141. }
  142. double RoundTo0( double x, double precision )
  143. {
  144. assert( precision != 0 );
  145. long long ix = KiROUND( x * precision );
  146. if ( x < 0.0 )
  147. ix = -ix;
  148. int remainder = ix % 10; // remainder is in precision mm
  149. if( remainder <= 2 )
  150. ix -= remainder; // truncate to the near number
  151. else if( remainder >= 8 )
  152. ix += 10 - remainder; // round to near number
  153. if ( x < 0 )
  154. ix = -ix;
  155. return (double) ix / precision;
  156. }
  157. wxConfigBase* GetNewConfig( const wxString& aProgName )
  158. {
  159. wxConfigBase* cfg = 0;
  160. wxFileName configname;
  161. configname.AssignDir( GetKicadConfigPath() );
  162. configname.SetFullName( aProgName );
  163. cfg = new wxFileConfig( wxT( "" ), wxT( "" ), configname.GetFullPath() );
  164. return cfg;
  165. }
  166. wxString GetKicadConfigPath()
  167. {
  168. wxFileName cfgpath;
  169. // From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
  170. // Unix: ~ (the home directory)
  171. // Windows: "C:\Documents and Settings\username\Application Data"
  172. // Mac: ~/Library/Preferences
  173. cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
  174. #if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
  175. wxString envstr;
  176. if( !wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) || envstr.IsEmpty() )
  177. {
  178. // XDG_CONFIG_HOME is not set, so use the fallback
  179. cfgpath.AppendDir( wxT( ".config" ) );
  180. }
  181. else
  182. {
  183. // Override the assignment above with XDG_CONFIG_HOME
  184. cfgpath.AssignDir( envstr );
  185. }
  186. #endif
  187. cfgpath.AppendDir( wxT( "kicad" ) );
  188. if( !cfgpath.DirExists() )
  189. {
  190. cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
  191. }
  192. return cfgpath.GetPath();
  193. }
  194. #include <ki_mutex.h>
  195. const wxString ExpandEnvVarSubstitutions( const wxString& aString )
  196. {
  197. // wxGetenv( wchar_t* ) is not re-entrant on linux.
  198. // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
  199. static MUTEX getenv_mutex;
  200. MUTLOCK lock( getenv_mutex );
  201. // We reserve the right to do this another way, by providing our own member
  202. // function.
  203. return wxExpandEnvVars( aString );
  204. }
  205. bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
  206. const wxString& aBaseFilename,
  207. REPORTER* aReporter )
  208. {
  209. wxString msg;
  210. wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
  211. // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
  212. // already an absolute path) absolute:
  213. if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
  214. {
  215. if( aReporter )
  216. {
  217. msg.Printf( _( "Cannot make path '%s' absolute with respect to '%s'." ),
  218. GetChars( aTargetFullFileName->GetPath() ),
  219. GetChars( baseFilePath ) );
  220. aReporter->Report( msg, REPORTER::RPT_ERROR );
  221. }
  222. return false;
  223. }
  224. // Ensure the path of aTargetFullFileName exists, and create it if needed:
  225. wxString outputPath( aTargetFullFileName->GetPath() );
  226. if( !wxFileName::DirExists( outputPath ) )
  227. {
  228. if( wxMkdir( outputPath ) )
  229. {
  230. if( aReporter )
  231. {
  232. msg.Printf( _( "Output directory '%s' created.\n" ), GetChars( outputPath ) );
  233. aReporter->Report( msg, REPORTER::RPT_INFO );
  234. return true;
  235. }
  236. }
  237. else
  238. {
  239. if( aReporter )
  240. {
  241. msg.Printf( _( "Cannot create output directory '%s'.\n" ),
  242. GetChars( outputPath ) );
  243. aReporter->Report( msg, REPORTER::RPT_ERROR );
  244. }
  245. return false;
  246. }
  247. }
  248. return true;
  249. }
  250. #ifdef __WXMAC__
  251. wxString GetOSXKicadUserDataDir()
  252. {
  253. // According to wxWidgets documentation for GetUserDataDir:
  254. // Mac: ~/Library/Application Support/appname
  255. wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
  256. // Since appname is different if started via launcher or standalone binary
  257. // map all to "kicad" here
  258. udir.RemoveLastDir();
  259. udir.AppendDir( wxT( "kicad" ) );
  260. return udir.GetPath();
  261. }
  262. wxString GetOSXKicadMachineDataDir()
  263. {
  264. return wxT( "/Library/Application Support/kicad" );
  265. }
  266. wxString GetOSXKicadDataDir()
  267. {
  268. // According to wxWidgets documentation for GetDataDir:
  269. // Mac: appname.app/Contents/SharedSupport bundle subdirectory
  270. wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
  271. // This must be mapped to main bundle for everything but kicad.app
  272. const wxArrayString dirs = ddir.GetDirs();
  273. if( dirs[dirs.GetCount() - 3] != wxT( "kicad.app" ) )
  274. {
  275. // Bundle structure resp. current path is
  276. // kicad.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
  277. // and will be mapped to
  278. // kicad.app/Contents/SharedSupprt
  279. ddir.RemoveLastDir();
  280. ddir.RemoveLastDir();
  281. ddir.RemoveLastDir();
  282. ddir.RemoveLastDir();
  283. ddir.AppendDir( wxT( "SharedSupport" ) );
  284. }
  285. return ddir.GetPath();
  286. }
  287. #endif