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.

326 lines
10 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #pragma once
  24. #include <wx/debug.h>
  25. #include <eda_shape.h>
  26. #include <tool/edit_points.h>
  27. class SHAPE_POLY_SET;
  28. /**
  29. * A helper class interface to manage the edit points for a single item.
  30. * Create one ofthese, and it will provide a way to keep a list of points
  31. * updated.
  32. *
  33. * For the moment this is implemented such that it mutates an external
  34. * #EDIT_POINTS object, but it might be able to also own the points.
  35. */
  36. class POINT_EDIT_BEHAVIOR
  37. {
  38. public:
  39. virtual ~POINT_EDIT_BEHAVIOR() = default;
  40. /**
  41. * Construct the initial set of edit points for the item
  42. * and append to the given list.
  43. *
  44. * @param aPoints The list of edit points to fill.
  45. */
  46. virtual void MakePoints( EDIT_POINTS& aPoints ) = 0;
  47. /**
  48. * Update the list of the edit points for the item.
  49. *
  50. * Be very careful not to overrun the list of points -
  51. * this class knows how bug there are because it made them
  52. * in the first place.
  53. *
  54. * If item has changed such that that number of points needs to
  55. * change, this method has to handle that (probably by clearing
  56. * the list and refilling it).
  57. *
  58. * @param aPoints The list of edit points to update.
  59. */
  60. virtual void UpdatePoints( EDIT_POINTS& aPoints ) = 0;
  61. /**
  62. * Update the item with the new positions of the edit points.
  63. *
  64. * This method should all commit and add to the update list anything that
  65. * is NOT the parent item of the EDIT_POINTs. For example, connected lines,
  66. * parent tables, etc. The item itself is already handled (most behaviors
  67. * don't need more than that).
  68. *
  69. * @param aEditedPoint The point that was dragged.
  70. * You can use this to check by address which point to update.
  71. * @param aPoints The new positions of the edit points.
  72. * @param aCommit The commit object to use to modify the item.
  73. * @param aUpdatedItems The list of items that were updated by the edit (not only the
  74. * item that was being edited, but also any other items that were
  75. * affected, e.g. by being conneted to the edited item).
  76. */
  77. virtual void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
  78. std::vector<EDA_ITEM*>& aUpdatedItems ) = 0;
  79. /**
  80. * Get the 45-degree constrainer for the item, when the given point is moved.
  81. * Return std::nullopt if not, and the caller can decide.
  82. *
  83. * If you want to actively disable constraining, return the aEditedPoint
  84. * position.
  85. */
  86. virtual OPT_VECTOR2I Get45DegreeConstrainer( const EDIT_POINT& aEditedPoint,
  87. EDIT_POINTS& aPoints ) const
  88. {
  89. // By default, no constrainer is defined and the caller must decide
  90. return std::nullopt;
  91. }
  92. protected:
  93. /**
  94. * Checks if two points are the same instance - which means the point is being edited.
  95. */
  96. static bool isModified( const EDIT_POINT& aEditedPoint, const EDIT_POINT& aPoint )
  97. {
  98. return &aEditedPoint == &aPoint;
  99. }
  100. };
  101. // Helper macros to check the number of points in the edit points object
  102. // Still a bug, but at least it won't segfault if the number of points is wrong
  103. #define CHECK_POINT_COUNT( aPoints, aExpected ) \
  104. wxCHECK( aPoints.PointsSize() == aExpected, /* void */ )
  105. #define CHECK_POINT_COUNT_GE( aPoints, aExpected ) \
  106. wxCHECK( aPoints.PointsSize() >= aExpected, /* void */ )
  107. /**
  108. * Class that implements "standard" polygon editing behavior.
  109. *
  110. * You still need to implement the POINT_EDIT_BEHAVIOR interface (in particular,
  111. * you may need to construct a poly set from or apply the poly set to an actual
  112. * object) but you can use the helper methods in this class to do the actual work.
  113. */
  114. class POLYGON_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
  115. {
  116. public:
  117. POLYGON_POINT_EDIT_BEHAVIOR( SHAPE_POLY_SET& aPolygon ) : m_polygon( aPolygon ) {}
  118. /**
  119. * Build the edit points for the given polygon outline.
  120. */
  121. static void BuildForPolyOutline( EDIT_POINTS& aPoints, const SHAPE_POLY_SET& aOutline );
  122. /**
  123. * Update the edit points with the current polygon outline.
  124. *
  125. * If the point sizes differ, the points are rebuilt entirely (in-place)
  126. */
  127. static void UpdatePointsFromOutline( const SHAPE_POLY_SET& aOutline, EDIT_POINTS& aPoints );
  128. /**
  129. * Update the polygon outline with the new positions of the edit points.
  130. */
  131. static void UpdateOutlineFromPoints( SHAPE_POLY_SET& aOutline, const EDIT_POINT& aEditedPoint,
  132. EDIT_POINTS& aPoints );
  133. void MakePoints( EDIT_POINTS& aPoints ) override
  134. {
  135. BuildForPolyOutline( aPoints, m_polygon );
  136. }
  137. void UpdatePoints( EDIT_POINTS& aPoints ) override
  138. {
  139. UpdatePointsFromOutline( m_polygon, aPoints );
  140. }
  141. void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
  142. std::vector<EDA_ITEM*>& aUpdatedItems ) override
  143. {
  144. UpdateOutlineFromPoints( m_polygon, aEditedPoint, aPoints );
  145. }
  146. private:
  147. SHAPE_POLY_SET& m_polygon;
  148. };
  149. /**
  150. * "Standard" polygon editing behavior for EDA_SHAPE polygons.
  151. *
  152. * As long as updating the EDA_SHAPE's SHAPE_POLY_SET in-place is enough,
  153. * this will do the job.
  154. */
  155. class EDA_POLYGON_POINT_EDIT_BEHAVIOR : public POLYGON_POINT_EDIT_BEHAVIOR
  156. {
  157. public:
  158. // Editing the underlying polygon shape in-place is enough
  159. EDA_POLYGON_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aPolygon ) :
  160. POLYGON_POINT_EDIT_BEHAVIOR( aPolygon.GetPolyShape() )
  161. {
  162. wxASSERT( aPolygon.GetShape() == SHAPE_T::POLY );
  163. }
  164. };
  165. /**
  166. * "Standard" segment editing behavior for EDA_SHAPE segments.
  167. */
  168. class EDA_SEGMENT_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
  169. {
  170. public:
  171. EDA_SEGMENT_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aSegment ) : m_segment( aSegment )
  172. {
  173. wxASSERT( aSegment.GetShape() == SHAPE_T::SEGMENT );
  174. }
  175. void MakePoints( EDIT_POINTS& aPoints ) override;
  176. void UpdatePoints( EDIT_POINTS& aPoints ) override;
  177. void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
  178. std::vector<EDA_ITEM*>& aUpdatedItems ) override;
  179. OPT_VECTOR2I Get45DegreeConstrainer( const EDIT_POINT& aEditedPoint,
  180. EDIT_POINTS& aPoints ) const override;
  181. protected:
  182. enum SEGMENT_POINTS
  183. {
  184. SEGMENT_START,
  185. SEGMENT_END,
  186. SEGMENT_MAX_POINTS,
  187. };
  188. private:
  189. EDA_SHAPE& m_segment;
  190. };
  191. /**
  192. * "Standard" circle editing behavior for EDA_SHAPE circles.
  193. */
  194. class EDA_CIRCLE_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
  195. {
  196. public:
  197. EDA_CIRCLE_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aCircle ) : m_circle( aCircle )
  198. {
  199. wxASSERT( aCircle.GetShape() == SHAPE_T::CIRCLE );
  200. }
  201. void MakePoints( EDIT_POINTS& aPoints ) override;
  202. void UpdatePoints( EDIT_POINTS& aPoints ) override;
  203. void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
  204. std::vector<EDA_ITEM*>& aUpdatedItems ) override;
  205. OPT_VECTOR2I Get45DegreeConstrainer( const EDIT_POINT& aEditedPoint,
  206. EDIT_POINTS& aPoints ) const override;
  207. protected:
  208. enum CIRCLE_POINTS
  209. {
  210. CIRC_CENTER,
  211. CIRC_END,
  212. CIRC_MAX_POINTS,
  213. };
  214. private:
  215. EDA_SHAPE& m_circle;
  216. };
  217. /**
  218. * "Standard" bezier editing behavior for EDA_SHAPE beziers.
  219. */
  220. class EDA_BEZIER_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
  221. {
  222. public:
  223. EDA_BEZIER_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aBezier ) : m_bezier( aBezier )
  224. {
  225. wxASSERT( aBezier.GetShape() == SHAPE_T::BEZIER );
  226. }
  227. void MakePoints( EDIT_POINTS& aPoints ) override;
  228. void UpdatePoints( EDIT_POINTS& aPoints ) override;
  229. void UpdateItem( const EDIT_POINT& aEditedPoint, EDIT_POINTS& aPoints, COMMIT& aCommit,
  230. std::vector<EDA_ITEM*>& aUpdatedItems ) override;
  231. protected:
  232. enum BEZIER_POINTS
  233. {
  234. BEZIER_START,
  235. BEZIER_CTRL_PT1,
  236. BEZIER_CTRL_PT2,
  237. BEZIER_END,
  238. BEZIER_MAX_POINTS
  239. };
  240. private:
  241. EDA_SHAPE& m_bezier;
  242. };
  243. /**
  244. * "Standard" table-cell editing behavior.
  245. *
  246. * This works over the #EDA_SHAPE basis of a SCH/PCB_TABLECELL.
  247. * The cells and tables themselves aren't (yet) polymorphic, so the implmentation
  248. * has to provide UpdateItem() to handle the actual update.
  249. */
  250. class EDA_TABLECELL_POINT_EDIT_BEHAVIOR : public POINT_EDIT_BEHAVIOR
  251. {
  252. public:
  253. EDA_TABLECELL_POINT_EDIT_BEHAVIOR( EDA_SHAPE& aCell ) : m_cell( aCell )
  254. {
  255. // While PCB_TEXTBOXES are not always RECTANGLEs, they are when they
  256. // are TABLECELLs.
  257. wxASSERT( aCell.GetShape() == SHAPE_T::RECTANGLE );
  258. }
  259. void MakePoints( EDIT_POINTS& aPoints ) override;
  260. void UpdatePoints( EDIT_POINTS& aPoints ) override;
  261. protected:
  262. enum TABLECELL_POINTS
  263. {
  264. COL_WIDTH,
  265. ROW_HEIGHT,
  266. TABLECELL_MAX_POINTS,
  267. };
  268. private:
  269. EDA_SHAPE& m_cell;
  270. };