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.

1540 lines
53 KiB

2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 CERN
  5. * Copyright (C) 2019-2023 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. #include <functional>
  25. using namespace std::placeholders;
  26. #include "ee_point_editor.h"
  27. #include <ee_grid_helper.h>
  28. #include <tool/tool_manager.h>
  29. #include <sch_commit.h>
  30. #include <view/view_controls.h>
  31. #include <gal/graphics_abstraction_layer.h>
  32. #include <geometry/seg.h>
  33. #include <tools/ee_actions.h>
  34. #include <tools/ee_selection_tool.h>
  35. #include <sch_edit_frame.h>
  36. #include <sch_line.h>
  37. #include <sch_bitmap.h>
  38. #include <sch_sheet.h>
  39. #include <sch_textbox.h>
  40. #include <sch_shape.h>
  41. #include <sch_sheet_pin.h>
  42. #include <symbol_edit_frame.h>
  43. #include <lib_shape.h>
  44. #include <lib_textbox.h>
  45. // Few constants to avoid using bare numbers for point indices
  46. enum ARC_POINTS
  47. {
  48. ARC_START, ARC_END, ARC_CENTER
  49. };
  50. enum CIRCLE_POINTS
  51. {
  52. CIRC_CENTER, CIRC_END
  53. };
  54. enum RECTANGLE_POINTS
  55. {
  56. RECT_TOPLEFT, RECT_TOPRIGHT, RECT_BOTLEFT, RECT_BOTRIGHT
  57. };
  58. enum RECTANGLE_LINES
  59. {
  60. RECT_TOP, RECT_RIGHT, RECT_BOT, RECT_LEFT
  61. };
  62. enum LINE_POINTS
  63. {
  64. LINE_START, LINE_END
  65. };
  66. enum BEZIER_CURVE_POINTS
  67. {
  68. BEZIER_CURVE_START,
  69. BEZIER_CURVE_CONTROL_POINT1,
  70. BEZIER_CURVE_CONTROL_POINT2,
  71. BEZIER_CURVE_END
  72. };
  73. class EDIT_POINTS_FACTORY
  74. {
  75. public:
  76. static std::shared_ptr<EDIT_POINTS> Make( EDA_ITEM* aItem, SCH_BASE_FRAME* frame )
  77. {
  78. std::shared_ptr<EDIT_POINTS> points = std::make_shared<EDIT_POINTS>( aItem );
  79. if( !aItem )
  80. return points;
  81. // Generate list of edit points based on the item type
  82. switch( aItem->Type() )
  83. {
  84. case LIB_SHAPE_T:
  85. {
  86. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( aItem );
  87. switch( shape->GetShape() )
  88. {
  89. case SHAPE_T::ARC:
  90. points->AddPoint( mapCoords( shape->GetStart() ) );
  91. points->AddPoint( mapCoords( shape->GetEnd() ) );
  92. points->AddPoint( mapCoords( shape->GetPosition() ) );
  93. break;
  94. case SHAPE_T::CIRCLE:
  95. points->AddPoint( mapCoords( shape->GetPosition() ) );
  96. points->AddPoint( mapCoords( shape->GetEnd() ) );
  97. break;
  98. case SHAPE_T::RECTANGLE:
  99. {
  100. shape->Normalize();
  101. VECTOR2I topLeft = mapCoords( shape->GetPosition() );
  102. VECTOR2I botRight = mapCoords( shape->GetEnd() );
  103. points->AddPoint( topLeft );
  104. points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
  105. points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
  106. points->AddPoint( botRight );
  107. points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
  108. points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
  109. points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
  110. points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
  111. points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
  112. points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
  113. points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
  114. points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
  115. break;
  116. }
  117. case SHAPE_T::POLY:
  118. for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
  119. points->AddPoint( mapCoords( pt ) );
  120. break;
  121. case SHAPE_T::BEZIER:
  122. points->AddPoint( mapCoords( shape->GetStart() ) );
  123. points->AddPoint( mapCoords( shape->GetBezierC1() ) );
  124. points->AddPoint( mapCoords( shape->GetBezierC2() ) );
  125. points->AddPoint( mapCoords( shape->GetEnd() ) );
  126. break;
  127. default:
  128. UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
  129. }
  130. break;
  131. }
  132. case LIB_TEXTBOX_T:
  133. {
  134. LIB_TEXTBOX* textBox = static_cast<LIB_TEXTBOX*>( aItem );
  135. textBox->Normalize();
  136. VECTOR2I topLeft = mapCoords( textBox->GetPosition() );
  137. VECTOR2I botRight = mapCoords( textBox->GetEnd() );
  138. points->AddPoint( topLeft );
  139. points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
  140. points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
  141. points->AddPoint( botRight );
  142. points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
  143. points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
  144. points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
  145. points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
  146. points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
  147. points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
  148. points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
  149. points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
  150. break;
  151. }
  152. case SCH_SHAPE_T:
  153. {
  154. SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( aItem );
  155. switch( shape->GetShape() )
  156. {
  157. case SHAPE_T::ARC:
  158. points->AddPoint( shape->GetStart() );
  159. points->AddPoint( shape->GetEnd() );
  160. points->AddPoint( shape->GetPosition() );
  161. break;
  162. case SHAPE_T::CIRCLE:
  163. points->AddPoint( shape->GetPosition() );
  164. points->AddPoint( shape->GetEnd() );
  165. break;
  166. case SHAPE_T::RECTANGLE:
  167. {
  168. shape->Normalize();
  169. VECTOR2I topLeft = shape->GetPosition();
  170. VECTOR2I botRight = shape->GetEnd();
  171. points->AddPoint( topLeft );
  172. points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
  173. points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
  174. points->AddPoint( botRight );
  175. points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
  176. points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
  177. points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
  178. points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
  179. points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
  180. points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
  181. points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
  182. points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
  183. break;
  184. }
  185. case SHAPE_T::POLY:
  186. for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
  187. points->AddPoint( pt );
  188. break;
  189. case SHAPE_T::BEZIER:
  190. points->AddPoint( shape->GetStart() );
  191. points->AddPoint( shape->GetBezierC1() );
  192. points->AddPoint( shape->GetBezierC2() );
  193. points->AddPoint( shape->GetEnd() );
  194. break;
  195. default:
  196. UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
  197. }
  198. break;
  199. }
  200. case SCH_TEXTBOX_T:
  201. {
  202. SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( aItem );
  203. textBox->Normalize();
  204. VECTOR2I topLeft = textBox->GetPosition();
  205. VECTOR2I botRight = textBox->GetEnd();
  206. points->AddPoint( topLeft );
  207. points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
  208. points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
  209. points->AddPoint( botRight );
  210. points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
  211. points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
  212. points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
  213. points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
  214. points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
  215. points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
  216. points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
  217. points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
  218. break;
  219. }
  220. case SCH_SHEET_T:
  221. {
  222. SCH_SHEET* sheet = (SCH_SHEET*) aItem;
  223. VECTOR2I topLeft = sheet->GetPosition();
  224. VECTOR2I botRight = sheet->GetPosition() + sheet->GetSize();
  225. points->AddPoint( topLeft );
  226. points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
  227. points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
  228. points->AddPoint( botRight );
  229. points->AddLine( points->Point( RECT_TOPLEFT ), points->Point( RECT_TOPRIGHT ) );
  230. points->Line( RECT_TOP ).SetConstraint( new EC_PERPLINE( points->Line( RECT_TOP ) ) );
  231. points->AddLine( points->Point( RECT_TOPRIGHT ), points->Point( RECT_BOTRIGHT ) );
  232. points->Line( RECT_RIGHT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_RIGHT ) ) );
  233. points->AddLine( points->Point( RECT_BOTRIGHT ), points->Point( RECT_BOTLEFT ) );
  234. points->Line( RECT_BOT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_BOT ) ) );
  235. points->AddLine( points->Point( RECT_BOTLEFT ), points->Point( RECT_TOPLEFT ) );
  236. points->Line( RECT_LEFT ).SetConstraint( new EC_PERPLINE( points->Line( RECT_LEFT ) ) );
  237. break;
  238. }
  239. case SCH_BITMAP_T:
  240. {
  241. SCH_BITMAP* bitmap = (SCH_BITMAP*) aItem;
  242. VECTOR2I topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
  243. VECTOR2I botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
  244. points->AddPoint( topLeft );
  245. points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
  246. points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
  247. points->AddPoint( botRight );
  248. break;
  249. }
  250. case SCH_LINE_T:
  251. {
  252. SCH_LINE* line = (SCH_LINE*) aItem;
  253. std::pair<EDA_ITEM*, int> connectedStart = { nullptr, STARTPOINT };
  254. std::pair<EDA_ITEM*, int> connectedEnd = { nullptr, STARTPOINT };
  255. for( SCH_ITEM* test : frame->GetScreen()->Items().OfType( SCH_LINE_T ) )
  256. {
  257. if( test->GetLayer() != LAYER_NOTES )
  258. continue;
  259. if( test == aItem )
  260. continue;
  261. SCH_LINE* testLine = static_cast<SCH_LINE*>( test );
  262. if( testLine->GetStartPoint() == line->GetStartPoint() )
  263. {
  264. connectedStart = { testLine, STARTPOINT };
  265. }
  266. else if( testLine->GetEndPoint() == line->GetStartPoint() )
  267. {
  268. connectedStart = { testLine, ENDPOINT };
  269. }
  270. else if( testLine->GetStartPoint() == line->GetEndPoint() )
  271. {
  272. connectedEnd = { testLine, STARTPOINT };
  273. }
  274. else if( testLine->GetEndPoint() == line->GetEndPoint() )
  275. {
  276. connectedEnd = { testLine, ENDPOINT };
  277. }
  278. }
  279. points->AddPoint( line->GetStartPoint(), connectedStart );
  280. points->AddPoint( line->GetEndPoint(), connectedEnd );
  281. break;
  282. }
  283. default:
  284. points.reset();
  285. break;
  286. }
  287. return points;
  288. }
  289. private:
  290. EDIT_POINTS_FACTORY() {};
  291. };
  292. EE_POINT_EDITOR::EE_POINT_EDITOR() :
  293. EE_TOOL_BASE<SCH_BASE_FRAME>( "eeschema.PointEditor" ),
  294. m_editedPoint( nullptr ),
  295. m_inPointEditor( false )
  296. {
  297. }
  298. void EE_POINT_EDITOR::Reset( RESET_REASON aReason )
  299. {
  300. EE_TOOL_BASE::Reset( aReason );
  301. m_editPoints.reset();
  302. m_editedPoint = nullptr;
  303. }
  304. bool EE_POINT_EDITOR::Init()
  305. {
  306. EE_TOOL_BASE::Init();
  307. auto& menu = m_selectionTool->GetToolMenu().GetMenu();
  308. menu.AddItem( EE_ACTIONS::pointEditorAddCorner,
  309. std::bind( &EE_POINT_EDITOR::addCornerCondition, this, _1 ) );
  310. menu.AddItem( EE_ACTIONS::pointEditorRemoveCorner,
  311. std::bind( &EE_POINT_EDITOR::removeCornerCondition, this, _1 ) );
  312. return true;
  313. }
  314. int EE_POINT_EDITOR::clearEditedPoints( const TOOL_EVENT& aEvent )
  315. {
  316. setEditedPoint( nullptr );
  317. return 0;
  318. }
  319. void EE_POINT_EDITOR::updateEditedPoint( const TOOL_EVENT& aEvent )
  320. {
  321. EDIT_POINT* point = m_editedPoint;
  322. if( !m_editPoints )
  323. {
  324. point = nullptr;
  325. }
  326. else if( aEvent.IsMotion() )
  327. {
  328. point = m_editPoints->FindPoint( aEvent.Position(), getView() );
  329. }
  330. else if( aEvent.IsDrag( BUT_LEFT ) )
  331. {
  332. point = m_editPoints->FindPoint( aEvent.DragOrigin(), getView() );
  333. }
  334. else
  335. {
  336. point = m_editPoints->FindPoint( getViewControls()->GetCursorPosition( false ), getView() );
  337. }
  338. if( m_editedPoint != point )
  339. setEditedPoint( point );
  340. }
  341. int EE_POINT_EDITOR::Main( const TOOL_EVENT& aEvent )
  342. {
  343. if( !m_selectionTool )
  344. return 0;
  345. if( m_inPointEditor )
  346. return 0;
  347. REENTRANCY_GUARD guard( &m_inPointEditor );
  348. if( m_isSymbolEditor )
  349. {
  350. SYMBOL_EDIT_FRAME* editor = getEditFrame<SYMBOL_EDIT_FRAME>();
  351. if( !editor->IsSymbolEditable() || editor->IsSymbolAlias() )
  352. return 0;
  353. }
  354. const EE_SELECTION& selection = m_selectionTool->GetSelection();
  355. if( selection.Size() != 1 || !selection.Front()->IsType( { LIB_SHAPE_T, SCH_SHAPE_T,
  356. LIB_TEXTBOX_T, SCH_TEXTBOX_T,
  357. SCH_SHEET_T,
  358. SCH_ITEM_LOCATE_GRAPHIC_LINE_T,
  359. SCH_BITMAP_T } ) )
  360. {
  361. return 0;
  362. }
  363. // Wait till drawing tool is done
  364. if( selection.Front()->IsNew() )
  365. return 0;
  366. Activate();
  367. KIGFX::VIEW_CONTROLS* controls = getViewControls();
  368. EE_GRID_HELPER* grid = new EE_GRID_HELPER( m_toolMgr );
  369. VECTOR2I cursorPos;
  370. KIGFX::VIEW* view = getView();
  371. EDA_ITEM* item = selection.Front();
  372. SCH_COMMIT commit( m_toolMgr );
  373. controls->ShowCursor( true );
  374. m_editPoints = EDIT_POINTS_FACTORY::Make( item, m_frame );
  375. view->Add( m_editPoints.get() );
  376. setEditedPoint( nullptr );
  377. updateEditedPoint( aEvent );
  378. bool inDrag = false;
  379. // Main loop: keep receiving events
  380. while( TOOL_EVENT* evt = Wait() )
  381. {
  382. if( grid )
  383. {
  384. grid->SetSnap( !evt->Modifier( MD_SHIFT ) );
  385. grid->SetUseGrid( getView()->GetGAL()->GetGridSnapping()
  386. && !evt->DisableGridSnapping() );
  387. }
  388. else
  389. {
  390. // This check is based on the assumption that the grid object must be valid.
  391. // If this assumption is wrong, please fix the code above.
  392. wxCHECK( false, 0 );
  393. }
  394. if( !m_editPoints || evt->IsSelectionEvent() )
  395. break;
  396. if ( !inDrag )
  397. updateEditedPoint( *evt );
  398. if( evt->IsDrag( BUT_LEFT ) && m_editedPoint )
  399. {
  400. if( !inDrag )
  401. {
  402. commit.Modify( m_editPoints->GetParent(), m_frame->GetScreen() );
  403. if( m_editPoints->GetParent()->Type() == SCH_LINE_T )
  404. {
  405. std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
  406. if( connected.first )
  407. commit.Modify( connected.first, m_frame->GetScreen() );
  408. connected = m_editPoints->Point( LINE_END ).GetConnected();
  409. if( connected.first )
  410. commit.Modify( connected.first, m_frame->GetScreen() );
  411. }
  412. inDrag = true;
  413. }
  414. bool snap = !evt->DisableGridSnapping();
  415. cursorPos =
  416. grid->Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
  417. controls->ForceCursorPosition( true, cursorPos );
  418. m_editedPoint->SetPosition( controls->GetCursorPosition( snap ) );
  419. updateParentItem( snap );
  420. updatePoints();
  421. }
  422. else if( inDrag && evt->IsMouseUp( BUT_LEFT ) )
  423. {
  424. if( !commit.Empty() )
  425. commit.Push( _( "Move Point" ) );
  426. controls->SetAutoPan( false );
  427. inDrag = false;
  428. }
  429. else if( evt->IsCancelInteractive() || evt->IsActivate() )
  430. {
  431. if( inDrag ) // Restore the last change
  432. {
  433. // Currently we are manually managing the lifetime of the grid
  434. // helpers because there is a bug in the tool stack that adds
  435. // the point editor again when commit.Revert() rebuilds the selection.
  436. // We remove this grid here so the its destructor is called before it
  437. // is added again.
  438. if( grid )
  439. {
  440. delete grid;
  441. grid = nullptr;
  442. }
  443. commit.Revert();
  444. inDrag = false;
  445. break;
  446. }
  447. else if( evt->IsCancelInteractive() )
  448. {
  449. break;
  450. }
  451. if( evt->IsActivate() )
  452. break;
  453. }
  454. else
  455. {
  456. evt->SetPassEvent();
  457. }
  458. controls->SetAutoPan( inDrag );
  459. controls->CaptureCursor( inDrag );
  460. }
  461. controls->SetAutoPan( false );
  462. controls->CaptureCursor( false );
  463. setEditedPoint( nullptr );
  464. if( m_editPoints )
  465. {
  466. view->Remove( m_editPoints.get() );
  467. m_editPoints.reset();
  468. m_frame->GetCanvas()->Refresh();
  469. }
  470. delete grid;
  471. return 0;
  472. }
  473. /**
  474. * Update the coordinates of 4 corners of a rectangle, according to constraints
  475. * and the moved corner
  476. * @param minWidth is the minimal width constraint
  477. * @param minHeight is the minimal height constraint
  478. * @param topLeft is the RECT_TOPLEFT to constraint
  479. * @param topRight is the RECT_TOPRIGHT to constraint
  480. * @param botLeft is the RECT_BOTLEFT to constraint
  481. * @param botRight is the RECT_BOTRIGHT to constraint
  482. */
  483. void EE_POINT_EDITOR::pinEditedCorner( int minWidth, int minHeight, VECTOR2I& topLeft,
  484. VECTOR2I& topRight, VECTOR2I& botLeft, VECTOR2I& botRight,
  485. EE_GRID_HELPER* aGrid ) const
  486. {
  487. if( isModified( m_editPoints->Point( RECT_TOPLEFT ) ) )
  488. {
  489. // pin edited point within opposite corner
  490. topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
  491. topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
  492. if( aGrid->GetSnap() )
  493. topLeft = aGrid->AlignGrid( topLeft, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  494. // push edited point edges to adjacent corners
  495. topRight.y = topLeft.y;
  496. botLeft.x = topLeft.x;
  497. }
  498. else if( isModified( m_editPoints->Point( RECT_TOPRIGHT ) ) )
  499. {
  500. // pin edited point within opposite corner
  501. topRight.x = std::max( topRight.x, botLeft.x + minWidth );
  502. topRight.y = std::min( topRight.y, botLeft.y - minHeight );
  503. if( aGrid->GetSnap() )
  504. topRight = aGrid->AlignGrid( topRight, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  505. // push edited point edges to adjacent corners
  506. topLeft.y = topRight.y;
  507. botRight.x = topRight.x;
  508. }
  509. else if( isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
  510. {
  511. // pin edited point within opposite corner
  512. botLeft.x = std::min( botLeft.x, topRight.x - minWidth );
  513. botLeft.y = std::max( botLeft.y, topRight.y + minHeight );
  514. if( aGrid->GetSnap() )
  515. botLeft = aGrid->AlignGrid( botLeft, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  516. // push edited point edges to adjacent corners
  517. botRight.y = botLeft.y;
  518. topLeft.x = botLeft.x;
  519. }
  520. else if( isModified( m_editPoints->Point( RECT_BOTRIGHT ) ) )
  521. {
  522. // pin edited point within opposite corner
  523. botRight.x = std::max( botRight.x, topLeft.x + minWidth );
  524. botRight.y = std::max( botRight.y, topLeft.y + minHeight );
  525. if( aGrid->GetSnap() )
  526. botRight = aGrid->AlignGrid( botRight, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  527. // push edited point edges to adjacent corners
  528. botLeft.y = botRight.y;
  529. topRight.x = botRight.x;
  530. }
  531. else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
  532. {
  533. topLeft.y = std::min( topLeft.y, botRight.y - minHeight );
  534. if( aGrid->GetSnap() )
  535. topLeft = aGrid->AlignGrid( topLeft, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  536. }
  537. else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
  538. {
  539. topLeft.x = std::min( topLeft.x, botRight.x - minWidth );
  540. if( aGrid->GetSnap() )
  541. topLeft = aGrid->AlignGrid( topLeft, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  542. }
  543. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  544. {
  545. botRight.y = std::max( botRight.y, topLeft.y + minHeight );
  546. if( aGrid->GetSnap() )
  547. botRight = aGrid->AlignGrid( botRight, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  548. }
  549. else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  550. {
  551. botRight.x = std::max( botRight.x, topLeft.x + minWidth );
  552. if( aGrid->GetSnap() )
  553. botRight = aGrid->AlignGrid( botRight, GRID_HELPER_GRIDS::GRID_GRAPHICS );
  554. }
  555. }
  556. void EE_POINT_EDITOR::updateParentItem( bool aSnapToGrid ) const
  557. {
  558. EDA_ITEM* item = m_editPoints->GetParent();
  559. if( !item )
  560. return;
  561. switch( item->Type() )
  562. {
  563. case LIB_SHAPE_T:
  564. {
  565. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
  566. switch( shape->GetShape() )
  567. {
  568. case SHAPE_T::ARC:
  569. if( getEditedPointIndex() == ARC_CENTER )
  570. {
  571. shape->SetEditState( 4 );
  572. shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_CENTER ).GetPosition() ) );
  573. }
  574. else if( getEditedPointIndex() == ARC_START )
  575. {
  576. shape->SetEditState( 2 );
  577. shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_START ).GetPosition() ) );
  578. }
  579. else if( getEditedPointIndex() == ARC_END )
  580. {
  581. shape->SetEditState( 3 );
  582. shape->CalcEdit( mapCoords( m_editPoints->Point( ARC_END ).GetPosition() ) );
  583. }
  584. break;
  585. case SHAPE_T::CIRCLE:
  586. shape->SetPosition( mapCoords( m_editPoints->Point( CIRC_CENTER ).GetPosition() ) );
  587. shape->SetEnd( mapCoords( m_editPoints->Point( CIRC_END ).GetPosition() ) );
  588. break;
  589. case SHAPE_T::POLY:
  590. shape->GetPolyShape().RemoveAllContours();
  591. shape->GetPolyShape().NewOutline();
  592. for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
  593. {
  594. VECTOR2I pt = mapCoords( m_editPoints->Point( i ).GetPosition() );
  595. shape->GetPolyShape().Append( pt.x, pt.y, -1, -1, true );
  596. }
  597. break;
  598. case SHAPE_T::RECTANGLE:
  599. {
  600. EE_GRID_HELPER gridHelper( m_toolMgr );
  601. VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
  602. VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
  603. VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
  604. VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
  605. gridHelper.SetSnap( aSnapToGrid );
  606. pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
  607. botLeft, botRight, &gridHelper );
  608. if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
  609. || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
  610. || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
  611. || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
  612. {
  613. shape->SetPosition( mapCoords( topLeft ) );
  614. shape->SetEnd( mapCoords( botRight ) );
  615. }
  616. else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
  617. {
  618. shape->SetStartY( mapCoords( topLeft ).y );
  619. }
  620. else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
  621. {
  622. shape->SetStartX( mapCoords( topLeft ).x );
  623. }
  624. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  625. {
  626. shape->SetEndY( mapCoords( botRight ).y );
  627. }
  628. else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  629. {
  630. shape->SetEndX( mapCoords( botRight ).x );
  631. }
  632. for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
  633. {
  634. if( !isModified( m_editPoints->Line( i ) ) )
  635. {
  636. m_editPoints->Line( i ).SetConstraint(
  637. new EC_PERPLINE( m_editPoints->Line( i ) ) );
  638. }
  639. }
  640. break;
  641. }
  642. case SHAPE_T::BEZIER:
  643. shape->SetStart( mapCoords( m_editPoints->Point( BEZIER_CURVE_START ).GetPosition() ) );
  644. shape->SetBezierC1( mapCoords( m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ).GetPosition() ) );
  645. shape->SetBezierC2( mapCoords( m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ).GetPosition() ) );
  646. shape->SetEnd( mapCoords( m_editPoints->Point( BEZIER_CURVE_END ).GetPosition() ) );
  647. shape->RebuildBezierToSegmentsPointsList( shape->GetWidth() );
  648. break;
  649. default:
  650. UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
  651. }
  652. break;
  653. }
  654. case LIB_TEXTBOX_T:
  655. {
  656. LIB_TEXTBOX* textbox = static_cast<LIB_TEXTBOX*>( item );
  657. EE_GRID_HELPER gridHelper( m_toolMgr );
  658. VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
  659. VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
  660. VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
  661. VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
  662. gridHelper.SetSnap( aSnapToGrid );
  663. pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
  664. botLeft, botRight, &gridHelper );
  665. if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
  666. || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
  667. || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
  668. || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
  669. {
  670. textbox->SetPosition( mapCoords( topLeft ) );
  671. textbox->SetEnd( mapCoords( botRight ) );
  672. }
  673. else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
  674. {
  675. textbox->SetStartY( mapCoords( topLeft ).y );
  676. }
  677. else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
  678. {
  679. textbox->SetStartX( mapCoords( topLeft ).x );
  680. }
  681. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  682. {
  683. textbox->SetEndY( mapCoords( botRight ).y );
  684. }
  685. else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  686. {
  687. textbox->SetEndX( mapCoords( botRight ).x );
  688. }
  689. for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
  690. {
  691. if( !isModified( m_editPoints->Line( i ) ) )
  692. {
  693. m_editPoints->Line( i ).SetConstraint(
  694. new EC_PERPLINE( m_editPoints->Line( i ) ) );
  695. }
  696. }
  697. textbox->ClearRenderCache();
  698. break;
  699. }
  700. case SCH_SHAPE_T:
  701. {
  702. SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
  703. switch( shape->GetShape() )
  704. {
  705. case SHAPE_T::ARC:
  706. if( getEditedPointIndex() == ARC_START )
  707. {
  708. shape->SetEditState( 2 );
  709. shape->CalcEdit( m_editPoints->Point( ARC_START ).GetPosition() );
  710. }
  711. else if( getEditedPointIndex() == ARC_END )
  712. {
  713. shape->SetEditState( 3 );
  714. shape->CalcEdit( m_editPoints->Point( ARC_END ).GetPosition() );
  715. }
  716. else if( getEditedPointIndex() == ARC_CENTER )
  717. {
  718. shape->SetEditState( 4 );
  719. shape->CalcEdit( m_editPoints->Point( ARC_CENTER ).GetPosition() );
  720. }
  721. break;
  722. case SHAPE_T::CIRCLE:
  723. shape->SetPosition( m_editPoints->Point( CIRC_CENTER ).GetPosition() );
  724. shape->SetEnd( m_editPoints->Point( CIRC_END ).GetPosition() );
  725. break;
  726. case SHAPE_T::POLY:
  727. shape->GetPolyShape().RemoveAllContours();
  728. shape->GetPolyShape().NewOutline();
  729. for( unsigned i = 0; i < m_editPoints->PointsSize(); ++i )
  730. {
  731. VECTOR2I pt = m_editPoints->Point( i ).GetPosition();
  732. shape->GetPolyShape().Append( pt.x, pt.y, -1, -1, true );
  733. }
  734. break;
  735. case SHAPE_T::RECTANGLE:
  736. {
  737. EE_GRID_HELPER gridHelper( m_toolMgr );
  738. VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
  739. VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
  740. VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
  741. VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
  742. gridHelper.SetSnap( aSnapToGrid );
  743. pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
  744. botLeft, botRight, &gridHelper );
  745. if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
  746. || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
  747. || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
  748. || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
  749. {
  750. shape->SetPosition( topLeft );
  751. shape->SetEnd( botRight );
  752. }
  753. else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
  754. {
  755. shape->SetStartY( topLeft.y );
  756. }
  757. else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
  758. {
  759. shape->SetStartX( topLeft.x );
  760. }
  761. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  762. {
  763. shape->SetEndY( botRight.y );
  764. }
  765. else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  766. {
  767. shape->SetEndX( botRight.x );
  768. }
  769. for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
  770. {
  771. if( !isModified( m_editPoints->Line( i ) ) )
  772. {
  773. m_editPoints->Line( i ).SetConstraint(
  774. new EC_PERPLINE( m_editPoints->Line( i ) ) );
  775. }
  776. }
  777. break;
  778. }
  779. case SHAPE_T::BEZIER:
  780. shape->SetStart( m_editPoints->Point( BEZIER_CURVE_START ).GetPosition() );
  781. shape->SetBezierC1( m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ).GetPosition() );
  782. shape->SetBezierC2( m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ).GetPosition() );
  783. shape->SetEnd( m_editPoints->Point( BEZIER_CURVE_END ).GetPosition() );
  784. shape->RebuildBezierToSegmentsPointsList( shape->GetWidth() );
  785. break;
  786. default:
  787. UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
  788. }
  789. break;
  790. }
  791. case SCH_TEXTBOX_T:
  792. {
  793. SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( item );
  794. EE_GRID_HELPER gridHelper( m_toolMgr );
  795. VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
  796. VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
  797. VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
  798. VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
  799. gridHelper.SetSnap( aSnapToGrid );
  800. pinEditedCorner( schIUScale.MilsToIU( 1 ), schIUScale.MilsToIU( 1 ), topLeft, topRight,
  801. botLeft, botRight, &gridHelper );
  802. if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
  803. || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
  804. || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
  805. || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
  806. {
  807. textBox->SetPosition( topLeft );
  808. textBox->SetEnd( botRight );
  809. }
  810. else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
  811. {
  812. textBox->SetStartY( topLeft.y );
  813. }
  814. else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
  815. {
  816. textBox->SetStartX( topLeft.x );
  817. }
  818. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  819. {
  820. textBox->SetEndY( botRight.y );
  821. }
  822. else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  823. {
  824. textBox->SetEndX( botRight.x );
  825. }
  826. for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
  827. {
  828. if( !isModified( m_editPoints->Line( i ) ) )
  829. {
  830. m_editPoints->Line( i ).SetConstraint(
  831. new EC_PERPLINE( m_editPoints->Line( i ) ) );
  832. }
  833. }
  834. textBox->ClearRenderCache();
  835. break;
  836. }
  837. case SCH_BITMAP_T:
  838. {
  839. EE_GRID_HELPER gridHelper( m_toolMgr );
  840. SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
  841. VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
  842. VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
  843. VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
  844. VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
  845. gridHelper.SetSnap( aSnapToGrid );
  846. pinEditedCorner( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ), topLeft, topRight,
  847. botLeft, botRight, &gridHelper );
  848. double oldWidth = bitmap->GetSize().x;
  849. double newWidth = topRight.x - topLeft.x;
  850. double widthRatio = newWidth / oldWidth;
  851. double oldHeight = bitmap->GetSize().y;
  852. double newHeight = botLeft.y - topLeft.y;
  853. double heightRatio = newHeight / oldHeight;
  854. bitmap->SetImageScale( bitmap->GetImageScale() * std::min( widthRatio, heightRatio ) );
  855. break;
  856. }
  857. case SCH_SHEET_T:
  858. {
  859. SCH_SHEET* sheet = (SCH_SHEET*) item;
  860. EE_GRID_HELPER gridHelper( m_toolMgr );
  861. VECTOR2I topLeft = m_editPoints->Point( RECT_TOPLEFT ).GetPosition();
  862. VECTOR2I topRight = m_editPoints->Point( RECT_TOPRIGHT ).GetPosition();
  863. VECTOR2I botLeft = m_editPoints->Point( RECT_BOTLEFT ).GetPosition();
  864. VECTOR2I botRight = m_editPoints->Point( RECT_BOTRIGHT ).GetPosition();
  865. VECTOR2I sheetNewPos = sheet->GetPosition();
  866. VECTOR2I sheetNewSize = sheet->GetSize();
  867. gridHelper.SetSnap( aSnapToGrid );
  868. int edited = getEditedPointIndex();
  869. if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  870. edited = RECT_TOPRIGHT;
  871. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  872. edited = RECT_BOTLEFT;
  873. gridHelper.SetSnap( aSnapToGrid );
  874. pinEditedCorner( sheet->GetMinWidth( edited == RECT_TOPRIGHT || edited == RECT_BOTRIGHT ),
  875. sheet->GetMinHeight( edited == RECT_BOTLEFT || edited == RECT_BOTRIGHT ),
  876. topLeft, topRight, botLeft, botRight, &gridHelper );
  877. if( isModified( m_editPoints->Point( RECT_TOPLEFT ) )
  878. || isModified( m_editPoints->Point( RECT_TOPRIGHT ) )
  879. || isModified( m_editPoints->Point( RECT_BOTRIGHT ) )
  880. || isModified( m_editPoints->Point( RECT_BOTLEFT ) ) )
  881. {
  882. sheetNewPos = topLeft;
  883. sheetNewSize = VECTOR2I( botRight.x - topLeft.x, botRight.y - topLeft.y );
  884. }
  885. else if( isModified( m_editPoints->Line( RECT_TOP ) ) )
  886. {
  887. sheetNewPos = VECTOR2I( sheet->GetPosition().x, topLeft.y );
  888. sheetNewSize = VECTOR2I( sheet->GetSize().x, botRight.y - topLeft.y );
  889. }
  890. else if( isModified( m_editPoints->Line( RECT_LEFT ) ) )
  891. {
  892. sheetNewPos = VECTOR2I( topLeft.x, sheet->GetPosition().y );
  893. sheetNewSize = VECTOR2I( botRight.x - topLeft.x, sheet->GetSize().y );
  894. }
  895. else if( isModified( m_editPoints->Line( RECT_BOT ) ) )
  896. {
  897. sheetNewSize = VECTOR2I( sheet->GetSize().x, botRight.y - topLeft.y );
  898. }
  899. else if( isModified( m_editPoints->Line( RECT_RIGHT ) ) )
  900. {
  901. sheetNewSize = VECTOR2I( botRight.x - topLeft.x, sheet->GetSize().y );
  902. }
  903. for( unsigned i = 0; i < m_editPoints->LinesSize(); ++i )
  904. {
  905. if( !isModified( m_editPoints->Line( i ) ) )
  906. {
  907. m_editPoints->Line( i ).SetConstraint(
  908. new EC_PERPLINE( m_editPoints->Line( i ) ) );
  909. }
  910. }
  911. if( sheet->GetPosition() != sheetNewPos )
  912. sheet->SetPositionIgnoringPins( sheetNewPos );
  913. if( sheet->GetSize() != sheetNewSize )
  914. sheet->Resize( sheetNewSize );
  915. break;
  916. }
  917. case SCH_LINE_T:
  918. {
  919. SCH_LINE* line = (SCH_LINE*) item;
  920. line->SetStartPoint( m_editPoints->Point( LINE_START ).GetPosition() );
  921. line->SetEndPoint( m_editPoints->Point( LINE_END ).GetPosition() );
  922. std::pair<EDA_ITEM*, int> connected = m_editPoints->Point( LINE_START ).GetConnected();
  923. if( connected.first )
  924. {
  925. if( connected.second == STARTPOINT )
  926. static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetStartPoint() );
  927. else if( connected.second == ENDPOINT )
  928. static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetStartPoint() );
  929. updateItem( connected.first, true );
  930. }
  931. connected = m_editPoints->Point( LINE_END ).GetConnected();
  932. if( connected.first )
  933. {
  934. if( connected.second == STARTPOINT )
  935. static_cast<SCH_LINE*>( connected.first )->SetStartPoint( line->GetEndPoint() );
  936. else if( connected.second == ENDPOINT )
  937. static_cast<SCH_LINE*>( connected.first )->SetEndPoint( line->GetEndPoint() );
  938. updateItem( connected.first, true );
  939. }
  940. break;
  941. }
  942. default:
  943. break;
  944. }
  945. updateItem( item, true );
  946. m_frame->SetMsgPanel( item );
  947. }
  948. void EE_POINT_EDITOR::updatePoints()
  949. {
  950. if( !m_editPoints )
  951. return;
  952. EDA_ITEM* item = m_editPoints->GetParent();
  953. if( !item )
  954. return;
  955. switch( item->Type() )
  956. {
  957. case LIB_SHAPE_T:
  958. {
  959. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( item );
  960. switch( shape->GetShape() )
  961. {
  962. case SHAPE_T::ARC:
  963. m_editPoints->Point( ARC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
  964. m_editPoints->Point( ARC_START ).SetPosition( mapCoords( shape->GetStart() ) );
  965. m_editPoints->Point( ARC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
  966. break;
  967. case SHAPE_T::CIRCLE:
  968. m_editPoints->Point( CIRC_CENTER ).SetPosition( mapCoords( shape->GetPosition() ) );
  969. m_editPoints->Point( CIRC_END ).SetPosition( mapCoords( shape->GetEnd() ) );
  970. break;
  971. case SHAPE_T::POLY:
  972. {
  973. if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
  974. {
  975. getView()->Remove( m_editPoints.get() );
  976. m_editedPoint = nullptr;
  977. m_editPoints = EDIT_POINTS_FACTORY::Make( item, m_frame );
  978. getView()->Add( m_editPoints.get() );
  979. }
  980. else
  981. {
  982. int ii = 0;
  983. for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
  984. m_editPoints->Point( ii++ ).SetPosition( mapCoords( pt ) );
  985. }
  986. break;
  987. }
  988. case SHAPE_T::RECTANGLE:
  989. {
  990. // point editor works only with rectangles having width and height > 0
  991. // Some symbols can have rectangles with width or height < 0
  992. // So normalize the size:
  993. BOX2I dummy;
  994. dummy.SetOrigin( mapCoords( shape->GetPosition() ) );
  995. dummy.SetEnd( mapCoords( shape->GetEnd() ) );
  996. dummy.Normalize();
  997. VECTOR2I topLeft = dummy.GetPosition();
  998. VECTOR2I botRight = dummy.GetEnd();
  999. m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
  1000. m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
  1001. m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
  1002. m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
  1003. break;
  1004. }
  1005. case SHAPE_T::BEZIER:
  1006. m_editPoints->Point( BEZIER_CURVE_START ).SetPosition( mapCoords( shape->GetStart() ) );
  1007. m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ).SetPosition( mapCoords( shape->GetBezierC1() ) );
  1008. m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ).SetPosition( mapCoords( shape->GetBezierC2() ) );
  1009. m_editPoints->Point( BEZIER_CURVE_END ).SetPosition( mapCoords( shape->GetEnd() ) );
  1010. break;
  1011. default:
  1012. UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
  1013. }
  1014. break;
  1015. }
  1016. case LIB_TEXTBOX_T:
  1017. {
  1018. LIB_TEXTBOX* textbox = static_cast<LIB_TEXTBOX*>( item );
  1019. // point editor works only with rectangles having width and height > 0
  1020. // Some symbols can have rectangles with width or height < 0
  1021. // So normalize the size:
  1022. BOX2I dummy;
  1023. dummy.SetOrigin( mapCoords( textbox->GetPosition() ) );
  1024. dummy.SetEnd( mapCoords( textbox->GetEnd() ) );
  1025. dummy.Normalize();
  1026. VECTOR2I topLeft = dummy.GetPosition();
  1027. VECTOR2I botRight = dummy.GetEnd();
  1028. m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
  1029. m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
  1030. m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
  1031. m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
  1032. break;
  1033. }
  1034. case SCH_SHAPE_T:
  1035. {
  1036. SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
  1037. switch( shape->GetShape() )
  1038. {
  1039. case SHAPE_T::ARC:
  1040. m_editPoints->Point( ARC_START ).SetPosition( shape->GetStart() );
  1041. m_editPoints->Point( ARC_END ).SetPosition( shape->GetEnd() );
  1042. m_editPoints->Point( ARC_CENTER ).SetPosition( shape->GetPosition() );
  1043. break;
  1044. case SHAPE_T::CIRCLE:
  1045. m_editPoints->Point( CIRC_CENTER ).SetPosition( shape->GetPosition() );
  1046. m_editPoints->Point( CIRC_END ).SetPosition( shape->GetEnd() );
  1047. break;
  1048. case SHAPE_T::POLY:
  1049. {
  1050. if( (int) m_editPoints->PointsSize() != shape->GetPointCount() )
  1051. {
  1052. getView()->Remove( m_editPoints.get() );
  1053. m_editedPoint = nullptr;
  1054. m_editPoints = EDIT_POINTS_FACTORY::Make( item, m_frame );
  1055. getView()->Add( m_editPoints.get() );
  1056. }
  1057. else
  1058. {
  1059. int ii = 0;
  1060. for( const VECTOR2I& pt : shape->GetPolyShape().Outline( 0 ).CPoints() )
  1061. m_editPoints->Point( ii++ ).SetPosition( pt );
  1062. }
  1063. break;
  1064. }
  1065. case SHAPE_T::RECTANGLE:
  1066. {
  1067. // point editor works only with rectangles having width and height > 0
  1068. // Some symbols can have rectangles with width or height < 0
  1069. // So normalize the size:
  1070. BOX2I dummy;
  1071. dummy.SetOrigin( shape->GetPosition() );
  1072. dummy.SetEnd( shape->GetEnd() );
  1073. dummy.Normalize();
  1074. VECTOR2I topLeft = dummy.GetPosition();
  1075. VECTOR2I botRight = dummy.GetEnd();
  1076. m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
  1077. m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
  1078. m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
  1079. m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
  1080. break;
  1081. }
  1082. case SHAPE_T::BEZIER:
  1083. m_editPoints->Point( BEZIER_CURVE_START ).SetPosition( shape->GetStart() );
  1084. m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT1 ).SetPosition( shape->GetBezierC1() );
  1085. m_editPoints->Point( BEZIER_CURVE_CONTROL_POINT2 ).SetPosition( shape->GetBezierC2() );
  1086. m_editPoints->Point( BEZIER_CURVE_END ).SetPosition( shape->GetEnd() );
  1087. break;
  1088. default:
  1089. UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
  1090. }
  1091. break;
  1092. }
  1093. case SCH_TEXTBOX_T:
  1094. {
  1095. SCH_TEXTBOX* textBox = static_cast<SCH_TEXTBOX*>( item );
  1096. // point editor works only with rectangles having width and height > 0
  1097. // Some symbols can have rectangles with width or height < 0
  1098. // So normalize the size:
  1099. BOX2I dummy;
  1100. dummy.SetOrigin( textBox->GetPosition() );
  1101. dummy.SetEnd( textBox->GetEnd() );
  1102. dummy.Normalize();
  1103. VECTOR2I topLeft = dummy.GetPosition();
  1104. VECTOR2I botRight = dummy.GetEnd();
  1105. m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
  1106. m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( VECTOR2I( botRight.x, topLeft.y ) );
  1107. m_editPoints->Point( RECT_BOTLEFT ).SetPosition( VECTOR2I( topLeft.x, botRight.y ) );
  1108. m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
  1109. break;
  1110. }
  1111. case SCH_BITMAP_T:
  1112. {
  1113. SCH_BITMAP* bitmap = (SCH_BITMAP*) item;
  1114. VECTOR2I topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
  1115. VECTOR2I botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
  1116. m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
  1117. m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
  1118. m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
  1119. m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
  1120. break;
  1121. }
  1122. case SCH_SHEET_T:
  1123. {
  1124. SCH_SHEET* sheet = (SCH_SHEET*) item;
  1125. VECTOR2I topLeft = sheet->GetPosition();
  1126. VECTOR2I botRight = sheet->GetPosition() + sheet->GetSize();
  1127. m_editPoints->Point( RECT_TOPLEFT ).SetPosition( topLeft );
  1128. m_editPoints->Point( RECT_TOPRIGHT ).SetPosition( botRight.x, topLeft.y );
  1129. m_editPoints->Point( RECT_BOTLEFT ).SetPosition( topLeft.x, botRight.y );
  1130. m_editPoints->Point( RECT_BOTRIGHT ).SetPosition( botRight );
  1131. break;
  1132. }
  1133. case SCH_LINE_T:
  1134. {
  1135. SCH_LINE* line = (SCH_LINE*) item;
  1136. m_editPoints->Point( LINE_START ).SetPosition( line->GetStartPoint() );
  1137. m_editPoints->Point( LINE_END ).SetPosition( line->GetEndPoint() );
  1138. break;
  1139. }
  1140. default:
  1141. break;
  1142. }
  1143. getView()->Update( m_editPoints.get() );
  1144. }
  1145. void EE_POINT_EDITOR::setEditedPoint( EDIT_POINT* aPoint )
  1146. {
  1147. KIGFX::VIEW_CONTROLS* controls = getViewControls();
  1148. if( aPoint )
  1149. {
  1150. m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
  1151. controls->ForceCursorPosition( true, aPoint->GetPosition() );
  1152. controls->ShowCursor( true );
  1153. }
  1154. else
  1155. {
  1156. if( m_frame->ToolStackIsEmpty() )
  1157. controls->ShowCursor( false );
  1158. controls->ForceCursorPosition( false );
  1159. }
  1160. m_editedPoint = aPoint;
  1161. }
  1162. bool EE_POINT_EDITOR::removeCornerCondition( const SELECTION& )
  1163. {
  1164. if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
  1165. return false;
  1166. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
  1167. if( shape->GetPolyShape().IsEmpty() )
  1168. return false;
  1169. SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
  1170. if( poly.GetPointCount() < 3 )
  1171. return false;
  1172. for( const VECTOR2I& pt : poly.CPoints() )
  1173. {
  1174. if( pt == mapCoords( m_editedPoint->GetPosition() ) )
  1175. return true;
  1176. }
  1177. return false;
  1178. }
  1179. bool EE_POINT_EDITOR::addCornerCondition( const SELECTION& )
  1180. {
  1181. if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
  1182. return false;
  1183. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
  1184. if( shape->GetShape() != SHAPE_T::POLY )
  1185. return false;
  1186. VECTOR2I cursorPos = getViewControls()->GetCursorPosition( false );
  1187. double threshold = getView()->ToWorld( EDIT_POINT::POINT_SIZE );
  1188. return shape->HitTest( cursorPos, (int) threshold );
  1189. }
  1190. int EE_POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
  1191. {
  1192. if( !m_editPoints || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
  1193. return 0;
  1194. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
  1195. SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
  1196. SCH_COMMIT commit( m_toolMgr );
  1197. commit.Modify( shape, m_frame->GetScreen() );
  1198. VECTOR2I cursor = getViewControls()->GetCursorPosition( !aEvent.DisableGridSnapping() );
  1199. VECTOR2I pos = mapCoords( cursor );
  1200. int currentMinDistance = INT_MAX;
  1201. int closestLineStart = 0;
  1202. for( unsigned i = 0; i < poly.GetPointCount() - 1; ++i )
  1203. {
  1204. int distance = (int) DistanceLinePoint( poly.CPoint( i ),
  1205. poly.CPoint( i + 1 ), pos );
  1206. if( distance < currentMinDistance )
  1207. {
  1208. currentMinDistance = distance;
  1209. closestLineStart = i;
  1210. }
  1211. }
  1212. poly.Insert( closestLineStart + 1, pos );
  1213. updateItem( shape, true );
  1214. updatePoints();
  1215. commit.Push( _( "Add Corner" ) );
  1216. return 0;
  1217. }
  1218. int EE_POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
  1219. {
  1220. if( !m_editPoints || !m_editedPoint || m_editPoints->GetParent()->Type() != LIB_SHAPE_T )
  1221. return 0;
  1222. LIB_SHAPE* shape = static_cast<LIB_SHAPE*>( m_editPoints->GetParent() );
  1223. SHAPE_LINE_CHAIN& poly = shape->GetPolyShape().Outline( 0 );
  1224. SCH_COMMIT commit( m_toolMgr );
  1225. commit.Modify( shape, m_frame->GetScreen() );
  1226. if( poly.GetPointCount() < 3 )
  1227. return 0;
  1228. poly.Remove( getEditedPointIndex() );
  1229. updateItem( shape, true );
  1230. updatePoints();
  1231. commit.Push( _( "Remove Corner" ) );
  1232. return 0;
  1233. }
  1234. int EE_POINT_EDITOR::modifiedSelection( const TOOL_EVENT& aEvent )
  1235. {
  1236. updatePoints();
  1237. return 0;
  1238. }
  1239. void EE_POINT_EDITOR::setTransitions()
  1240. {
  1241. Go( &EE_POINT_EDITOR::Main, EVENTS::PointSelectedEvent );
  1242. Go( &EE_POINT_EDITOR::Main, EVENTS::SelectedEvent );
  1243. Go( &EE_POINT_EDITOR::Main, ACTIONS::activatePointEditor.MakeEvent() );
  1244. Go( &EE_POINT_EDITOR::addCorner, EE_ACTIONS::pointEditorAddCorner.MakeEvent() );
  1245. Go( &EE_POINT_EDITOR::removeCorner, EE_ACTIONS::pointEditorRemoveCorner.MakeEvent() );
  1246. Go( &EE_POINT_EDITOR::modifiedSelection, EVENTS::SelectedItemsModified );
  1247. Go( &EE_POINT_EDITOR::clearEditedPoints, EVENTS::ClearedEvent );
  1248. }