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.

397 lines
13 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2008-2012 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2004-2012 KiCad Developers, see change_log.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 getpart.cpp
  27. * @brief functions to get and place library components.
  28. */
  29. #include <fctsys.h>
  30. #include <appl_wxstruct.h>
  31. #include <gr_basic.h>
  32. #include <class_drawpanel.h>
  33. #include <confirm.h>
  34. #include <wxEeschemaStruct.h>
  35. #include <kicad_device_context.h>
  36. #include <msgpanel.h>
  37. #include <general.h>
  38. #include <protos.h>
  39. #include <class_library.h>
  40. #include <sch_component.h>
  41. #include <libeditframe.h>
  42. #include <viewlib_frame.h>
  43. #include <eeschema_id.h>
  44. #include <dialog_choose_component.h>
  45. #include <component_tree_search_container.h>
  46. #include <dialog_get_component.h>
  47. #include <boost/foreach.hpp>
  48. wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( LIB_ALIAS* aPreselectedAlias,
  49. int* aUnit, int* aConvert )
  50. {
  51. wxSemaphore semaphore( 0, 1 );
  52. wxString cmpname;
  53. // Close the current Lib browser, if open, and open a new one, in "modal" mode:
  54. LIB_VIEW_FRAME * viewlibFrame = LIB_VIEW_FRAME::GetActiveLibraryViewer();;
  55. if( viewlibFrame )
  56. viewlibFrame->Destroy();
  57. viewlibFrame = new LIB_VIEW_FRAME( this, NULL, &semaphore,
  58. KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT );
  59. if ( aPreselectedAlias )
  60. {
  61. viewlibFrame->SetSelectedLibrary( aPreselectedAlias->GetLibraryName() );
  62. viewlibFrame->SetSelectedComponent( aPreselectedAlias->GetName() );
  63. }
  64. if( aUnit && *aUnit > 0 )
  65. viewlibFrame->SetUnit( *aUnit );
  66. if( aConvert && *aConvert > 0 )
  67. viewlibFrame->SetConvert( *aConvert );
  68. viewlibFrame->Refresh();
  69. // Show the library viewer frame until it is closed
  70. // Wait for viewer closing event:
  71. while( semaphore.TryWait() == wxSEMA_BUSY )
  72. {
  73. wxYield();
  74. wxMilliSleep( 50 );
  75. }
  76. cmpname = viewlibFrame->GetSelectedComponent();
  77. if( aUnit )
  78. *aUnit = viewlibFrame->GetUnit();
  79. if( aConvert )
  80. *aConvert = viewlibFrame->GetConvert();
  81. viewlibFrame->Destroy();
  82. return cmpname;
  83. }
  84. wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const wxString& aLibname,
  85. wxArrayString& aHistoryList,
  86. int& aHistoryLastUnit,
  87. bool aUseLibBrowser,
  88. int* aUnit,
  89. int* aConvert )
  90. {
  91. int cmpCount = 0;
  92. wxString dialogTitle;
  93. COMPONENT_TREE_SEARCH_CONTAINER search_container; // Container doing search-as-you-type
  94. if( !aLibname.IsEmpty() )
  95. {
  96. CMP_LIBRARY* currLibrary = CMP_LIBRARY::FindLibrary( aLibname );
  97. if( currLibrary != NULL )
  98. {
  99. cmpCount = currLibrary->GetCount();
  100. search_container.AddLibrary( *currLibrary );
  101. }
  102. }
  103. else
  104. {
  105. BOOST_FOREACH( CMP_LIBRARY& lib, CMP_LIBRARY::GetLibraryList() )
  106. {
  107. cmpCount += lib.GetCount();
  108. search_container.AddLibrary( lib );
  109. }
  110. }
  111. if( !aHistoryList.empty() )
  112. {
  113. // This is good for a transition for experineced users: giving them a History. Ideally,
  114. // we actually make this part even faster to access with a popup on ALT-a or something.
  115. // the history is under a node named "-- History --"
  116. // However, because it is translatable, and we need to have a node name starting by "-- "
  117. // because we (later) sort all node names alphabetically and this node should be the first,
  118. // we build it with only with "History" string translatable
  119. wxString nodename;
  120. nodename << wxT("-- ") << _("History") << wxT(" --");
  121. search_container.AddAliasList( nodename, aHistoryList, NULL );
  122. search_container.SetPreselectNode( aHistoryList[0], aHistoryLastUnit );
  123. }
  124. const int deMorgan = aConvert ? *aConvert : 1;
  125. dialogTitle.Printf( _( "Choose Component (%d items loaded)" ), cmpCount );
  126. DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, &search_container, deMorgan );
  127. if( dlg.ShowModal() == wxID_CANCEL )
  128. return wxEmptyString;
  129. wxString cmpName;
  130. LIB_ALIAS* const alias = dlg.GetSelectedAlias( aUnit );
  131. if ( alias )
  132. cmpName = alias->GetName();
  133. if( dlg.IsExternalBrowserSelected() ) // User requested big component browser.
  134. cmpName = SelectComponentFromLibBrowser( alias, aUnit, aConvert);
  135. if ( !cmpName.empty() )
  136. {
  137. AddHistoryComponentName( aHistoryList, cmpName );
  138. if ( aUnit ) aHistoryLastUnit = *aUnit;
  139. }
  140. return cmpName;
  141. }
  142. SCH_COMPONENT* SCH_EDIT_FRAME::Load_Component( wxDC* aDC,
  143. const wxString& aLibname,
  144. wxArrayString& aHistoryList,
  145. int& aHistoryLastUnit,
  146. bool aUseLibBrowser )
  147. {
  148. int unit = 1;
  149. int convert = 1;
  150. SetRepeatItem( NULL );
  151. m_canvas->SetIgnoreMouseEvents( true );
  152. wxString Name = SelectComponentFromLibrary( aLibname, aHistoryList, aHistoryLastUnit,
  153. aUseLibBrowser, &unit, &convert );
  154. if( Name.IsEmpty() )
  155. {
  156. m_canvas->SetIgnoreMouseEvents( false );
  157. m_canvas->MoveCursorToCrossHair();
  158. return NULL;
  159. }
  160. #ifndef KICAD_KEEPCASE
  161. Name.MakeUpper();
  162. #endif
  163. LIB_COMPONENT* Entry = CMP_LIBRARY::FindLibraryComponent( Name, aLibname );
  164. m_canvas->SetIgnoreMouseEvents( false );
  165. m_canvas->MoveCursorToCrossHair();
  166. if( Entry == NULL )
  167. {
  168. wxString msg;
  169. msg.Printf( _( "Failed to find part <%s> in library" ), GetChars( Name ) );
  170. wxMessageBox( msg );
  171. return NULL;
  172. }
  173. SCH_COMPONENT* component;
  174. component = new SCH_COMPONENT( *Entry, m_CurrentSheet, unit, convert,
  175. GetCrossHairPosition(), true );
  176. // Set the m_ChipName value, from component name in lib, for aliases
  177. // Note if Entry is found, and if Name is an alias of a component,
  178. // alias exists because its root component was found
  179. component->SetLibName( Name );
  180. // Set the component value that can differ from component name in lib, for aliases
  181. component->GetField( VALUE )->SetText( Name );
  182. MSG_PANEL_ITEMS items;
  183. component->SetCurrentSheetPath( &GetCurrentSheet() );
  184. component->GetMsgPanelInfo( items );
  185. SetMsgPanel( items );
  186. component->Draw( m_canvas, aDC, wxPoint( 0, 0 ), g_XorMode );
  187. component->SetFlags( IS_NEW );
  188. MoveItem( (SCH_ITEM*) component, aDC );
  189. return component;
  190. }
  191. void SCH_EDIT_FRAME::OrientComponent( COMPONENT_ORIENTATION_T aOrientation )
  192. {
  193. SCH_SCREEN* screen = GetScreen();
  194. SCH_ITEM* item = screen->GetCurItem();
  195. wxCHECK_RET( item != NULL && item->Type() == SCH_COMPONENT_T,
  196. wxT( "Cannot change orientation of invalid schematic item." ) );
  197. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  198. m_canvas->MoveCursorToCrossHair();
  199. if( component->GetFlags() == 0 )
  200. {
  201. SaveCopyInUndoList( item, UR_CHANGED );
  202. GetScreen()->SetCurItem( NULL );
  203. }
  204. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  205. // Erase the previous component in it's current orientation.
  206. m_canvas->CrossHairOff( &dc );
  207. if( component->GetFlags() )
  208. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode );
  209. else
  210. {
  211. component->SetFlags( IS_MOVED ); // do not redraw the component
  212. m_canvas->RefreshDrawingRect( component->GetBoundingBox() );
  213. component->ClearFlags( IS_MOVED );
  214. }
  215. component->SetOrientation( aOrientation );
  216. /* Redraw the component in the new position. */
  217. if( component->GetFlags() )
  218. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode );
  219. else
  220. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
  221. m_canvas->CrossHairOn( &dc );
  222. GetScreen()->TestDanglingEnds( m_canvas, &dc );
  223. OnModify();
  224. }
  225. /*
  226. * Handle select part in multi-part component.
  227. */
  228. void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
  229. {
  230. SCH_SCREEN* screen = GetScreen();
  231. SCH_ITEM* item = screen->GetCurItem();
  232. wxCHECK_RET( item != NULL && item->Type() == SCH_COMPONENT_T,
  233. wxT( "Cannot select unit of invalid schematic item." ) );
  234. INSTALL_UNBUFFERED_DC( dc, m_canvas );
  235. m_canvas->MoveCursorToCrossHair();
  236. SCH_COMPONENT* component = (SCH_COMPONENT*) item;
  237. int unit = aEvent.GetId() + 1 - ID_POPUP_SCH_SELECT_UNIT1;
  238. LIB_COMPONENT* libEntry = CMP_LIBRARY::FindLibraryComponent( component->GetLibName() );
  239. if( libEntry == NULL )
  240. return;
  241. wxCHECK_RET( (unit >= 1) && (unit <= libEntry->GetPartCount()),
  242. wxString::Format( wxT( "Cannot select unit %d from component "), unit ) +
  243. libEntry->GetName() );
  244. int unitCount = libEntry->GetPartCount();
  245. if( (unitCount <= 1) || (component->GetUnit() == unit) )
  246. return;
  247. if( unit < 1 )
  248. unit = 1;
  249. if( unit > unitCount )
  250. unit = unitCount;
  251. STATUS_FLAGS flags = component->GetFlags();
  252. if( !flags ) // No command in progress: save in undo list
  253. SaveCopyInUndoList( component, UR_CHANGED );
  254. if( flags )
  255. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode, g_GhostColor );
  256. else
  257. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode );
  258. /* Update the unit number. */
  259. component->SetUnitSelection( m_CurrentSheet, unit );
  260. component->SetUnit( unit );
  261. component->ClearFlags();
  262. component->SetFlags( flags ); // Restore m_Flag modified by SetUnit()
  263. /* Redraw the component in the new position. */
  264. if( flags )
  265. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), g_XorMode, g_GhostColor );
  266. else
  267. component->Draw( m_canvas, &dc, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
  268. screen->TestDanglingEnds( m_canvas, &dc );
  269. OnModify();
  270. }
  271. void SCH_EDIT_FRAME::ConvertPart( SCH_COMPONENT* DrawComponent, wxDC* DC )
  272. {
  273. LIB_COMPONENT* LibEntry;
  274. if( DrawComponent == NULL )
  275. return;
  276. LibEntry = CMP_LIBRARY::FindLibraryComponent( DrawComponent->GetLibName() );
  277. if( LibEntry == NULL )
  278. return;
  279. if( !LibEntry->HasConversion() )
  280. {
  281. DisplayError( this, wxT( "No convert found" ) );
  282. return;
  283. }
  284. STATUS_FLAGS flags = DrawComponent->GetFlags();
  285. if( DrawComponent->GetFlags() )
  286. DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode, g_GhostColor );
  287. else
  288. DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode );
  289. DrawComponent->SetConvert( DrawComponent->GetConvert() + 1 );
  290. // ensure m_Convert = 0, 1 or 2
  291. // 0 and 1 = shape 1 = not converted
  292. // 2 = shape 2 = first converted shape
  293. // > 2 is not used but could be used for more shapes
  294. // like multiple shapes for a programmable component
  295. // When m_Convert = val max, return to the first shape
  296. if( DrawComponent->GetConvert() > 2 )
  297. DrawComponent->SetConvert( 1 );
  298. DrawComponent->ClearFlags();
  299. DrawComponent->SetFlags( flags ); // Restore m_Flag (modified by SetConvert())
  300. /* Redraw the component in the new position. */
  301. if( DrawComponent->IsMoving() )
  302. DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode, g_GhostColor );
  303. else
  304. DrawComponent->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
  305. GetScreen()->TestDanglingEnds( m_canvas, DC );
  306. OnModify( );
  307. }