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.

802 lines
20 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2017 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. /**
  25. * @file sch_line.cpp
  26. * @brief Class SCH_LINE implementation
  27. */
  28. #include <fctsys.h>
  29. #include <gr_basic.h>
  30. #include <macros.h>
  31. #include <sch_draw_panel.h>
  32. #include <plotter.h>
  33. #include <base_units.h>
  34. #include <eeschema_config.h>
  35. #include <general.h>
  36. #include <list_operations.h>
  37. #include <sch_line.h>
  38. #include <sch_edit_frame.h>
  39. #include <netlist_object.h>
  40. #include <sch_view.h>
  41. #include <dialogs/dialog_edit_line_style.h>
  42. static wxPenStyle getwxPenStyle( PlotDashType aType )
  43. {
  44. switch( aType )
  45. {
  46. case PLOTDASHTYPE_SOLID: return wxPENSTYLE_SOLID;
  47. case PLOTDASHTYPE_DASH: return wxPENSTYLE_SHORT_DASH;
  48. case PLOTDASHTYPE_DOT: return wxPENSTYLE_DOT;
  49. case PLOTDASHTYPE_DASHDOT: return wxPENSTYLE_DOT_DASH;
  50. }
  51. wxFAIL_MSG( "Unhandled PlotDashType" );
  52. return wxPENSTYLE_SOLID;
  53. }
  54. SCH_LINE::SCH_LINE( const wxPoint& pos, int layer ) :
  55. SCH_ITEM( NULL, SCH_LINE_T )
  56. {
  57. m_start = pos;
  58. m_end = pos;
  59. m_startIsDangling = m_endIsDangling = false;
  60. m_size = 0;
  61. m_style = -1;
  62. m_color = COLOR4D::UNSPECIFIED;
  63. switch( layer )
  64. {
  65. default:
  66. m_Layer = LAYER_NOTES;
  67. break;
  68. case LAYER_WIRE:
  69. m_Layer = LAYER_WIRE;
  70. break;
  71. case LAYER_BUS:
  72. m_Layer = LAYER_BUS;
  73. break;
  74. }
  75. }
  76. SCH_LINE::SCH_LINE( const SCH_LINE& aLine ) :
  77. SCH_ITEM( aLine )
  78. {
  79. m_start = aLine.m_start;
  80. m_end = aLine.m_end;
  81. m_size = aLine.m_size;
  82. m_style = aLine.m_style;
  83. m_color = aLine.m_color;
  84. m_startIsDangling = aLine.m_startIsDangling;
  85. m_endIsDangling = aLine.m_endIsDangling;
  86. }
  87. EDA_ITEM* SCH_LINE::Clone() const
  88. {
  89. return new SCH_LINE( *this );
  90. }
  91. static const char* style_names[] =
  92. {
  93. "solid", "dashed", "dotted", "dash_dot", nullptr
  94. };
  95. const char* SCH_LINE::GetLineStyleName( int aStyle )
  96. {
  97. const char * styleName = style_names[1];
  98. switch( aStyle )
  99. {
  100. case PLOTDASHTYPE_SOLID:
  101. styleName = style_names[0];
  102. break;
  103. default:
  104. case PLOTDASHTYPE_DASH:
  105. styleName = style_names[1];
  106. break;
  107. case PLOTDASHTYPE_DOT:
  108. styleName = style_names[2];
  109. break;
  110. case PLOTDASHTYPE_DASHDOT:
  111. styleName = style_names[3];
  112. break;
  113. }
  114. return styleName;
  115. }
  116. int SCH_LINE::GetLineStyleInternalId( const wxString& aStyleName )
  117. {
  118. int id = -1; // Default style id
  119. for( int ii = 0; style_names[ii] != nullptr; ii++ )
  120. {
  121. if( aStyleName == style_names[ii] )
  122. {
  123. id = ii;
  124. break;
  125. }
  126. }
  127. return id;
  128. }
  129. void SCH_LINE::Move( const wxPoint& aOffset )
  130. {
  131. if( (m_Flags & STARTPOINT) == 0 && aOffset != wxPoint( 0, 0 ) )
  132. {
  133. m_start += aOffset;
  134. SetModified();
  135. }
  136. if( (m_Flags & ENDPOINT) == 0 && aOffset != wxPoint( 0, 0 ) )
  137. {
  138. m_end += aOffset;
  139. SetModified();
  140. }
  141. }
  142. #if defined(DEBUG)
  143. void SCH_LINE::Show( int nestLevel, std::ostream& os ) const
  144. {
  145. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
  146. << " layer=\"" << m_Layer << '"'
  147. << " startIsDangling=\"" << m_startIsDangling
  148. << '"' << " endIsDangling=\""
  149. << m_endIsDangling << '"' << ">"
  150. << " <start" << m_start << "/>"
  151. << " <end" << m_end << "/>" << "</"
  152. << GetClass().Lower().mb_str() << ">\n";
  153. }
  154. #endif
  155. const EDA_RECT SCH_LINE::GetBoundingBox() const
  156. {
  157. int width = 25;
  158. int xmin = std::min( m_start.x, m_end.x ) - width;
  159. int ymin = std::min( m_start.y, m_end.y ) - width;
  160. int xmax = std::max( m_start.x, m_end.x ) + width;
  161. int ymax = std::max( m_start.y, m_end.y ) + width;
  162. // return a rectangle which is [pos,dim) in nature. therefore the +1
  163. EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin + 1, ymax - ymin + 1 ) );
  164. return ret;
  165. }
  166. double SCH_LINE::GetLength() const
  167. {
  168. return GetLineLength( m_start, m_end );
  169. }
  170. COLOR4D SCH_LINE::GetDefaultColor() const
  171. {
  172. return GetLayerColor( m_Layer );
  173. }
  174. void SCH_LINE::SetLineColor( const COLOR4D aColor )
  175. {
  176. if( aColor == GetDefaultColor() )
  177. m_color = COLOR4D::UNSPECIFIED;
  178. else
  179. m_color = aColor;
  180. }
  181. void SCH_LINE::SetLineColor( const double r, const double g, const double b, const double a )
  182. {
  183. COLOR4D newColor(r, g, b, a);
  184. if( newColor == GetDefaultColor() || newColor == COLOR4D::UNSPECIFIED )
  185. m_color = COLOR4D::UNSPECIFIED;
  186. else
  187. {
  188. // Eeschema does not allow alpha channel in colors
  189. newColor.a = 1.0;
  190. m_color = newColor;
  191. }
  192. }
  193. COLOR4D SCH_LINE::GetLineColor() const
  194. {
  195. if( m_color == COLOR4D::UNSPECIFIED )
  196. return GetLayerColor( m_Layer );
  197. return m_color;
  198. }
  199. int SCH_LINE::GetDefaultStyle() const
  200. {
  201. if( m_Layer == LAYER_NOTES )
  202. return PLOTDASHTYPE_DASH;
  203. return PLOTDASHTYPE_SOLID;
  204. }
  205. void SCH_LINE::SetLineStyle( const int aStyle )
  206. {
  207. if( aStyle == GetDefaultStyle() )
  208. m_style = -1;
  209. else
  210. m_style = aStyle;
  211. }
  212. int SCH_LINE::GetLineStyle() const
  213. {
  214. if( m_style >= 0 )
  215. return m_style;
  216. return GetDefaultStyle();
  217. }
  218. int SCH_LINE::GetDefaultWidth() const
  219. {
  220. if( m_Layer == LAYER_BUS )
  221. return GetDefaultBusThickness();
  222. return GetDefaultLineThickness();
  223. }
  224. void SCH_LINE::SetLineWidth( const int aSize )
  225. {
  226. if( aSize == GetDefaultWidth() )
  227. m_size = 0;
  228. else
  229. m_size = aSize;
  230. }
  231. int SCH_LINE::GetPenSize() const
  232. {
  233. if( m_size > 0 )
  234. return m_size;
  235. if( m_Layer == LAYER_BUS )
  236. return GetDefaultBusThickness();
  237. return GetDefaultLineThickness();
  238. }
  239. void SCH_LINE::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset,
  240. GR_DRAWMODE DrawMode, COLOR4D Color )
  241. {
  242. COLOR4D color;
  243. int width = GetPenSize();
  244. if( Color != COLOR4D::UNSPECIFIED )
  245. color = Color;
  246. else if( m_color != COLOR4D::UNSPECIFIED )
  247. color = m_color;
  248. else
  249. color = GetLayerColor( GetState( BRIGHTENED ) ? LAYER_BRIGHTENED : m_Layer );
  250. GRSetDrawMode( DC, DrawMode );
  251. wxPoint start = m_start;
  252. wxPoint end = m_end;
  253. if( ( m_Flags & STARTPOINT ) == 0 )
  254. start += offset;
  255. if( ( m_Flags & ENDPOINT ) == 0 )
  256. end += offset;
  257. GRLine( panel->GetClipBox(), DC, start.x, start.y, end.x, end.y, width, color,
  258. getwxPenStyle( (PlotDashType) GetLineStyle() ) );
  259. if( m_startIsDangling )
  260. DrawDanglingSymbol( panel, DC, start, color );
  261. if( m_endIsDangling )
  262. DrawDanglingSymbol( panel, DC, end, color );
  263. }
  264. void SCH_LINE::MirrorX( int aXaxis_position )
  265. {
  266. MIRROR( m_start.y, aXaxis_position );
  267. MIRROR( m_end.y, aXaxis_position );
  268. }
  269. void SCH_LINE::MirrorY( int aYaxis_position )
  270. {
  271. MIRROR( m_start.x, aYaxis_position );
  272. MIRROR( m_end.x, aYaxis_position );
  273. }
  274. void SCH_LINE::Rotate( wxPoint aPosition )
  275. {
  276. RotatePoint( &m_start, aPosition, 900 );
  277. RotatePoint( &m_end, aPosition, 900 );
  278. }
  279. bool SCH_LINE::IsSameQuadrant( SCH_LINE* aLine, const wxPoint& aPosition )
  280. {
  281. wxPoint first;
  282. wxPoint second;
  283. if( m_start == aPosition )
  284. first = m_end - aPosition;
  285. else if( m_end == aPosition )
  286. first = m_start - aPosition;
  287. else
  288. return false;
  289. if( aLine->m_start == aPosition )
  290. second = aLine->m_end - aPosition;
  291. else if( aLine->m_end == aPosition )
  292. second = aLine->m_start - aPosition;
  293. else
  294. return false;
  295. return ( sign( first.x ) == sign( second.x ) &&
  296. sign( first.y ) == sign( second.y ) );
  297. }
  298. bool SCH_LINE::IsParallel( SCH_LINE* aLine )
  299. {
  300. wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, false,
  301. wxT( "Cannot test line segment for overlap." ) );
  302. wxPoint firstSeg = m_end - m_start;
  303. wxPoint secondSeg = aLine->m_end - aLine->m_start;
  304. // Use long long here to avoid overflow in calculations
  305. return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
  306. }
  307. EDA_ITEM* SCH_LINE::MergeOverlap( SCH_LINE* aLine )
  308. {
  309. auto less = []( const wxPoint& lhs, const wxPoint& rhs ) -> bool
  310. {
  311. if( lhs.x == rhs.x )
  312. return lhs.y < rhs.y;
  313. return lhs.x < rhs.x;
  314. };
  315. wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, NULL,
  316. wxT( "Cannot test line segment for overlap." ) );
  317. if( this == aLine || GetLayer() != aLine->GetLayer() )
  318. return NULL;
  319. SCH_LINE leftmost = SCH_LINE( *aLine );
  320. SCH_LINE rightmost = SCH_LINE( *this );
  321. // We place the start to the left and below the end of both lines
  322. if( leftmost.m_start != std::min( { leftmost.m_start, leftmost.m_end }, less ) )
  323. std::swap( leftmost.m_start, leftmost.m_end );
  324. if( rightmost.m_start != std::min( { rightmost.m_start, rightmost.m_end }, less ) )
  325. std::swap( rightmost.m_start, rightmost.m_end );
  326. // -leftmost is the line that starts farthest to the left
  327. // -other is the line that is _not_ leftmost
  328. // -rightmost is the line that ends farthest to the right. This may or
  329. // may not be 'other' as the second line may be completely covered by
  330. // the first.
  331. if( less( rightmost.m_start, leftmost.m_start ) )
  332. std::swap( leftmost, rightmost );
  333. SCH_LINE other = SCH_LINE( rightmost );
  334. if( less( rightmost.m_end, leftmost.m_end ) )
  335. rightmost = leftmost;
  336. // If we end one before the beginning of the other, no overlap is possible
  337. if( less( leftmost.m_end, other.m_start ) )
  338. {
  339. return NULL;
  340. }
  341. // Search for a common end:
  342. if( ( leftmost.m_start == other.m_start )
  343. && ( leftmost.m_end == other.m_end ) ) // Trivial case
  344. {
  345. return new SCH_LINE( leftmost );
  346. }
  347. bool colinear = false;
  348. /* Test alignment: */
  349. if( ( leftmost.m_start.y == leftmost.m_end.y )
  350. && ( other.m_start.y == other.m_end.y ) ) // Horizontal segment
  351. {
  352. colinear = ( leftmost.m_start.y == other.m_start.y );
  353. }
  354. else if( ( leftmost.m_start.x == leftmost.m_end.x )
  355. && ( other.m_start.x == other.m_end.x ) ) // Vertical segment
  356. {
  357. colinear = ( leftmost.m_start.x == other.m_start.x );
  358. }
  359. else
  360. {
  361. // We use long long here to avoid overflow -- it enforces promotion
  362. // Don't use double as we need to make a direct comparison
  363. // The slope of the left-most line is dy/dx. Then we check that the slope
  364. // from the left most start to the right most start is the same as well as
  365. // the slope from the left most start to right most end.
  366. long long dx = leftmost.m_end.x - leftmost.m_start.x;
  367. long long dy = leftmost.m_end.y - leftmost.m_start.y;
  368. colinear = ( ( ( other.m_start.y - leftmost.m_start.y ) * dx ==
  369. ( other.m_start.x - leftmost.m_start.x ) * dy ) &&
  370. ( ( other.m_end.y - leftmost.m_start.y ) * dx ==
  371. ( other.m_end.x - leftmost.m_start.x ) * dy ) );
  372. }
  373. // Make a new segment that merges the 2 segments
  374. if( colinear )
  375. {
  376. leftmost.m_end = rightmost.m_end;
  377. return new SCH_LINE( leftmost );
  378. }
  379. return NULL;
  380. }
  381. void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  382. {
  383. if( GetLayer() == LAYER_NOTES )
  384. return;
  385. if( ( GetLayer() == LAYER_BUS ) || ( GetLayer() == LAYER_WIRE ) )
  386. {
  387. DANGLING_END_ITEM item( (GetLayer() == LAYER_BUS) ? BUS_START_END : WIRE_START_END, this,
  388. m_start );
  389. aItemList.push_back( item );
  390. DANGLING_END_ITEM item1( (GetLayer() == LAYER_BUS) ? BUS_END_END : WIRE_END_END, this,
  391. m_end );
  392. aItemList.push_back( item1 );
  393. }
  394. }
  395. bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
  396. {
  397. bool previousStartState = m_startIsDangling;
  398. bool previousEndState = m_endIsDangling;
  399. m_startIsDangling = m_endIsDangling = true;
  400. if( GetLayer() == LAYER_WIRE )
  401. {
  402. for( DANGLING_END_ITEM item : aItemList )
  403. {
  404. if( item.GetItem() == this )
  405. continue;
  406. if( item.GetType() == BUS_START_END ||
  407. item.GetType() == BUS_END_END ||
  408. item.GetType() == BUS_ENTRY_END )
  409. continue;
  410. if( m_start == item.GetPosition() )
  411. m_startIsDangling = false;
  412. if( m_end == item.GetPosition() )
  413. m_endIsDangling = false;
  414. if( (m_startIsDangling == false) && (m_endIsDangling == false) )
  415. break;
  416. }
  417. }
  418. else if( GetLayer() == LAYER_BUS || GetLayer() == LAYER_NOTES )
  419. {
  420. // Lines on the notes layer and the bus layer cannot be tested for dangling ends.
  421. previousStartState = previousEndState = m_startIsDangling = m_endIsDangling = false;
  422. }
  423. return ( previousStartState != m_startIsDangling ) || ( previousEndState != m_endIsDangling );
  424. }
  425. bool SCH_LINE::IsSelectStateChanged( const wxRect& aRect )
  426. {
  427. bool previousState = IsSelected();
  428. if( aRect.Contains( m_start ) && aRect.Contains( m_end ) )
  429. {
  430. SetFlags( SELECTED );
  431. ClearFlags( STARTPOINT | ENDPOINT );
  432. }
  433. else if( aRect.Contains( m_start ) )
  434. {
  435. ClearFlags( STARTPOINT );
  436. SetFlags( SELECTED | ENDPOINT );
  437. }
  438. else if( aRect.Contains( m_end ) )
  439. {
  440. ClearFlags( ENDPOINT );
  441. SetFlags( SELECTED | STARTPOINT );
  442. }
  443. else
  444. {
  445. ClearFlags( SELECTED | STARTPOINT | ENDPOINT );
  446. }
  447. return previousState != IsSelected();
  448. }
  449. bool SCH_LINE::IsConnectable() const
  450. {
  451. if( m_Layer == LAYER_WIRE || m_Layer == LAYER_BUS )
  452. return true;
  453. return false;
  454. }
  455. bool SCH_LINE::CanConnect( const SCH_ITEM* aItem ) const
  456. {
  457. switch( aItem->Type() )
  458. {
  459. case SCH_JUNCTION_T:
  460. case SCH_NO_CONNECT_T:
  461. case SCH_LABEL_T:
  462. case SCH_GLOBAL_LABEL_T:
  463. case SCH_HIERARCHICAL_LABEL_T:
  464. case SCH_BUS_WIRE_ENTRY_T:
  465. case SCH_COMPONENT_T:
  466. case SCH_SHEET_T:
  467. case SCH_SHEET_PIN_T:
  468. return true;
  469. default:
  470. return aItem->GetLayer() == m_Layer;
  471. }
  472. }
  473. void SCH_LINE::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const
  474. {
  475. aPoints.push_back( m_start );
  476. aPoints.push_back( m_end );
  477. }
  478. wxString SCH_LINE::GetSelectMenuText( EDA_UNITS_T aUnits ) const
  479. {
  480. wxString txtfmt, orient;
  481. if( m_start.x == m_end.x )
  482. orient = _( "Vertical" );
  483. else if( m_start.y == m_end.y )
  484. orient = _( "Horizontal" );
  485. switch( m_Layer )
  486. {
  487. case LAYER_NOTES:
  488. txtfmt = _( "%s Graphic Line from (%s, %s) to (%s, %s)" );
  489. break;
  490. case LAYER_WIRE:
  491. txtfmt = _( "%s Wire from (%s, %s) to (%s, %s)" );
  492. break;
  493. case LAYER_BUS:
  494. txtfmt = _( "%s Bus from (%s, %s) to (%s, %s)" );
  495. break;
  496. default:
  497. txtfmt = _( "%s Line on Unknown Layer from (%s, %s) to (%s, %s)" );
  498. }
  499. return wxString::Format( txtfmt,
  500. orient,
  501. MessageTextFromValue( aUnits, m_start.x ),
  502. MessageTextFromValue( aUnits, m_start.y ),
  503. MessageTextFromValue( aUnits, m_end.x ),
  504. MessageTextFromValue( aUnits, m_end.y ) );
  505. }
  506. BITMAP_DEF SCH_LINE::GetMenuImage() const
  507. {
  508. if( m_Layer == LAYER_NOTES )
  509. return add_dashed_line_xpm;
  510. else if( m_Layer == LAYER_WIRE )
  511. return add_line_xpm;
  512. return add_bus_xpm;
  513. }
  514. void SCH_LINE::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems,
  515. SCH_SHEET_PATH* aSheetPath )
  516. {
  517. // Net list item not required for graphic lines.
  518. if( (GetLayer() != LAYER_BUS) && (GetLayer() != LAYER_WIRE) )
  519. return;
  520. NETLIST_OBJECT* item = new NETLIST_OBJECT();
  521. item->m_SheetPath = *aSheetPath;
  522. item->m_SheetPathInclude = *aSheetPath;
  523. item->m_Comp = (SCH_ITEM*) this;
  524. item->m_Start = m_start;
  525. item->m_End = m_end;
  526. if( GetLayer() == LAYER_BUS )
  527. {
  528. item->m_Type = NET_BUS;
  529. }
  530. else /* WIRE */
  531. {
  532. item->m_Type = NET_SEGMENT;
  533. }
  534. aNetListItems.push_back( item );
  535. }
  536. bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
  537. {
  538. if( Type() != aItem.Type() )
  539. return Type() < aItem.Type();
  540. SCH_LINE* line = (SCH_LINE*) &aItem;
  541. if( GetLength() != line->GetLength() )
  542. return GetLength() < line->GetLength();
  543. if( m_start.x != line->m_start.x )
  544. return m_start.x < line->m_start.x;
  545. if( m_start.y != line->m_start.y )
  546. return m_start.y < line->m_start.y;
  547. return false;
  548. }
  549. bool SCH_LINE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
  550. {
  551. return TestSegmentHit( aPosition, m_start, m_end, aAccuracy );
  552. }
  553. bool SCH_LINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  554. {
  555. if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) )
  556. return false;
  557. EDA_RECT rect = aRect;
  558. if ( aAccuracy )
  559. rect.Inflate( aAccuracy );
  560. if( aContained )
  561. return rect.Contains( m_start ) && rect.Contains( m_end );
  562. return rect.Intersects( m_start, m_end );
  563. }
  564. void SCH_LINE::SwapData( SCH_ITEM* aItem )
  565. {
  566. SCH_LINE* item = (SCH_LINE*) aItem;
  567. std::swap( m_Layer, item->m_Layer );
  568. std::swap( m_start, item->m_start );
  569. std::swap( m_end, item->m_end );
  570. std::swap( m_startIsDangling, item->m_startIsDangling );
  571. std::swap( m_endIsDangling, item->m_endIsDangling );
  572. std::swap( m_style, item->m_style );
  573. std::swap( m_size, item->m_size );
  574. std::swap( m_color, item->m_color );
  575. }
  576. bool SCH_LINE::doIsConnected( const wxPoint& aPosition ) const
  577. {
  578. if( m_Layer != LAYER_WIRE && m_Layer != LAYER_BUS )
  579. return false;
  580. return IsEndPoint( aPosition );
  581. }
  582. void SCH_LINE::Plot( PLOTTER* aPlotter )
  583. {
  584. if( m_color != COLOR4D::UNSPECIFIED )
  585. aPlotter->SetColor( m_color );
  586. else
  587. aPlotter->SetColor( GetLayerColor( GetLayer() ) );
  588. aPlotter->SetCurrentLineWidth( GetPenSize() );
  589. aPlotter->SetDash( GetLineStyle() );
  590. aPlotter->MoveTo( m_start );
  591. aPlotter->FinishTo( m_end );
  592. aPlotter->SetDash( 0 );
  593. }
  594. void SCH_LINE::SetPosition( const wxPoint& aPosition )
  595. {
  596. m_end = m_end - ( m_start - aPosition );
  597. m_start = aPosition;
  598. }
  599. wxPoint SCH_LINE::MidPoint()
  600. {
  601. return wxPoint( ( m_start.x + m_end.x ) / 2, ( m_start.y + m_end.y ) / 2 );
  602. }
  603. int SCH_EDIT_FRAME::EditLine( SCH_LINE* aLine, bool aRedraw )
  604. {
  605. if( aLine == NULL )
  606. return wxID_CANCEL;
  607. // We purposely disallow editing everything except graphic lines
  608. if( aLine->GetLayer() != LAYER_NOTES )
  609. return wxID_CANCEL;
  610. DIALOG_EDIT_LINE_STYLE dlg( this, aLine );
  611. if( dlg.ShowModal() == wxID_CANCEL )
  612. return wxID_CANCEL;
  613. if( aRedraw )
  614. RefreshItem( aLine );
  615. return wxID_OK;
  616. }