Bladeren bron

Make shape-related actions context sensitive

`delete' and `copy' are only enabled if a shape is selected, while `new
item' only if not already in create mode.
Michael Pitidis 13 jaren geleden
bovenliggende
commit
2b6cbafb31
3 gewijzigde bestanden met toevoegingen van 22 en 18 verwijderingen
  1. 3 0
      canvas.py
  2. 17 17
      labelme.py
  3. 2 1
      lib.py

+ 3 - 0
canvas.py

@@ -10,6 +10,7 @@ class Canvas(QWidget):
     zoomRequest = pyqtSignal(int)
     scrollRequest = pyqtSignal(int, int)
     newShape = pyqtSignal(QPoint)
+    selectionChanged = pyqtSignal(bool)
 
     SELECT, EDIT = range(2)
 
@@ -145,6 +146,7 @@ class Canvas(QWidget):
                 self.selectedShape = shape
                 self.calculateOffsets(shape, point)
                 self.setHiding()
+                self.selectionChanged.emit(True)
                 return
 
     def calculateOffsets(self, shape, point):
@@ -178,6 +180,7 @@ class Canvas(QWidget):
             self.selectedShape.selected = False
             self.selectedShape = None
             self.setHiding(False)
+            self.selectionChanged.emit(False)
 
     def deleteSelected(self):
         if self.selectedShape:

+ 17 - 17
labelme.py

@@ -24,13 +24,10 @@ from labelFile import LabelFile
 __appname__ = 'labelme'
 
 # FIXME
+# - Select shapes with right click as well.
 # - [low] Label validation/postprocessing breaks with TAB.
-# - Disable context menu entries depending on context.
 
 # TODO:
-# - Add a new column in list widget with checkbox to show/hide shape.
-# - Make sure the `save' action is disabled when no labels are
-#   present in the image, e.g. when all of them are deleted.
 # - [easy] Add button to Hide/Show all labels.
 # - Zoom is too "steppy".
 
@@ -83,7 +80,6 @@ class MainWindow(QMainWindow, WindowMixin):
         self.canvas = Canvas()
         #self.canvas.setAlignment(Qt.AlignCenter)
 
-        self.canvas.setContextMenuPolicy(Qt.ActionsContextMenu)
         self.canvas.zoomRequest.connect(self.zoomRequest)
 
         scroll = QScrollArea()
@@ -96,6 +92,7 @@ class MainWindow(QMainWindow, WindowMixin):
         self.canvas.scrollRequest.connect(self.scrollRequest)
 
         self.canvas.newShape.connect(self.newShape)
+        self.canvas.selectionChanged.connect(self.shapeSelectionChanged)
 
         self.setCentralWidget(scroll)
         self.addDockWidget(Qt.RightDockWidgetArea, self.dock)
@@ -113,22 +110,19 @@ class MainWindow(QMainWindow, WindowMixin):
         label = action('&New Item', self.newLabel,
                 'Ctrl+N', 'new', u'Add new label')
         copy = action('&Copy', self.copySelectedShape,
-                'Ctrl+C', 'copy', u'Copy')
+                'Ctrl+C', 'copy', u'Copy', enabled=False)
         delete = action('&Delete', self.deleteSelectedShape,
-                'Ctrl+D', 'delete', u'Delete')
+                'Ctrl+D', 'delete', u'Delete', enabled=False)
         hide = action('&Hide labels', self.hideLabelsToggle,
                 'Ctrl+H', 'hide', u'Hide background labels when drawing',
                 checkable=True)
 
-        self.canvas.setContextMenuPolicy( Qt.CustomContextMenu )
+        # Custom context menu for the canvas widget:
+        self.popMenu = QMenu(self)
+        addActions(self.popMenu, (label, copy, delete))
+        self.canvas.setContextMenuPolicy(Qt.CustomContextMenu)
         self.canvas.customContextMenuRequested.connect(self.popContextMenu)
 
-        # Popup Menu
-        self.popMenu = QMenu(self )
-        self.popMenu.addAction( label )
-        self.popMenu.addAction(copy)
-        self.popMenu.addAction( delete )
-
         labels = self.dock.toggleViewAction()
         labels.setShortcut('Ctrl+L')
 
@@ -137,7 +131,7 @@ class MainWindow(QMainWindow, WindowMixin):
 
         # Store actions for further handling.
         self.actions = struct(save=save, open=open, color=color,
-                label=label, delete=delete, zoom=zoom)
+                label=label, delete=delete, zoom=zoom, copy=copy)
         save.setEnabled(False)
 
         fit_window = action('&Fit Window', self.setFitWindow,
@@ -153,7 +147,7 @@ class MainWindow(QMainWindow, WindowMixin):
         addActions(self.menus.view, (labels,))
 
         self.tools = self.toolbar('Tools')
-        addActions(self.tools, (open, save, color, None, label, delete, hide, None,
+        addActions(self.tools, (open, save, color, labels, None, label, delete, hide, None,
             zoom, fit_window, None, quit))
 
 
@@ -198,6 +192,10 @@ class MainWindow(QMainWindow, WindowMixin):
         # Callbacks:
         self.zoom_widget.editingFinished.connect(self.paintCanvas)
 
+    def shapeSelectionChanged(self, selected=False):
+        self.actions.delete.setEnabled(selected)
+        self.actions.copy.setEnabled(selected)
+
     def popContextMenu(self, point):
         self.popMenu.exec_(self.canvas.mapToGlobal(point))
 
@@ -262,8 +260,9 @@ class MainWindow(QMainWindow, WindowMixin):
         action = self.label.popUp(position)
         if action == self.label.OK:
             self.addLabel(self.canvas.setLastLabel(self.label.text()))
-            # Enable the save action.
+            # Enable appropriate actions.
             self.actions.save.setEnabled(True)
+            self.actions.label.setEnabled(True)
         elif action == self.label.UNDO:
             self.canvas.undoLastLine()
         elif action == self.label.DELETE:
@@ -406,6 +405,7 @@ class MainWindow(QMainWindow, WindowMixin):
     def newLabel(self):
         self.canvas.deSelectShape()
         self.canvas.setEditing()
+        self.actions.label.setEnabled(False)
 
     def deleteSelectedShape(self):
         self.remLabel(self.canvas.deleteSelected())

+ 2 - 1
lib.py

@@ -15,7 +15,7 @@ def newButton(text, icon=None, slot=None):
     return b
 
 def newAction(parent, text, slot=None, shortcut=None, icon=None,
-        tip=None, checkable=False):
+        tip=None, checkable=False, enabled=True):
     """Create a new action and assign callbacks, shortcuts, etc."""
     a = QAction(text, parent)
     if icon is not None:
@@ -29,6 +29,7 @@ def newAction(parent, text, slot=None, shortcut=None, icon=None,
         a.triggered.connect(slot)
     if checkable:
         a.setCheckable(True)
+    a.setEnabled(enabled)
     return a