- in 2Sided Plugin clicking LMB and also pressing CTRL+Shift will add the click coordinates to the Drll Alignment Coordinates
- added support for all Plugins to handle the LMB click release event without connect/reconnect of the mouse events - code refactoring in app_Main file
This commit is contained in:
@@ -12,6 +12,9 @@ CHANGELOG for FlatCAM beta
|
||||
- fixed a typo in the Object UI
|
||||
- in 2Sided Plugin advanced mode fixed the bounds calculation: if no object is selected on canvas then the object selected in Source Object is used
|
||||
- in 2Sided Plugin added a new typ of alignment drills: manual. This mode will no longer add pairs of drill holes mirrored against reference but only add in place drill holes
|
||||
- in 2Sided Plugin clicking LMB and also pressing CTRL+Shift will add the click coordinates to the Drll Alignment Coordinates
|
||||
- added support for all Plugins to handle the LMB click release event without connect/reconnect of the mouse events
|
||||
- code refactoring in app_Main file
|
||||
|
||||
3.10.2021
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ class DblSidedTool(AppTool):
|
||||
self.ui.object_type_combo.currentIndexChanged.connect(self.on_object_type)
|
||||
|
||||
self.ui.add_point_button.clicked.connect(self.on_point_add)
|
||||
self.ui.add_drill_point_button.clicked.connect(self.on_drill_add)
|
||||
self.ui.delete_drill_point_button.clicked.connect(self.on_drill_delete_last)
|
||||
self.ui.box_type_radio.activated_custom.connect(self.on_combo_box_type)
|
||||
|
||||
@@ -433,21 +432,35 @@ class DblSidedTool(AppTool):
|
||||
self.app.delete_selection_shape()
|
||||
|
||||
self.ui.axis_location.set_value('point')
|
||||
|
||||
# set the reference point for mirror
|
||||
self.ui.point_entry.set_value(center_pt_coords)
|
||||
|
||||
self.on_exit()
|
||||
self.app.inform.emit('[success] %s' % _("Mirror reference point set."))
|
||||
break
|
||||
|
||||
elif event.button == right_button and self.app.event_is_dragging is False:
|
||||
self.on_exit(cancelled=True)
|
||||
|
||||
def on_mouse_plugin_click_release(self):
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
# if modifiers == QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
# clip_val = self.app.clipboard.text()
|
||||
# self.ui.point_entry.set_value(clip_val)
|
||||
if modifiers == QtCore.Qt.KeyboardModifier.ControlModifier | QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
clip_val = self.app.clipboard.text().replace("[", '').replace("]", '')
|
||||
self.ui.alignment_holes.set_value(clip_val)
|
||||
else:
|
||||
return
|
||||
self.drill_values = clip_val
|
||||
|
||||
def on_exit(self, cancelled=None):
|
||||
self.app.call_source = "app"
|
||||
self.app.ui.notebook.setDisabled(False)
|
||||
self.disconnect_events()
|
||||
|
||||
if cancelled is True:
|
||||
self.app.delete_selection_shape()
|
||||
self.disconnect_events()
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
|
||||
|
||||
def disconnect_events(self):
|
||||
@@ -506,11 +519,6 @@ class DblSidedTool(AppTool):
|
||||
(self.decimals, self.app.pos[0], self.decimals, self.app.pos[1])
|
||||
self.ui.point_entry.set_value(val)
|
||||
|
||||
def on_drill_add(self):
|
||||
self.drill_values += (self.app.defaults["global_point_clipboard_format"] %
|
||||
(self.decimals, self.app.pos[0], self.decimals, self.app.pos[1])) + ','
|
||||
self.ui.alignment_holes.set_value(self.drill_values)
|
||||
|
||||
def on_drill_delete_last(self):
|
||||
drill_values_without_last_tupple = self.drill_values.rpartition('(')[0]
|
||||
self.drill_values = drill_values_without_last_tupple
|
||||
@@ -897,13 +905,6 @@ class DsidedUI:
|
||||
"The (x, y) coordinates are captured by pressing SHIFT key\n"
|
||||
"and left mouse button click on canvas or you can enter the coordinates manually.")
|
||||
)
|
||||
# self.add_point_button.setStyleSheet("""
|
||||
# QPushButton
|
||||
# {
|
||||
# font-weight: bold;
|
||||
# }
|
||||
# """)
|
||||
# self.add_point_button.setMinimumWidth(60)
|
||||
|
||||
pr_hlay.addWidget(self.point_entry, stretch=1)
|
||||
pr_hlay.addWidget(self.add_point_button)
|
||||
@@ -1072,41 +1073,21 @@ class DsidedUI:
|
||||
"- one drill in mirror position over the axis selected above in the 'Align Axis'.")
|
||||
)
|
||||
|
||||
grid4.addWidget(self.ah_label, 8, 0, 1, 2)
|
||||
|
||||
self.alignment_holes = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
self.alignment_holes.setPlaceholderText(_("Drill coordinates"))
|
||||
|
||||
grid4.addWidget(self.ah_label, 8, 0, 1, 2)
|
||||
grid4.addWidget(self.alignment_holes, 9, 0, 1, 2)
|
||||
|
||||
self.add_drill_point_button = FCButton(_("Add"))
|
||||
self.add_drill_point_button.setIcon(QtGui.QIcon(self.app.resource_location + '/plus16.png'))
|
||||
self.add_drill_point_button.setToolTip(
|
||||
_("Add alignment drill holes coordinates in the format: (x1, y1), (x2, y2), ... \n"
|
||||
"on one side of the alignment axis.\n\n"
|
||||
"The coordinates set can be obtained:\n"
|
||||
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
|
||||
"- press SHIFT key and left mouse clicking on canvas. Then Ctrl+V in the field.\n"
|
||||
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the field and click Paste.\n"
|
||||
"- by entering the coords manually in the format: (x1, y1), (x2, y2), ...")
|
||||
)
|
||||
# self.add_drill_point_button.setStyleSheet("""
|
||||
# QPushButton
|
||||
# {
|
||||
# font-weight: bold;
|
||||
# }
|
||||
# """)
|
||||
|
||||
self.delete_drill_point_button = FCButton(_("Delete Last"))
|
||||
self.delete_drill_point_button = QtWidgets.QToolButton()
|
||||
self.delete_drill_point_button.setIcon(QtGui.QIcon(self.app.resource_location + '/trash32.png'))
|
||||
self.delete_drill_point_button.setToolTip(
|
||||
_("Delete the last coordinates tuple in the list.")
|
||||
)
|
||||
drill_hlay = QtWidgets.QHBoxLayout()
|
||||
|
||||
drill_hlay.addWidget(self.add_drill_point_button)
|
||||
drill_hlay.addWidget(self.delete_drill_point_button)
|
||||
|
||||
grid4.addLayout(drill_hlay, 10, 0, 1, 2)
|
||||
hlay = QtWidgets.QHBoxLayout()
|
||||
hlay.addWidget(self.alignment_holes)
|
||||
hlay.addWidget(self.delete_drill_point_button)
|
||||
grid4.addLayout(hlay, 9, 0, 1, 2)
|
||||
|
||||
FCGridLayout.set_common_column_size([obj_grid, grid_bounds, grid_mirror, grid_box_ref, grid4], 0)
|
||||
|
||||
|
||||
268
app_Main.py
268
app_Main.py
@@ -1231,6 +1231,9 @@ class App(QtCore.QObject):
|
||||
self.corners_tool = None
|
||||
self.etch_tool = None
|
||||
|
||||
# when this list will get populated will contain a list of references to all the Plugins in this APp
|
||||
self.app_plugins = []
|
||||
|
||||
# always install tools only after the shell is initialized because the self.inform.emit() depends on shell
|
||||
try:
|
||||
self.install_tools()
|
||||
@@ -1988,6 +1991,46 @@ class App(QtCore.QObject):
|
||||
self.pcb_wizard_tool.install(icon=QtGui.QIcon(self.resource_location + '/drill32.png'),
|
||||
pos=self.ui.menufileimport)
|
||||
|
||||
# create a list of plugins references
|
||||
self.app_plugins = [
|
||||
self.dblsidedtool,
|
||||
self.distance_tool,
|
||||
self.distance_min_tool,
|
||||
self.panelize_tool,
|
||||
self.film_tool,
|
||||
self.paste_tool,
|
||||
self.calculator_tool,
|
||||
self.rules_tool,
|
||||
self.sub_tool,
|
||||
self.move_tool,
|
||||
|
||||
self.cutout_tool,
|
||||
self.ncclear_tool,
|
||||
self.paint_tool,
|
||||
self.isolation_tool,
|
||||
self.follow_tool,
|
||||
self.drilling_tool,
|
||||
self.milling_tool,
|
||||
self.levelling_tool,
|
||||
|
||||
self.optimal_tool,
|
||||
self.transform_tool,
|
||||
self.report_tool,
|
||||
self.pdf_tool,
|
||||
self.image_tool,
|
||||
self.pcb_wizard_tool,
|
||||
self.cal_exc_tool,
|
||||
self.qrcode_tool,
|
||||
self.copper_thieving_tool,
|
||||
self.fiducial_tool,
|
||||
self.extract_tool,
|
||||
self.align_objects_tool,
|
||||
self.punch_tool,
|
||||
self.invert_tool,
|
||||
self.corners_tool,
|
||||
self.etch_tool
|
||||
]
|
||||
|
||||
self.log.debug("Tools are installed.")
|
||||
|
||||
def remove_tools(self):
|
||||
@@ -2012,10 +2055,17 @@ class App(QtCore.QObject):
|
||||
self.log.debug("init_tools()")
|
||||
|
||||
# delete the data currently in the Tools Tab and the Tab itself
|
||||
widget = QtWidgets.QTabWidget.widget(self.ui.notebook, 2)
|
||||
found_idx = None
|
||||
for tab_idx in range(self.ui.notebook.count()):
|
||||
if self.ui.notebook.widget(tab_idx).objectName() == "plugin_tab":
|
||||
found_idx = tab_idx
|
||||
print(found_idx)
|
||||
break
|
||||
remove_idx = found_idx if found_idx else 2
|
||||
widget = QtWidgets.QTabWidget.widget(self.ui.notebook, remove_idx)
|
||||
if widget is not None:
|
||||
widget.deleteLater()
|
||||
self.ui.notebook.removeTab(2)
|
||||
self.ui.notebook.removeTab(remove_idx)
|
||||
|
||||
# rebuild the Tools Tab
|
||||
# self.ui.plugin_tab = QtWidgets.QWidget()
|
||||
@@ -2677,7 +2727,7 @@ class App(QtCore.QObject):
|
||||
break
|
||||
if found_idx:
|
||||
self.ui.notebook.setCurrentWidget(self.ui.properties_tab)
|
||||
self.ui.notebook.removeTab(2)
|
||||
self.ui.notebook.removeTab(found_idx)
|
||||
|
||||
if edited_obj.kind == 'geometry':
|
||||
obj_type = "Geometry"
|
||||
@@ -6701,7 +6751,7 @@ class App(QtCore.QObject):
|
||||
break
|
||||
if found_idx:
|
||||
self.ui.notebook.setCurrentWidget(self.ui.properties_tab)
|
||||
self.ui.notebook.removeTab(2)
|
||||
self.ui.notebook.removeTab(found_idx)
|
||||
|
||||
# HACK: the content was removed but let's create it again
|
||||
self.ui.plugin_tab = QtWidgets.QWidget()
|
||||
@@ -6759,7 +6809,7 @@ class App(QtCore.QObject):
|
||||
self.app_obj.object_changed.emit(obj)
|
||||
self.inform.emit('[success] %s.' % _("Flip on Y axis done"))
|
||||
except Exception as e:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s.' % (_("Action was not executed"), str(e)))
|
||||
self.inform.emit('[ERROR_NOTCL] %s: %s.' % (_("Action was not executed"), str(e)))
|
||||
return
|
||||
|
||||
def on_flipx(self):
|
||||
@@ -6805,7 +6855,7 @@ class App(QtCore.QObject):
|
||||
self.app_obj.object_changed.emit(obj)
|
||||
self.inform.emit('[success] %s.' % _("Flip on X axis done"))
|
||||
except Exception as e:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s.' % (_("Action was not executed"), str(e)))
|
||||
self.inform.emit('[ERROR_NOTCL] %s: %s.' % (_("Action was not executed"), str(e)))
|
||||
return
|
||||
|
||||
def on_rotate(self, silent=False, preset=None):
|
||||
@@ -7310,90 +7360,143 @@ class App(QtCore.QObject):
|
||||
# if the released mouse button was RMB then test if it was a panning motion or not, if not it was a context
|
||||
# canvas menu
|
||||
if event.button == right_button and self.ui.popMenu.mouse_is_panning is False: # right click
|
||||
self.ui.popMenu.mouse_is_panning = False
|
||||
|
||||
if self.inhibit_context_menu is False:
|
||||
self.cursor = QtGui.QCursor()
|
||||
self.populate_cmenu_grids()
|
||||
self.ui.popMenu.popup(self.cursor.pos())
|
||||
self.on_mouse_context_menu()
|
||||
|
||||
# if the released mouse button was LMB then test if we had a right-to-left selection or a left-to-right
|
||||
# selection and then select a type of selection ("enclosing" or "touching")
|
||||
|
||||
if event.button == 1: # left click
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
|
||||
if modifiers == QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
# do not auto open the Project Tab
|
||||
self.click_noproject = True
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
shift_modifier_key = QtCore.Qt.KeyboardModifier.ShiftModifier
|
||||
ctrl_modifier_key = QtCore.Qt.KeyboardModifier.ControlModifier
|
||||
ctrl_shift_modifier_key = ctrl_modifier_key | shift_modifier_key
|
||||
|
||||
self.clipboard.setText(
|
||||
self.defaults["global_point_clipboard_format"] %
|
||||
(self.decimals, self.pos[0], self.decimals, self.pos[1])
|
||||
)
|
||||
self.inform.emit('[success] %s' % _("Coordinates copied to clipboard."))
|
||||
if key_modifier == shift_modifier_key or key_modifier == ctrl_shift_modifier_key:
|
||||
self.on_mouse_and_key_modifiers(position=self.pos, modifiers=key_modifier)
|
||||
self.on_mouse_plugin_click_release()
|
||||
return
|
||||
else:
|
||||
self.on_mouse_plugin_click_release()
|
||||
|
||||
# the object selection on canvas does not work for App Tools or for Editors
|
||||
# the object selection on canvas will not work for App Tools or for Editors
|
||||
if self.call_source != 'app':
|
||||
return
|
||||
|
||||
if self.doubleclick is True:
|
||||
self.doubleclick = False
|
||||
if self.collection.get_selected():
|
||||
self.ui.notebook.setCurrentWidget(self.ui.properties_tab)
|
||||
if self.ui.splitter.sizes()[0] == 0:
|
||||
self.ui.splitter.setSizes([1, 1])
|
||||
try:
|
||||
# delete the selection shape(S) as it may be in the way
|
||||
self.delete_selection_shape()
|
||||
self.delete_hover_shape()
|
||||
except Exception as e:
|
||||
self.log.error(
|
||||
"FlatCAMApp.on_mouse_click_release_over_plot() double click --> Error: %s" % str(e))
|
||||
return
|
||||
self.on_mouse_double_click()
|
||||
return
|
||||
|
||||
# WORKAROUND for LEGACY MODE
|
||||
if self.is_legacy is True:
|
||||
# if there is no move on canvas then we have no dragging selection
|
||||
if self.dx == 0 or self.dy == 0:
|
||||
self.selection_type = None
|
||||
|
||||
if self.selection_type is not None:
|
||||
try:
|
||||
self.selection_area_handler(self.pos, pos, self.selection_type)
|
||||
self.selection_type = None
|
||||
except Exception as e:
|
||||
self.log.error(
|
||||
"FlatCAMApp.on_mouse_click_release_over_plot() select area --> Error: %s" % str(e))
|
||||
return
|
||||
|
||||
if key_modifier == shift_modifier_key:
|
||||
mod_key = 'Shift'
|
||||
elif key_modifier == ctrl_modifier_key:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
# WORKAROUND for LEGACY MODE
|
||||
if self.is_legacy is True:
|
||||
# if there is no move on canvas then we have no dragging selection
|
||||
if self.dx == 0 or self.dy == 0:
|
||||
self.selection_type = None
|
||||
mod_key = None
|
||||
|
||||
if self.selection_type is not None:
|
||||
try:
|
||||
self.selection_area_handler(self.pos, pos, self.selection_type)
|
||||
self.selection_type = None
|
||||
except Exception as e:
|
||||
self.log.error(
|
||||
"FlatCAMApp.on_mouse_click_release_over_plot() select area --> Error: %s" % str(e))
|
||||
return
|
||||
else:
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
if key_modifier == QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif key_modifier == QtCore.Qt.KeyboardModifier.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
try:
|
||||
if self.command_active is None:
|
||||
if mod_key == self.defaults["global_mselect_key"]:
|
||||
# If the modifier key is pressed when the LMB is clicked then if the object is selected it will
|
||||
# deselect, and if it's not selected then it will be selected
|
||||
self.select_objects(key='multisel')
|
||||
else:
|
||||
mod_key = None
|
||||
# If there is no active command (self.command_active is None) then we check if
|
||||
# we clicked on a object by checking the bounding limits against mouse click position
|
||||
self.select_objects()
|
||||
|
||||
try:
|
||||
if self.command_active is None:
|
||||
# If the CTRL key is pressed when the LMB is clicked then if the object is selected it will
|
||||
# deselect, and if it's not selected then it will be selected
|
||||
# If there is no active command (self.command_active is None) then we check if we clicked
|
||||
# on a object by checking the bounding limits against mouse click position
|
||||
if mod_key == self.defaults["global_mselect_key"]:
|
||||
self.select_objects(key='multisel')
|
||||
else:
|
||||
# If there is no active command (self.command_active is None) then we check if
|
||||
# we clicked on a object by checking the bounding limits against mouse click position
|
||||
self.select_objects()
|
||||
self.delete_hover_shape()
|
||||
except Exception as e:
|
||||
self.log.error(
|
||||
"FlatCAMApp.on_mouse_click_release_over_plot() select click --> Error: %s" % str(e))
|
||||
return
|
||||
|
||||
self.delete_hover_shape()
|
||||
except Exception as e:
|
||||
self.log.error(
|
||||
"FlatCAMApp.on_mouse_click_release_over_plot() select click --> Error: %s" % str(e))
|
||||
return
|
||||
def on_mouse_double_click(self):
|
||||
"""
|
||||
Called when mouse double clicking on canvas.
|
||||
|
||||
:return:
|
||||
"""
|
||||
self.doubleclick = False
|
||||
if self.collection.get_selected():
|
||||
self.ui.notebook.setCurrentWidget(self.ui.properties_tab)
|
||||
if self.ui.splitter.sizes()[0] == 0:
|
||||
self.ui.splitter.setSizes([1, 1])
|
||||
try:
|
||||
# delete the selection shape(S) as it may be in the way
|
||||
self.delete_selection_shape()
|
||||
self.delete_hover_shape()
|
||||
except Exception as e:
|
||||
self.log.error(
|
||||
"FlatCAMApp.on_mouse_click_release_over_plot() double click --> Error: %s" % str(e))
|
||||
|
||||
def on_mouse_and_key_modifiers(self, position, modifiers):
|
||||
"""
|
||||
Called when the mouse is left-clicked on canvas and simultaneously a key modifier
|
||||
(Ctrl, AAlt, Shift) is pressed.
|
||||
|
||||
:param position: A tupple made of the clicked position x, y coordinates
|
||||
:param modifiers: Key modifiers (Ctrl, Alt, Shift or a combination of them)
|
||||
:return:
|
||||
"""
|
||||
|
||||
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
|
||||
if modifiers == QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
# do not auto open the Project Tab
|
||||
self.click_noproject = True
|
||||
|
||||
self.clipboard.setText(
|
||||
self.defaults["global_point_clipboard_format"] %
|
||||
(self.decimals,position[0], self.decimals, position[1])
|
||||
)
|
||||
self.inform.emit('[success] %s' % _("Coordinates copied to clipboard."))
|
||||
elif modifiers == QtCore.Qt.KeyboardModifier.ControlModifier | QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
try:
|
||||
old_clipb = eval(self.clipboard.text())
|
||||
except Exception as err:
|
||||
# self.log.error("App.on_mouse_and_key_modifiers() --> %s" % str(err))
|
||||
old_clipb = None
|
||||
|
||||
clip_pos_val = (
|
||||
self.dec_format(position[0], self.decimals),
|
||||
self.dec_format(position[1], self.decimals)
|
||||
)
|
||||
clip_text = "(%s, %s)" % (str(clip_pos_val[0]), str(clip_pos_val[1]))
|
||||
|
||||
if old_clipb is None or old_clipb == '':
|
||||
self.clipboard.setText(clip_text)
|
||||
else:
|
||||
if isinstance(old_clipb, list):
|
||||
old_clipb.append(clip_pos_val)
|
||||
else:
|
||||
old_clipb = [old_clipb, clip_pos_val]
|
||||
self.clipboard.setText(str(old_clipb))
|
||||
self.inform.emit('[success] %s' % _("Coordinates copied to clipboard."))
|
||||
|
||||
def on_mouse_context_menu(self):
|
||||
"""
|
||||
Display a context menu when mouse right-clicking on canvas.
|
||||
|
||||
:return:
|
||||
"""
|
||||
if self.inhibit_context_menu is False:
|
||||
self.cursor = QtGui.QCursor()
|
||||
self.populate_cmenu_grids()
|
||||
self.ui.popMenu.popup(self.cursor.pos())
|
||||
|
||||
def selection_area_handler(self, start_pos, end_pos, sel_type):
|
||||
"""
|
||||
@@ -7613,6 +7716,25 @@ class App(QtCore.QObject):
|
||||
tx=_("selected"))
|
||||
)
|
||||
|
||||
def on_mouse_plugin_click_release(self):
|
||||
"""
|
||||
Handle specific tasks in the Plugins for the mouse click release
|
||||
|
||||
:return:
|
||||
"""
|
||||
|
||||
if self.ui.notebook.currentWidget().objectName() == "plugin_tab":
|
||||
tab_idx = self.ui.notebook.currentIndex()
|
||||
for plugin in self.app_plugins:
|
||||
# execute this only for the current active plugin
|
||||
if self.ui.notebook.tabText(tab_idx) == plugin.pluginName:
|
||||
try:
|
||||
plugin.on_mouse_plugin_click_release()
|
||||
except AttributeError:
|
||||
# not all plugins have this implemented
|
||||
# print("This does not have it", self.ui.notebook.tabText(tab_idx))
|
||||
pass
|
||||
|
||||
def delete_hover_shape(self):
|
||||
self.hover_shapes.clear()
|
||||
self.hover_shapes.redraw()
|
||||
|
||||
Reference in New Issue
Block a user