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.

394 lines
13 KiB

// 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
18 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2004-2011 KiCad Developers, see change_log.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. /**
  25. * @file sheet.cpp
  26. */
  27. #include <fctsys.h>
  28. #include <gr_basic.h>
  29. #include <class_drawpanel.h>
  30. #include <confirm.h>
  31. #include <wxEeschemaStruct.h>
  32. #include <base_units.h>
  33. #include <general.h>
  34. #include <sch_sheet.h>
  35. #include <dialogs/dialog_sch_sheet_props.h>
  36. #include <wildcards_and_files_ext.h>
  37. bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, wxDC* aDC )
  38. {
  39. if( aSheet == NULL )
  40. return false;
  41. // Get the new texts
  42. DIALOG_SCH_SHEET_PROPS dlg( this );
  43. wxString units = GetUnitsLabel( g_UserUnit );
  44. dlg.SetFileName( aSheet->GetFileName() );
  45. dlg.SetFileNameTextSize( ReturnStringFromValue( g_UserUnit, aSheet->GetFileNameSize() ) );
  46. dlg.SetFileNameTextSizeUnits( units );
  47. dlg.SetSheetName( aSheet->GetName() );
  48. dlg.SetSheetNameTextSize( ReturnStringFromValue( g_UserUnit, aSheet->GetSheetNameSize() ) );
  49. dlg.SetSheetNameTextSizeUnits( units );
  50. /* This ugly hack fixes a bug in wxWidgets 2.8.7 and likely earlier
  51. * versions for the flex grid sizer in wxGTK that prevents the last
  52. * column from being sized correctly. It doesn't cause any problems
  53. * on win32 so it doesn't need to wrapped in ugly #ifdef __WXGTK__
  54. * #endif.
  55. */
  56. dlg.Layout();
  57. dlg.Fit();
  58. dlg.SetMinSize( dlg.GetSize() );
  59. if( dlg.ShowModal() == wxID_CANCEL )
  60. return false;
  61. wxFileName fileName = dlg.GetFileName();
  62. fileName.SetExt( SchematicFileExtension );
  63. if( !fileName.IsOk() )
  64. {
  65. DisplayError( this, _( "File name is not valid!" ) );
  66. return false;
  67. }
  68. // Duplicate sheet names are not valid.
  69. const SCH_SHEET* sheet = GetScreen()->GetSheet( dlg.GetSheetName() );
  70. if( (sheet != NULL) && (sheet != aSheet) )
  71. {
  72. DisplayError( this, wxString::Format( _( "A sheet named \"%s\" already exists." ),
  73. GetChars( dlg.GetSheetName() ) ) );
  74. return false;
  75. }
  76. wxString msg;
  77. wxString tmp;
  78. bool loadFromFile = false;
  79. SCH_SCREEN* useScreen = NULL;
  80. wxString newFullFilename = fileName.GetFullPath();
  81. // Inside Eeschema, filenames are stored using unix notation
  82. newFullFilename.Replace( wxT("\\"), wxT("/") );
  83. // Search for a schematic file having the same filename exists,
  84. // already in use in the hierarchy, or on disk,
  85. // in order to reuse it
  86. if( !g_RootSheet->SearchHierarchy( newFullFilename, &useScreen ) )
  87. loadFromFile = fileName.FileExists();
  88. if( aSheet->GetScreen() == NULL ) // New sheet.
  89. {
  90. if( ( useScreen != NULL ) || loadFromFile ) // Load from existing file.
  91. {
  92. if( useScreen != NULL )
  93. {
  94. msg.Printf( _( "A file named <%s> already exists in the current schematic hierarchy." ),
  95. GetChars( newFullFilename ) );
  96. }
  97. else
  98. {
  99. msg.Printf( _( "A file named <%s> already exists." ),
  100. GetChars( newFullFilename ) );
  101. }
  102. msg += _("\n\nDo you want to create a sheet with the contents of this file?" );
  103. if( !IsOK( this, msg ) )
  104. return false;
  105. }
  106. else // New file.
  107. {
  108. aSheet->SetScreen( new SCH_SCREEN() );
  109. aSheet->GetScreen()->SetFileName( newFullFilename );
  110. }
  111. }
  112. else // Existing sheet.
  113. {
  114. bool isUndoable = true;
  115. bool renameFile = false;
  116. // We are always using here a case insensitive comparison
  117. // to avoid issues under Windows, although under Unix
  118. // filenames are case sensitive.
  119. // But many users create schematic under both Unix and Windows
  120. if( newFullFilename.CmpNoCase( aSheet->GetFileName() ) != 0 )
  121. {
  122. // Sheet file name changes cannot be undone.
  123. isUndoable = false;
  124. msg = _( "Changing the sheet file name cannot be undone. " );
  125. if( ( useScreen != NULL ) || loadFromFile ) // Load from existing file.
  126. {
  127. wxString tmp;
  128. if( useScreen != NULL )
  129. {
  130. tmp.Printf( _( "A file named <%s> already exists in the current schematic hierarchy." ),
  131. GetChars( newFullFilename ) );
  132. }
  133. else
  134. {
  135. tmp.Printf( _( "A file named <%s> already exists." ),
  136. GetChars( newFullFilename ) );
  137. }
  138. msg += tmp;
  139. msg += _("\n\nDo you want to replace the sheet with the contents of this file?" );
  140. if( !IsOK( this, msg ) )
  141. return false;
  142. if( loadFromFile )
  143. aSheet->SetScreen( NULL );
  144. }
  145. else // Save to new file name.
  146. {
  147. if( aSheet->GetScreenCount() > 1 )
  148. {
  149. msg += _( "This sheet uses shared data in a complex hierarchy.\n\n" );
  150. msg += _( "Do you wish to convert it to a simple hierarchical sheet?" );
  151. if( !IsOK( NULL, msg ) )
  152. return false;
  153. }
  154. renameFile = true;
  155. }
  156. }
  157. aSheet->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode );
  158. m_canvas->SetIgnoreMouseEvents( true );
  159. if( isUndoable )
  160. SaveCopyInUndoList( aSheet, UR_CHANGED );
  161. if( renameFile )
  162. {
  163. aSheet->GetScreen()->SetFileName( newFullFilename );
  164. SaveEEFile( aSheet->GetScreen() );
  165. // If the the associated screen is shared by more than one sheet, remove the
  166. // screen and reload the file to a new screen. Failure to do this will trash
  167. // the screen reference counting in complex hierarchies.
  168. if( aSheet->GetScreenCount() > 1 )
  169. {
  170. aSheet->SetScreen( NULL );
  171. loadFromFile = true;
  172. }
  173. }
  174. }
  175. aSheet->SetFileName( newFullFilename );
  176. if( useScreen )
  177. aSheet->SetScreen( useScreen );
  178. else if( loadFromFile )
  179. aSheet->Load( this );
  180. aSheet->SetFileNameSize( ReturnValueFromString( g_UserUnit, dlg.GetFileNameTextSize() ) );
  181. aSheet->SetName( dlg.GetSheetName() );
  182. aSheet->SetSheetNameSize( ReturnValueFromString( g_UserUnit, dlg.GetSheetNameTextSize() ) );
  183. if( aSheet->GetName().IsEmpty() )
  184. aSheet->SetName( wxString::Format( wxT( "Sheet%8.8lX" ), aSheet->GetTimeStamp() ) );
  185. m_canvas->MoveCursorToCrossHair();
  186. m_canvas->SetIgnoreMouseEvents( false );
  187. aSheet->Draw( m_canvas, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
  188. OnModify();
  189. return true;
  190. }
  191. /* Move selected sheet with the cursor.
  192. * Callback function use by m_mouseCaptureCallback.
  193. */
  194. static void MoveOrResizeSheet( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
  195. bool aErase )
  196. {
  197. wxPoint moveVector;
  198. BASE_SCREEN* screen = aPanel->GetScreen();
  199. SCH_SHEET* sheet = (SCH_SHEET*) screen->GetCurItem();
  200. if( aErase )
  201. sheet->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
  202. wxPoint pos = sheet->GetPosition();
  203. if( sheet->IsResized() )
  204. {
  205. int width = aPanel->GetParent()->GetCrossHairPosition().x - sheet->GetPosition().x;
  206. int height = aPanel->GetParent()->GetCrossHairPosition().y - sheet->GetPosition().y;
  207. // If the sheet doesn't have any pins, clamp the minimum size to the default values.
  208. width = ( width < MIN_SHEET_WIDTH ) ? MIN_SHEET_WIDTH : width;
  209. height = ( height < MIN_SHEET_HEIGHT ) ? MIN_SHEET_HEIGHT : height;
  210. if( sheet->HasPins() )
  211. {
  212. int gridSizeX = KiROUND( screen->GetGridSize().x );
  213. int gridSizeY = KiROUND( screen->GetGridSize().y );
  214. // If the sheet has pins, use the pin positions to clamp the minimum height.
  215. height = ( height < sheet->GetMinHeight() + gridSizeY ) ?
  216. sheet->GetMinHeight() + gridSizeY : height;
  217. width = ( width < sheet->GetMinWidth() + gridSizeX ) ?
  218. sheet->GetMinWidth() + gridSizeX : width;
  219. }
  220. wxPoint grid = aPanel->GetParent()->GetNearestGridPosition(
  221. wxPoint( pos.x + width, pos.y + height ) );
  222. sheet->Resize( wxSize( grid.x - pos.x, grid.y - pos.y ) );
  223. }
  224. else if( sheet->IsMoving() )
  225. {
  226. moveVector = aPanel->GetParent()->GetCrossHairPosition() - pos;
  227. sheet->Move( moveVector );
  228. }
  229. sheet->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
  230. }
  231. // Complete sheet move.
  232. static void ExitSheet( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
  233. {
  234. SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
  235. SCH_ITEM* item = screen->GetCurItem();
  236. SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
  237. if( (item == NULL) || (item->Type() != SCH_SHEET_T) || (parent == NULL) )
  238. return;
  239. parent->SetRepeatItem( NULL );
  240. item->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode );
  241. if( item->IsNew() )
  242. {
  243. delete item;
  244. }
  245. else if( item->IsMoving() || item->IsResized() )
  246. {
  247. screen->Remove( item );
  248. delete item;
  249. item = parent->GetUndoItem();
  250. wxCHECK_RET( item != NULL, wxT( "Cannot restore undefined last sheet item." ) );
  251. screen->Append( item );
  252. // the owner of item is no more parent, this is the draw list of screen:
  253. parent->SetUndoItem( NULL );
  254. item->Draw( aPanel, aDC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
  255. item->ClearFlags();
  256. }
  257. else
  258. {
  259. item->ClearFlags();
  260. }
  261. screen->SetCurItem( NULL );
  262. }
  263. // Create hierarchy sheet.
  264. SCH_SHEET* SCH_EDIT_FRAME::CreateSheet( wxDC* aDC )
  265. {
  266. SetRepeatItem( NULL );
  267. SCH_SHEET* sheet = new SCH_SHEET( GetCrossHairPosition() );
  268. sheet->SetFlags( IS_NEW | IS_RESIZED );
  269. sheet->SetTimeStamp( GetNewTimeStamp() );
  270. sheet->SetParent( GetScreen() );
  271. sheet->SetScreen( NULL );
  272. // need to check if this is being added to the GetDrawItems().
  273. // also need to update the hierarchy, if we are adding
  274. // a sheet to a screen that already has multiple instances (!)
  275. GetScreen()->SetCurItem( sheet );
  276. m_canvas->SetMouseCapture( MoveOrResizeSheet, ExitSheet );
  277. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, false );
  278. m_canvas->CrossHairOff( aDC );
  279. SetCrossHairPosition( sheet->GetResizePosition() );
  280. m_canvas->MoveCursorToCrossHair();
  281. m_canvas->CrossHairOn( aDC );
  282. return sheet;
  283. }
  284. void SCH_EDIT_FRAME::ReSizeSheet( SCH_SHEET* aSheet, wxDC* aDC )
  285. {
  286. if( aSheet == NULL || aSheet->IsNew() )
  287. return;
  288. wxCHECK_RET( aSheet->Type() == SCH_SHEET_T,
  289. wxString::Format( wxT( "Cannot perform sheet resize on %s object." ),
  290. GetChars( aSheet->GetClass() ) ) );
  291. m_canvas->CrossHairOff( aDC );
  292. SetCrossHairPosition( aSheet->GetResizePosition() );
  293. m_canvas->MoveCursorToCrossHair();
  294. m_canvas->CrossHairOn( aDC );
  295. SetUndoItem( aSheet );
  296. aSheet->SetFlags( IS_RESIZED );
  297. m_canvas->SetMouseCapture( MoveOrResizeSheet, ExitSheet );
  298. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true );
  299. if( aSheet->IsNew() ) // not already in edit, save a copy for undo/redo
  300. SetUndoItem( aSheet );
  301. }
  302. void SCH_EDIT_FRAME::StartMoveSheet( SCH_SHEET* aSheet, wxDC* aDC )
  303. {
  304. if( ( aSheet == NULL ) || ( aSheet->Type() != SCH_SHEET_T ) )
  305. return;
  306. m_canvas->CrossHairOff( aDC );
  307. SetCrossHairPosition( aSheet->GetPosition() );
  308. m_canvas->MoveCursorToCrossHair();
  309. if( !aSheet->IsNew() )
  310. SetUndoItem( aSheet );
  311. aSheet->SetFlags( IS_MOVED );
  312. m_canvas->SetMouseCapture( MoveOrResizeSheet, ExitSheet );
  313. m_canvas->CallMouseCapture( aDC, wxDefaultPosition, true );
  314. m_canvas->CrossHairOn( aDC );
  315. }