diff --git a/FlatCAMApp.py b/FlatCAMApp.py index b4bfc580..8f9285da 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -700,6 +700,7 @@ class App(QtCore.QObject): # Global APP Preferences "global_serial": 0, "global_stats": {}, + "global_tabs_detachable": True, "units": "IN", "global_app_level": 'b', "global_language": 'English', @@ -1580,6 +1581,14 @@ class App(QtCore.QObject): # ToolBar signals self.connect_toolbar_signals() + # Notebook signals + # make the right click on the notebook tab connect to a function + self.ui.notebook.setupContextMenu() + self.ui.notebook.addContextMenu( + "Detachable Tabs", self.on_notebook_tab_rmb_click, initial_checked=self.defaults["global_tabs_detachable"]) + # activate initial state + self.on_notebook_tab_rmb_click(self.defaults["global_tabs_detachable"]) + # Context Menu self.ui.popmenu_disable.triggered.connect(lambda: self.toggle_plots(self.collection.get_selected())) self.ui.popmenu_panel_toggle.triggered.connect(self.on_toggle_notebook) @@ -4598,6 +4607,10 @@ class App(QtCore.QObject): self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry.set_value(new_val_sel) self.defaults['global_proj_item_dis_color'] = new_val_sel + def on_notebook_tab_rmb_click(self, checked): + self.ui.notebook.set_detachable(val=checked) + self.defaults["global_tabs_detachable"] = checked + def on_deselect_all(self): self.collection.set_all_inactive() self.delete_selection_shape() diff --git a/README.md b/README.md index af921bbd..88de6423 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing. ================================================= +22.08.2019 + +- added ability to turn ON/OFF the detachable capability of the tabs in Notebook through a context menu activated by right mouse button click on the Notebook header + 21.08.2019 - added feature in Paint Tool allowing the painting to be done on Gerber objects diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py index b8d60eeb..84d938c6 100644 --- a/flatcamGUI/GUIElements.py +++ b/flatcamGUI/GUIElements.py @@ -847,9 +847,9 @@ class FCDetachableTab(QtWidgets.QTabWidget): super().__init__() self.tabBar = self.FCTabBar(self) - self.tabBar.onDetachTabSignal.connect(self.detachTab) self.tabBar.onMoveTabSignal.connect(self.moveTab) self.tabBar.detachedTabDropSignal.connect(self.detachedTabDrop) + self.set_detachable(val=True) self.setTabBar(self.tabBar) @@ -872,6 +872,48 @@ class FCDetachableTab(QtWidgets.QTabWidget): self.setTabsClosable(True) self.tabCloseRequested.connect(self.closeTab) + def set_rmb_callback(self, callback): + """ + + :param callback: Function to call on right mouse click on tab + :type callback: func + :return: None + """ + + self.tabBar.right_click.connect(callback) + + def set_detachable(self, val=True): + try: + self.tabBar.onDetachTabSignal.disconnect() + except TypeError: + pass + + if val is True: + self.tabBar.onDetachTabSignal.connect(self.detachTab) + # the tab can be moved around + self.tabBar.can_be_dragged = True + else: + # the detached tab can't be moved + self.tabBar.can_be_dragged = False + + return val + + def setupContextMenu(self): + self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + + def addContextMenu(self, entry, call_function, icon=None, initial_checked=False): + action_name = str(entry) + action = QtWidgets.QAction(self) + action.setCheckable(True) + action.setText(action_name) + if icon: + assert isinstance(icon, QtGui.QIcon), \ + "Expected the argument to be QtGui.QIcon. Instead it is %s" % type(icon) + action.setIcon(icon) + action.setChecked(initial_checked) + self.addAction(action) + action.triggered.connect(call_function) + def useOldIndex(self, param): if param: self.use_old_index = True @@ -1209,6 +1251,8 @@ class FCDetachableTab(QtWidgets.QTabWidget): onMoveTabSignal = pyqtSignal(int, int) detachedTabDropSignal = pyqtSignal(str, int, QtCore.QPoint) + right_click = pyqtSignal(int) + def __init__(self, parent=None): QtWidgets.QTabBar.__init__(self, parent) @@ -1216,11 +1260,16 @@ class FCDetachableTab(QtWidgets.QTabWidget): self.setElideMode(QtCore.Qt.ElideRight) self.setSelectionBehaviorOnRemove(QtWidgets.QTabBar.SelectLeftTab) + self.prev_index = -1 + self.dragStartPos = QtCore.QPoint() self.dragDropedPos = QtCore.QPoint() self.mouseCursor = QtGui.QCursor() self.dragInitiated = False + # set this to False and the tab will no longer be displayed as detached + self.can_be_dragged = True + def mouseDoubleClickEvent(self, event): """ Send the onDetachTabSignal when a tab is double clicked @@ -1234,21 +1283,37 @@ class FCDetachableTab(QtWidgets.QTabWidget): def mousePressEvent(self, event): """ - Set the starting position for a drag event when the mouse button is pressed + Set the starting position for a drag event when the left mouse button is pressed. + Start detection of a right mouse click. :param event: a mouse press event :return: """ if event.button() == QtCore.Qt.LeftButton: self.dragStartPos = event.pos() + elif event.button() == QtCore.Qt.RightButton: + self.prev_index = self.tabAt(event.pos()) self.dragDropedPos.setX(0) self.dragDropedPos.setY(0) - self.dragInitiated = False QtWidgets.QTabBar.mousePressEvent(self, event) + def mouseReleaseEvent(self, event): + """ + Finish the detection of the right mouse click on the tab + + + :param event: a mouse press event + :return: + """ + if event.button() == QtCore.Qt.RightButton and self.prev_index == self.tabAt(event.pos()): + self.right_click.emit(self.prev_index) + self.prev_index = -1 + + QtWidgets.QTabBar.mouseReleaseEvent(self, event) + def mouseMoveEvent(self, event): """ Determine if the current movement is a drag. If it is, convert it into a QDrag. If the @@ -1264,7 +1329,7 @@ class FCDetachableTab(QtWidgets.QTabWidget): self.dragInitiated = True # If the current movement is a drag initiated by the left button - if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated): + if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged): # Stop the move event finishMoveEvent = QtGui.QMouseEvent(