AppTool.py 9.0 KB

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