FlatCAMTool.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. # ########################################################## ##
  2. # FlatCAM: 2D Post-processing for Manufacturing #
  3. # http://flatcam.org #
  4. # Author: Juan Pablo Caram (c) #
  5. # Date: 2/5/2014 #
  6. # MIT Licence #
  7. # ########################################################## ##
  8. from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets
  9. from PyQt5.QtCore import Qt
  10. from shapely.geometry import Polygon, LineString
  11. import gettext
  12. import FlatCAMTranslation as fcTranslate
  13. import builtins
  14. fcTranslate.apply_language('strings')
  15. if '_' not in builtins.__dict__:
  16. _ = gettext.gettext
  17. class FlatCAMTool(QtWidgets.QWidget):
  18. toolName = "FlatCAM Generic Tool"
  19. def __init__(self, app, parent=None):
  20. """
  21. :param app: The application this tool will run in.
  22. :type app: App
  23. :param parent: Qt Parent
  24. :return: FlatCAMTool
  25. """
  26. self.app = app
  27. self.decimals = app.decimals
  28. QtWidgets.QWidget.__init__(self, parent)
  29. # self.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
  30. self.layout = QtWidgets.QVBoxLayout()
  31. self.setLayout(self.layout)
  32. self.menuAction = None
  33. def install(self, icon=None, separator=None, shortcut=None, **kwargs):
  34. before = None
  35. # 'pos' is the menu where the Action has to be installed
  36. # if no 'pos' kwarg is provided then by default our Action will be installed in the menutool
  37. # as it previously was
  38. if 'pos' in kwargs:
  39. pos = kwargs['pos']
  40. else:
  41. pos = self.app.ui.menutool
  42. # 'before' is the Action in the menu stated by 'pos' kwarg, before which we want our Action to be installed
  43. # if 'before' kwarg is not provided, by default our Action will be added in the last place.
  44. if 'before' in kwargs:
  45. before = (kwargs['before'])
  46. # create the new Action
  47. self.menuAction = QtWidgets.QAction(self)
  48. # if provided, add an icon to this Action
  49. if icon is not None:
  50. self.menuAction.setIcon(icon)
  51. # set the text name of the Action, which will be displayed in the menu
  52. if shortcut is None:
  53. self.menuAction.setText(self.toolName)
  54. else:
  55. self.menuAction.setText(self.toolName + '\t%s' % shortcut)
  56. # add a ToolTip to the new Action
  57. # self.menuAction.setToolTip(self.toolTip) # currently not available
  58. # insert the action in the position specified by 'before' and 'pos' kwargs
  59. pos.insertAction(before, self.menuAction)
  60. # if separator parameter is True add a Separator after the newly created Action
  61. if separator is True:
  62. pos.addSeparator()
  63. self.menuAction.triggered.connect(self.run)
  64. def run(self):
  65. if self.app.tool_tab_locked is True:
  66. return
  67. # Remove anything else in the GUI
  68. self.app.ui.tool_scroll_area.takeWidget()
  69. # Put ourself in the GUI
  70. self.app.ui.tool_scroll_area.setWidget(self)
  71. # Switch notebook to tool page
  72. self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
  73. # Set the tool name as the widget object name
  74. self.app.ui.tool_scroll_area.widget().setObjectName(self.toolName)
  75. self.show()
  76. def draw_tool_selection_shape(self, old_coords, coords, **kwargs):
  77. """
  78. :param old_coords: old coordinates
  79. :param coords: new coordinates
  80. :param kwargs:
  81. :return:
  82. """
  83. if 'shapes_storage' in kwargs:
  84. s_storage = kwargs['shapes_storage']
  85. else:
  86. s_storage = self.app.tool_shapes
  87. if 'color' in kwargs:
  88. color = kwargs['color']
  89. else:
  90. color = self.app.defaults['global_sel_line']
  91. if 'face_color' in kwargs:
  92. face_color = kwargs['face_color']
  93. else:
  94. face_color = self.app.defaults['global_sel_fill']
  95. if 'face_alpha' in kwargs:
  96. face_alpha = kwargs['face_alpha']
  97. else:
  98. face_alpha = 0.3
  99. x0, y0 = old_coords
  100. x1, y1 = coords
  101. pt1 = (x0, y0)
  102. pt2 = (x1, y0)
  103. pt3 = (x1, y1)
  104. pt4 = (x0, y1)
  105. sel_rect = Polygon([pt1, pt2, pt3, pt4])
  106. # color_t = Color(face_color)
  107. # color_t.alpha = face_alpha
  108. color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
  109. s_storage.add(sel_rect, color=color, face_color=color_t, update=True, layer=0, tolerance=None)
  110. if self.app.is_legacy is True:
  111. s_storage.redraw()
  112. def draw_selection_shape_polygon(self, points, **kwargs):
  113. """
  114. :param points: a list of points from which to create a Polygon
  115. :param kwargs:
  116. :return:
  117. """
  118. if 'shapes_storage' in kwargs:
  119. s_storage = kwargs['shapes_storage']
  120. else:
  121. s_storage = self.app.tool_shapes
  122. if 'color' in kwargs:
  123. color = kwargs['color']
  124. else:
  125. color = self.app.defaults['global_sel_line']
  126. if 'face_color' in kwargs:
  127. face_color = kwargs['face_color']
  128. else:
  129. face_color = self.app.defaults['global_sel_fill']
  130. if 'face_alpha' in kwargs:
  131. face_alpha = kwargs['face_alpha']
  132. else:
  133. face_alpha = 0.3
  134. if len(points) < 3:
  135. sel_rect = LineString(points)
  136. else:
  137. sel_rect = Polygon(points)
  138. # color_t = Color(face_color)
  139. # color_t.alpha = face_alpha
  140. color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
  141. s_storage.add(sel_rect, color=color, face_color=color_t, update=True, layer=0, tolerance=None)
  142. if self.app.is_legacy is True:
  143. s_storage.redraw()
  144. def delete_tool_selection_shape(self, **kwargs):
  145. """
  146. :param kwargs:
  147. :return:
  148. """
  149. if 'shapes_storage' in kwargs:
  150. s_storage = kwargs['shapes_storage']
  151. else:
  152. s_storage = self.app.tool_shapes
  153. s_storage.clear()
  154. s_storage.redraw()
  155. def draw_moving_selection_shape_poly(self, points, data, **kwargs):
  156. """
  157. :param points:
  158. :param data:
  159. :param kwargs:
  160. :return:
  161. """
  162. if 'shapes_storage' in kwargs:
  163. s_storage = kwargs['shapes_storage']
  164. else:
  165. s_storage = self.app.move_tool.sel_shapes
  166. if 'color' in kwargs:
  167. color = kwargs['color']
  168. else:
  169. color = self.app.defaults['global_sel_line']
  170. if 'face_color' in kwargs:
  171. face_color = kwargs['face_color']
  172. else:
  173. face_color = self.app.defaults['global_sel_fill']
  174. if 'face_alpha' in kwargs:
  175. face_alpha = kwargs['face_alpha']
  176. else:
  177. face_alpha = 0.3
  178. temp_points = [x for x in points]
  179. try:
  180. if data != temp_points[-1]:
  181. temp_points.append(data)
  182. except IndexError:
  183. return
  184. l_points = len(temp_points)
  185. if l_points == 2:
  186. geo = LineString(temp_points)
  187. elif l_points > 2:
  188. geo = Polygon(temp_points)
  189. else:
  190. return
  191. color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
  192. color_t_error = "#00000000"
  193. if geo.is_valid and not geo.is_empty:
  194. s_storage.add(geo, color=color, face_color=color_t, update=True, layer=0, tolerance=None)
  195. elif not geo.is_valid:
  196. s_storage.add(geo, color="red", face_color=color_t_error, update=True, layer=0, tolerance=None)
  197. if self.app.is_legacy is True:
  198. s_storage.redraw()
  199. def delete_moving_selection_shape(self, **kwargs):
  200. """
  201. :param kwargs:
  202. :return:
  203. """
  204. if 'shapes_storage' in kwargs:
  205. s_storage = kwargs['shapes_storage']
  206. else:
  207. s_storage = self.app.move_tool.sel_shapes
  208. s_storage.clear()
  209. s_storage.redraw()
  210. def confirmation_message(self, accepted, minval, maxval):
  211. if accepted is False:
  212. self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
  213. (_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
  214. else:
  215. self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
  216. def confirmation_message_int(self, accepted, minval, maxval):
  217. if accepted is False:
  218. self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
  219. (_("Edited value is out of range"), minval, maxval))
  220. else:
  221. self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
  222. def sizeHint(self):
  223. """
  224. I've overloaded this just in case I will need to make changes in the future to enforce dimensions
  225. :return:
  226. """
  227. default_hint_size = super(FlatCAMTool, self).sizeHint()
  228. return QtCore.QSize(default_hint_size.width(), default_hint_size.height())