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.

373 lines
13 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014-2017 CERN
  5. * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Maciej Suminski <maciej.suminski@cern.ch>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #ifndef __DRAWING_TOOL_H
  27. #define __DRAWING_TOOL_H
  28. #include <stack>
  29. #include <optional>
  30. #include <tool/tool_menu.h>
  31. #include <tools/pcb_tool_base.h>
  32. #include <tools/pcb_actions.h>
  33. namespace KIGFX
  34. {
  35. class VIEW;
  36. class VIEW_CONTROLS;
  37. }
  38. class BOARD;
  39. class PCB_BASE_EDIT_FRAME;
  40. class PCB_SHAPE;
  41. class POLYGON_GEOM_MANAGER;
  42. class PCB_TUNING_PATTERN;
  43. class STATUS_MIN_MAX_POPUP;
  44. /**
  45. * Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
  46. */
  47. class DRAWING_TOOL : public PCB_TOOL_BASE
  48. {
  49. public:
  50. DRAWING_TOOL();
  51. ~DRAWING_TOOL();
  52. /// @copydoc TOOL_INTERACTIVE::Init()
  53. bool Init() override;
  54. /// @copydoc TOOL_INTERACTIVE::Reset()
  55. void Reset( RESET_REASON aReason ) override;
  56. ///< The possible drawing modes of DRAWING_TOOL
  57. enum class MODE
  58. {
  59. NONE,
  60. LINE,
  61. RECTANGLE,
  62. CIRCLE,
  63. ARC,
  64. IMAGE,
  65. TEXT,
  66. ANCHOR,
  67. DXF,
  68. DIMENSION,
  69. KEEPOUT,
  70. ZONE,
  71. GRAPHIC_POLYGON,
  72. VIA,
  73. TUNING
  74. };
  75. /**
  76. * Return the current drawing mode of the DRAWING_TOOL or #MODE::NONE if not currently in
  77. * any drawing mode.
  78. */
  79. MODE GetDrawingMode() const;
  80. /**
  81. */
  82. std::vector<BOARD_ITEM*> DrawBoardCharacteristics( const VECTOR2I& origin, PCB_LAYER_ID aLayer,
  83. bool aDrawNow, VECTOR2I* tablesize );
  84. /**
  85. */
  86. std::vector<BOARD_ITEM*> DrawSpecificationStackup( const VECTOR2I& origin, PCB_LAYER_ID aLayer,
  87. bool aDrawNow, VECTOR2I* tablesize );
  88. /**
  89. */
  90. int PlaceCharacteristics( const TOOL_EVENT& aEvent );
  91. /**
  92. */
  93. int PlaceStackup( const TOOL_EVENT& aEvent );
  94. /**
  95. */
  96. int PlaceTuningPattern( const TOOL_EVENT& aEvent );
  97. /**
  98. * Start interactively drawing a line.
  99. *
  100. * After invoking the function it expects the user to click at least two times to determine
  101. * the origin and the end for a line. If there are more clicks, the line is drawn as a
  102. * continuous polyline.
  103. */
  104. int DrawLine( const TOOL_EVENT& aEvent );
  105. /**
  106. * Start interactively drawing a rectangle.
  107. *
  108. * After invoking the function it expects the user to first click on a point that is going
  109. * to be used as the top-left of the rectangle. The second click determines the bottom-right.
  110. */
  111. int DrawRectangle( const TOOL_EVENT& aEvent );
  112. /**
  113. * Start interactively drawing a circle.
  114. *
  115. * After invoking the function it expects the user to first click on a point that is going
  116. * to be used as the center of the circle. The second click determines the circle radius.
  117. */
  118. int DrawCircle( const TOOL_EVENT& aEvent );
  119. /**
  120. * Start interactively drawing an arc.
  121. *
  122. * After invoking the function it expects the user to first click on a point that is going
  123. * to be used as the center of the arc. The second click determines the origin and radius,
  124. * the third one - the angle.
  125. */
  126. int DrawArc( const TOOL_EVENT& aEvent );
  127. /**
  128. * Display a dialog that allows one to select a reference image and then decide where to
  129. * place the image in the editor.
  130. */
  131. int PlaceReferenceImage( const TOOL_EVENT& aEvent );
  132. /**
  133. * Display a dialog that allows one to input text and its settings and then lets the user
  134. * decide where to place the text in editor.
  135. */
  136. int PlaceText( const TOOL_EVENT& aEvent );
  137. /*
  138. * Start interactively drawing a table (rows & columns of TEXTBOXes).
  139. */
  140. int DrawTable( const TOOL_EVENT& aEvent );
  141. /**
  142. * Start interactively drawing a dimension.
  143. *
  144. * After invoking the function it expects the user to first click on a point that is going
  145. * to be used as the origin of the dimension. The second click determines the end and the
  146. * third click modifies its height.
  147. */
  148. int DrawDimension( const TOOL_EVENT& aEvent );
  149. /**
  150. * Start interactively drawing a zone.
  151. *
  152. * After invoking the function a zone settings dialog is displayed. After confirmation it
  153. * allows the user to set points that are going to be used as a boundary polygon of the
  154. * zone. Double click or clicking on the origin of the boundary polyline finishes the
  155. * drawing.
  156. *
  157. * The event parameter indicates which type of zone to draw:
  158. * - ADD add a new zone/keepout with fresh settings.
  159. * - CUTOUT add a cutout to an existing zone.
  160. * - SIMILAR add a new zone with the same settings as an existing one.
  161. */
  162. int DrawZone( const TOOL_EVENT& aEvent );
  163. int DrawVia( const TOOL_EVENT& aEvent );
  164. /**
  165. * Place a drawing imported from a DXF or SVG file in footprint editor.
  166. */
  167. int PlaceImportedGraphics( const TOOL_EVENT& aEvent );
  168. /**
  169. * Interactively place a set of @ref BOARD_ITEM.
  170. * As a list of BOARD_ITEMs can be resource intesive to move around,
  171. * we can use a reduced set of BOARD_ITEMs for preview purpose only.
  172. *
  173. * @param aEvent
  174. * @param aItems BOARD_ITEMs to add to the board.
  175. * @param aPreview BOARD_ITEMs only used during placement / preview.
  176. * @param aLayers Set of allowed destination when asking the user.
  177. * If set to NULL, the user is not asked and all BOARD_ITEMs remain on
  178. * their layers.
  179. */
  180. int InteractivePlaceWithPreview( const TOOL_EVENT& aEvent,
  181. std::vector<BOARD_ITEM*>& aItems,
  182. std::vector<BOARD_ITEM*>& aPreview, LSET* aLayers );
  183. /**
  184. * Place the footprint anchor (only in footprint editor).
  185. */
  186. int SetAnchor( const TOOL_EVENT& aEvent );
  187. /**
  188. * Toggle the horizontal/vertical/45-degree constraint for drawing tools.
  189. */
  190. int ToggleHV45Mode( const TOOL_EVENT& toolEvent );
  191. ///< Set up handlers for various events.
  192. void setTransitions() override;
  193. void SetStroke( const STROKE_PARAMS& aStroke, PCB_LAYER_ID aLayer )
  194. {
  195. m_layer = aLayer;
  196. m_stroke = aStroke;
  197. }
  198. void UpdateStatusBar() const;
  199. private:
  200. /**
  201. * Start drawing a selected shape (i.e. PCB_SHAPE).
  202. *
  203. * @param aGraphic is an object that is going to be used by the tool for drawing. Must be
  204. * already created. The tool deletes the object if it is not added to a BOARD.
  205. * @param aStartingPoint is a starting point for this new PCB_SHAPE. If it exists the new
  206. * item has its start point set to aStartingPoint, and its settings
  207. * (width, layer) set to the current default values.
  208. * @return False if the tool was canceled before the origin was set or origin and end are
  209. * the same point.
  210. */
  211. bool drawShape( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
  212. std::optional<VECTOR2D> aStartingPoint,
  213. std::stack<PCB_SHAPE*>* aCommittedGraphics );
  214. /**
  215. * Start drawing an arc.
  216. *
  217. * @param aGraphic is an object that is going to be used by the tool for drawing. Must be
  218. * already created. The tool deletes the object if it is not added to a BOARD.
  219. * @return False if the tool was canceled before the origin was set or origin and end are
  220. * the same point.
  221. */
  222. bool drawArc( const TOOL_EVENT& aTool, PCB_SHAPE** aGraphic,
  223. std::optional<VECTOR2D> aStartingPoint );
  224. /**
  225. * Draw a polygon, that is added as a zone or a keepout area.
  226. *
  227. * @param aKeepout dictates if the drawn polygon is a zone or a keepout area.
  228. * @param aMode dictates the mode of the zone tool:
  229. * - ADD add a new zone/keepout with fresh settings
  230. * - CUTOUT add a cutout to an existing zone
  231. * - SIMILAR add a new zone with the same settings as an existing one
  232. */
  233. /**
  234. * Get a source zone item for an action that takes an existing zone into account (for
  235. * example a cutout of an existing zone).
  236. *
  237. * The source zone is taken from the current selection.
  238. *
  239. * @param aMode mode of the zone tool
  240. * @param aZone updated pointer to a suitable source zone, or nullptr if none found, or
  241. * the action doesn't need a source
  242. * @return true if a suitable zone was found, or the action doesn't need a zone. False if
  243. * the action needs a zone but none was found.
  244. */
  245. bool getSourceZoneForAction( ZONE_MODE aMode, ZONE** aZone );
  246. /**
  247. * Force the dimension lime to be drawn on multiple of 45 degrees.
  248. *
  249. * @param aDimension is the dimension element currently being drawn.
  250. */
  251. void constrainDimension( PCB_DIMENSION_BASE* aDim );
  252. /**
  253. * Clamps the end vector to respect numeric limits of difference representation
  254. *
  255. * @param aOrigin - the origin vector.
  256. * @param aEnd - the end vector.
  257. * @return clamped end vector.
  258. */
  259. VECTOR2I getClampedDifferenceEnd( const VECTOR2I& aOrigin, const VECTOR2I& aEnd )
  260. {
  261. typedef std::numeric_limits<int> coord_limits;
  262. const int guardValue = 1;
  263. VECTOR2I::extended_type maxDiff = coord_limits::max() - guardValue;
  264. VECTOR2I::extended_type xDiff = VECTOR2I::extended_type( aEnd.x ) - aOrigin.x;
  265. VECTOR2I::extended_type yDiff = VECTOR2I::extended_type( aEnd.y ) - aOrigin.y;
  266. if( xDiff > maxDiff )
  267. xDiff = maxDiff;
  268. if( yDiff > maxDiff )
  269. yDiff = maxDiff;
  270. if( xDiff < -maxDiff )
  271. xDiff = -maxDiff;
  272. if( yDiff < -maxDiff )
  273. yDiff = -maxDiff;
  274. return aOrigin + VECTOR2I( int( xDiff ), int( yDiff ) );
  275. }
  276. /**
  277. * Clamps the end vector to respect numeric limits of radius representation
  278. *
  279. * @param aOrigin - the origin vector.
  280. * @param aEnd - the end vector.
  281. * @return clamped end vector.
  282. */
  283. VECTOR2I getClampedRadiusEnd( const VECTOR2I& aOrigin, const VECTOR2I& aEnd )
  284. {
  285. typedef std::numeric_limits<int> coord_limits;
  286. const int guardValue = 10;
  287. VECTOR2I::extended_type xDiff = VECTOR2I::extended_type( aEnd.x ) - aOrigin.x;
  288. VECTOR2I::extended_type yDiff = VECTOR2I::extended_type( aEnd.y ) - aOrigin.y;
  289. double maxRadius = coord_limits::max() / 2 - guardValue;
  290. double radius = std::hypot( xDiff, yDiff );
  291. if( radius > maxRadius )
  292. {
  293. double scaleFactor = maxRadius / radius;
  294. xDiff = KiROUND<double, int>( xDiff * scaleFactor );
  295. yDiff = KiROUND<double, int>( yDiff * scaleFactor );
  296. }
  297. return aOrigin + VECTOR2I( int( xDiff ), int( yDiff ) );
  298. }
  299. KIGFX::VIEW* m_view;
  300. KIGFX::VIEW_CONTROLS* m_controls;
  301. BOARD* m_board;
  302. PCB_BASE_EDIT_FRAME* m_frame;
  303. MODE m_mode;
  304. bool m_inDrawingTool; // Re-entrancy guard
  305. PCB_LAYER_ID m_layer; // The layer we last drew on
  306. STROKE_PARAMS m_stroke; // Current stroke for multi-segment drawing
  307. TEXT_ATTRIBUTES m_textAttrs;
  308. PCB_SELECTION m_preview;
  309. BOARD_CONNECTED_ITEM* m_pickerItem;
  310. PCB_TUNING_PATTERN* m_tuningPattern;
  311. static const unsigned int WIDTH_STEP; // Amount of width change for one -/+ key press
  312. static const unsigned int COORDS_PADDING; // Padding from coordinates limits for this tool
  313. friend class ZONE_CREATE_HELPER; // give internal access to helper classes
  314. };
  315. #endif /* __DRAWING_TOOL_H */