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.

388 lines
10 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-2017 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 <eda_base_frame.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 <wx/url.h>
  40. #include <pgm_base.h>
  41. using KIGFX::COLOR4D;
  42. /**
  43. * Global variables definitions.
  44. *
  45. * TODO: All of these variables should be moved into the class were they
  46. * are defined and used. Most of them probably belong in the
  47. * application class.
  48. */
  49. EDA_UNITS_T g_UserUnit;
  50. COLOR4D g_GhostColor;
  51. /* Class LOCALE_IO
  52. * is a class that can be instantiated within a scope in which you are expecting
  53. * exceptions to be thrown. Its constructor sets a "C" locale, to read/print files
  54. * with fp numbers.
  55. * Its destructor insures that the default locale is restored if an exception
  56. * is thrown, or not.
  57. */
  58. std::atomic<unsigned int> LOCALE_IO::m_c_count(0);
  59. LOCALE_IO::LOCALE_IO()
  60. {
  61. // use thread safe, atomic operation
  62. if( m_c_count++ == 0 )
  63. {
  64. // Store the user locale name, to restore this locale later, in dtor
  65. m_user_locale = setlocale( LC_ALL, 0 );
  66. // Switch the locale to C locale, to read/write files with fp numbers
  67. setlocale( LC_ALL, "C" );
  68. }
  69. }
  70. LOCALE_IO::~LOCALE_IO()
  71. {
  72. // use thread safe, atomic operation
  73. if( --m_c_count == 0 )
  74. {
  75. // revert to the user locale
  76. setlocale( LC_ALL, m_user_locale.c_str() );
  77. }
  78. }
  79. wxSize GetTextSize( const wxString& aSingleLine, wxWindow* aWindow )
  80. {
  81. wxCoord width;
  82. wxCoord height;
  83. {
  84. wxClientDC dc( aWindow );
  85. dc.SetFont( aWindow->GetFont() );
  86. dc.GetTextExtent( aSingleLine, &width, &height );
  87. }
  88. return wxSize( width, height );
  89. }
  90. bool EnsureTextCtrlWidth( wxTextCtrl* aCtrl, const wxString* aString )
  91. {
  92. wxWindow* window = aCtrl->GetParent();
  93. if( !window )
  94. window = aCtrl;
  95. wxString ctrlText;
  96. if( !aString )
  97. {
  98. ctrlText = aCtrl->GetValue();
  99. aString = &ctrlText;
  100. }
  101. wxSize textz = GetTextSize( *aString, window );
  102. wxSize ctrlz = aCtrl->GetSize();
  103. if( ctrlz.GetWidth() < textz.GetWidth() + 10 )
  104. {
  105. ctrlz.SetWidth( textz.GetWidth() + 10 );
  106. aCtrl->SetSizeHints( ctrlz );
  107. return true;
  108. }
  109. return false;
  110. }
  111. void wxStringSplit( const wxString& aText, wxArrayString& aStrings, wxChar aSplitter )
  112. {
  113. wxString tmp;
  114. for( unsigned ii = 0; ii < aText.Length(); ii++ )
  115. {
  116. if( aText[ii] == aSplitter )
  117. {
  118. aStrings.Add( tmp );
  119. tmp.Clear();
  120. }
  121. else
  122. tmp << aText[ii];
  123. }
  124. if( !tmp.IsEmpty() )
  125. {
  126. aStrings.Add( tmp );
  127. }
  128. }
  129. int ProcessExecute( const wxString& aCommandLine, int aFlags, wxProcess *callback )
  130. {
  131. return wxExecute( aCommandLine, aFlags, callback );
  132. }
  133. timestamp_t GetNewTimeStamp()
  134. {
  135. static timestamp_t oldTimeStamp;
  136. timestamp_t newTimeStamp;
  137. newTimeStamp = time( NULL );
  138. if( newTimeStamp <= oldTimeStamp )
  139. newTimeStamp = oldTimeStamp + 1;
  140. oldTimeStamp = newTimeStamp;
  141. return newTimeStamp;
  142. }
  143. double RoundTo0( double x, double precision )
  144. {
  145. assert( precision != 0 );
  146. long long ix = KiROUND( x * precision );
  147. if ( x < 0.0 )
  148. ix = -ix;
  149. int remainder = ix % 10; // remainder is in precision mm
  150. if( remainder <= 2 )
  151. ix -= remainder; // truncate to the near number
  152. else if( remainder >= 8 )
  153. ix += 10 - remainder; // round to near number
  154. if ( x < 0 )
  155. ix = -ix;
  156. return (double) ix / precision;
  157. }
  158. wxConfigBase* GetNewConfig( const wxString& aProgName )
  159. {
  160. wxConfigBase* cfg = 0;
  161. wxFileName configname;
  162. configname.AssignDir( GetKicadConfigPath() );
  163. configname.SetFullName( aProgName );
  164. cfg = new wxFileConfig( wxT( "" ), wxT( "" ), configname.GetFullPath() );
  165. return cfg;
  166. }
  167. wxString GetKicadConfigPath()
  168. {
  169. wxFileName cfgpath;
  170. // From the wxWidgets wxStandardPaths::GetUserConfigDir() help:
  171. // Unix: ~ (the home directory)
  172. // Windows: "C:\Documents and Settings\username\Application Data"
  173. // Mac: ~/Library/Preferences
  174. cfgpath.AssignDir( wxStandardPaths::Get().GetUserConfigDir() );
  175. #if !defined( __WINDOWS__ ) && !defined( __WXMAC__ )
  176. wxString envstr;
  177. if( !wxGetEnv( wxT( "XDG_CONFIG_HOME" ), &envstr ) || envstr.IsEmpty() )
  178. {
  179. // XDG_CONFIG_HOME is not set, so use the fallback
  180. cfgpath.AppendDir( wxT( ".config" ) );
  181. }
  182. else
  183. {
  184. // Override the assignment above with XDG_CONFIG_HOME
  185. cfgpath.AssignDir( envstr );
  186. }
  187. #endif
  188. cfgpath.AppendDir( wxT( "kicad" ) );
  189. if( !cfgpath.DirExists() )
  190. {
  191. cfgpath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
  192. }
  193. return cfgpath.GetPath();
  194. }
  195. #include <ki_mutex.h>
  196. const wxString ExpandEnvVarSubstitutions( const wxString& aString )
  197. {
  198. // wxGetenv( wchar_t* ) is not re-entrant on linux.
  199. // Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
  200. static MUTEX getenv_mutex;
  201. MUTLOCK lock( getenv_mutex );
  202. // We reserve the right to do this another way, by providing our own member
  203. // function.
  204. return wxExpandEnvVars( aString );
  205. }
  206. const wxString ResolveUriByEnvVars( const wxString& aUri )
  207. {
  208. // URL-like URI: return as is.
  209. wxURL url( aUri );
  210. if( url.GetError() == wxURL_NOERR )
  211. return aUri;
  212. // Otherwise, the path points to a local file. Resolve environment
  213. // variables if any.
  214. return ExpandEnvVarSubstitutions( aUri );
  215. }
  216. bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
  217. const wxString& aBaseFilename,
  218. REPORTER* aReporter )
  219. {
  220. wxString msg;
  221. wxString baseFilePath = wxFileName( aBaseFilename ).GetPath();
  222. // make aTargetFullFileName path, which is relative to aBaseFilename path (if it is not
  223. // already an absolute path) absolute:
  224. if( !aTargetFullFileName->MakeAbsolute( baseFilePath ) )
  225. {
  226. if( aReporter )
  227. {
  228. msg.Printf( _( "Cannot make path \"%s\" absolute with respect to \"%s\"." ),
  229. GetChars( aTargetFullFileName->GetPath() ),
  230. GetChars( baseFilePath ) );
  231. aReporter->Report( msg, REPORTER::RPT_ERROR );
  232. }
  233. return false;
  234. }
  235. // Ensure the path of aTargetFullFileName exists, and create it if needed:
  236. wxString outputPath( aTargetFullFileName->GetPath() );
  237. if( !wxFileName::DirExists( outputPath ) )
  238. {
  239. if( wxMkdir( outputPath ) )
  240. {
  241. if( aReporter )
  242. {
  243. msg.Printf( _( "Output directory \"%s\" created.\n" ), GetChars( outputPath ) );
  244. aReporter->Report( msg, REPORTER::RPT_INFO );
  245. return true;
  246. }
  247. }
  248. else
  249. {
  250. if( aReporter )
  251. {
  252. msg.Printf( _( "Cannot create output directory \"%s\".\n" ),
  253. GetChars( outputPath ) );
  254. aReporter->Report( msg, REPORTER::RPT_ERROR );
  255. }
  256. return false;
  257. }
  258. }
  259. return true;
  260. }
  261. #ifdef __WXMAC__
  262. wxString GetOSXKicadUserDataDir()
  263. {
  264. // According to wxWidgets documentation for GetUserDataDir:
  265. // Mac: ~/Library/Application Support/appname
  266. wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
  267. // Since appname is different if started via launcher or standalone binary
  268. // map all to "kicad" here
  269. udir.RemoveLastDir();
  270. udir.AppendDir( wxT( "kicad" ) );
  271. return udir.GetPath();
  272. }
  273. wxString GetOSXKicadMachineDataDir()
  274. {
  275. return wxT( "/Library/Application Support/kicad" );
  276. }
  277. wxString GetOSXKicadDataDir()
  278. {
  279. // According to wxWidgets documentation for GetDataDir:
  280. // Mac: appname.app/Contents/SharedSupport bundle subdirectory
  281. wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
  282. // This must be mapped to main bundle for everything but kicad.app
  283. const wxArrayString dirs = ddir.GetDirs();
  284. if( dirs[dirs.GetCount() - 3] != wxT( "kicad.app" ) )
  285. {
  286. // Bundle structure resp. current path is
  287. // kicad.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
  288. // and will be mapped to
  289. // kicad.app/Contents/SharedSupprt
  290. ddir.RemoveLastDir();
  291. ddir.RemoveLastDir();
  292. ddir.RemoveLastDir();
  293. ddir.RemoveLastDir();
  294. ddir.AppendDir( wxT( "SharedSupport" ) );
  295. }
  296. return ddir.GetPath();
  297. }
  298. #endif
  299. // add this only if it is not in wxWidgets (for instance before 3.1.0)
  300. #ifdef USE_KICAD_WXSTRING_HASH
  301. size_t std::hash<wxString>::operator()( const wxString& s ) const
  302. {
  303. return std::hash<std::wstring>{}( s.ToStdWstring() );
  304. }
  305. #endif