FlatCAMTool.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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 'color' in kwargs:
  84. color = kwargs['color']
  85. else:
  86. color = self.app.defaults['global_sel_line']
  87. if 'face_color' in kwargs:
  88. face_color = kwargs['face_color']
  89. else:
  90. face_color = self.app.defaults['global_sel_fill']
  91. if 'face_alpha' in kwargs:
  92. face_alpha = kwargs['face_alpha']
  93. else:
  94. face_alpha = 0.3
  95. x0, y0 = old_coords
  96. x1, y1 = coords
  97. pt1 = (x0, y0)
  98. pt2 = (x1, y0)
  99. pt3 = (x1, y1)
  100. pt4 = (x0, y1)
  101. sel_rect = Polygon([pt1, pt2, pt3, pt4])
  102. # color_t = Color(face_color)
  103. # color_t.alpha = face_alpha
  104. color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
  105. self.app.tool_shapes.add(sel_rect, color=color, face_color=color_t, update=True,
  106. layer=0, tolerance=None)
  107. if self.app.is_legacy is True:
  108. self.app.tool_shapes.redraw()
  109. def draw_selection_shape_polygon(self, points, **kwargs):
  110. """
  111. :param points: a list of points from which to create a Polygon
  112. :param kwargs:
  113. :return:
  114. """
  115. if 'color' in kwargs:
  116. color = kwargs['color']
  117. else:
  118. color = self.app.defaults['global_sel_line']
  119. if 'face_color' in kwargs:
  120. face_color = kwargs['face_color']
  121. else:
  122. face_color = self.app.defaults['global_sel_fill']
  123. if 'face_alpha' in kwargs:
  124. face_alpha = kwargs['face_alpha']
  125. else:
  126. face_alpha = 0.3
  127. if len(points) < 3:
  128. sel_rect = LineString(points)
  129. else:
  130. sel_rect = Polygon(points)
  131. # color_t = Color(face_color)
  132. # color_t.alpha = face_alpha
  133. color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
  134. self.app.tool_shapes.add(sel_rect, color=color, face_color=color_t, update=True,
  135. layer=0, tolerance=None)
  136. if self.app.is_legacy is True:
  137. self.app.tool_shapes.redraw()
  138. def delete_tool_selection_shape(self):
  139. self.app.tool_shapes.clear()
  140. self.app.tool_shapes.redraw()
  141. def draw_moving_selection_shape_poly(self, points, data, **kwargs):
  142. """
  143. :param points:
  144. :param data:
  145. :param kwargs:
  146. :return:
  147. """
  148. if 'color' in kwargs:
  149. color = kwargs['color']
  150. else:
  151. color = self.app.defaults['global_sel_line']
  152. if 'face_color' in kwargs:
  153. face_color = kwargs['face_color']
  154. else:
  155. face_color = self.app.defaults['global_sel_fill']
  156. if 'face_alpha' in kwargs:
  157. face_alpha = kwargs['face_alpha']
  158. else:
  159. face_alpha = 0.3
  160. temp_points = [x for x in points]
  161. try:
  162. if data != temp_points[-1]:
  163. temp_points.append(data)
  164. except IndexError:
  165. return
  166. l_points = len(temp_points)
  167. if l_points == 2:
  168. geo = LineString(temp_points)
  169. elif l_points > 2:
  170. geo = Polygon(temp_points)
  171. else:
  172. return
  173. color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
  174. color_t_error = "#00000000"
  175. if geo.is_valid and not geo.is_empty:
  176. self.app.move_tool.sel_shapes.add(geo, color=color, face_color=color_t, update=True,
  177. layer=0, tolerance=None)
  178. elif not geo.is_valid:
  179. self.app.move_tool.sel_shapes.add(geo, color="red", face_color=color_t_error, update=True,
  180. layer=0, tolerance=None)
  181. if self.app.is_legacy is True:
  182. self.app.move_tool.sel_shapes.redraw()
  183. def delete_moving_selection_shape(self):
  184. self.app.move_tool.sel_shapes.clear()
  185. self.app.move_tool.sel_shapes.redraw()
  186. def confirmation_message(self, accepted, minval, maxval):
  187. if accepted is False:
  188. self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
  189. (_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
  190. else:
  191. self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
  192. def confirmation_message_int(self, accepted, minval, maxval):
  193. if accepted is False:
  194. self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
  195. (_("Edited value is out of range"), minval, maxval))
  196. else:
  197. self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
  198. def sizeHint(self):
  199. """
  200. I've overloaded this just in case I will need to make changes in the future to enforce dimensions
  201. :return:
  202. """
  203. default_hint_size = super(FlatCAMTool, self).sizeHint()
  204. return QtCore.QSize(default_hint_size.width(), default_hint_size.height())