소스 검색

Merge branch 'feature/zoom'

Michael Pitidis 13 년 전
부모
커밋
350b9d596d
2개의 변경된 파일82개의 추가작업 그리고 19개의 파일을 삭제
  1. 68 19
      labelme.py
  2. 14 0
      zoomwidget.py

+ 68 - 19
labelme.py

@@ -12,6 +12,7 @@ from PyQt4.QtGui import *
 from PyQt4.QtCore import *
 
 from canvas import Canvas
+from zoomwidget import ZoomWidget
 
 __appname__ = 'labelme'
 
@@ -74,23 +75,43 @@ class MainWindow(QMainWindow, WindowMixin):
         self.dock = QDockWidget(u'Label', parent=self)
         self.dock.setObjectName(u'Label')
         self.dock.setWidget(self.label)
+        self.zoom_widget = ZoomWidget()
         #self.dock.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetFloatable)
 
-        self.imageWidget = Canvas()
-        self.imageWidget.setAlignment(Qt.AlignCenter)
-        self.imageWidget.setContextMenuPolicy(Qt.ActionsContextMenu)
+        self.canvas = Canvas()
+        self.canvas.setAlignment(Qt.AlignCenter)
+        self.canvas.setContextMenuPolicy(Qt.ActionsContextMenu)
 
+        scroll = QScrollArea()
+        scroll.setWidget(self.canvas)
+        scroll.setWidgetResizable(True)
+
+        self.setCentralWidget(scroll)
         self.addDockWidget(Qt.BottomDockWidgetArea, self.dock)
-        self.setCentralWidget(self.imageWidget)
 
         # Actions
         quit = action(self, '&Quit', self.close, 'Ctrl+Q', u'Exit application')
         open = action(self, '&Open', self.openFile, 'Ctrl+O', u'Open file')
+        color = action(self, '&Color', self.chooseColor, 'Ctrl+C', u'Choose line color')
         labl = self.dock.toggleViewAction()
         labl.setShortcut('Ctrl+L')
 
-        add_actions(self.menu('&File'), (open, None, labl, None, quit))
-        add_actions(self.toolbar('Tools'), (open, None, labl, None, quit))
+        zoom = QWidgetAction(self)
+        zoom.setDefaultWidget(self.zoom_widget)
+        fit_window = action(self, '&Fit Window', self.setFitWindow,
+                'Ctrl+F', u'Fit image to window', checkable=True)
+
+        self.menus = struct(
+                file=self.menu('&File'),
+                edit=self.menu('&Image'),
+                view=self.menu('&View'))
+        add_actions(self.menus.file, (open, quit))
+        add_actions(self.menus.edit, (color, fit_window))
+        add_actions(self.menus.view, (labl,))
+
+        self.tools = self.toolbar('Tools')
+        add_actions(self.tools, (open, color, None, zoom, fit_window, None, quit))
+
 
         self.statusBar().showMessage('%s started.' % __appname__)
         self.statusBar().show()
@@ -99,6 +120,9 @@ class MainWindow(QMainWindow, WindowMixin):
         self.image = QImage()
         self.filename = filename
         self.recent_files = []
+        self.color = None
+        self.zoom_level = 100
+        self.fit_window = False
 
         # TODO: Could be completely declarative.
         # Restore application settings.
@@ -120,12 +144,23 @@ class MainWindow(QMainWindow, WindowMixin):
         # or simply:
         #self.restoreGeometry(settings['window/geometry']
         self.restoreState(settings['window/state'])
+        self.color = QColor(settings.get('line/color', QColor(0, 255, 0, 128)))
 
         # The file menu has default dynamically generated entries.
         self.updateFileMenu()
         # Since loading the file may take some time, make sure it runs in the background.
         self.queueEvent(partial(self.loadFile, self.filename))
 
+        # Callbacks:
+        self.zoom_widget.editingFinished.connect(self.showImage)
+
+
+    ## Callback functions:
+    def setFitWindow(self, value=True):
+        self.zoom_widget.setEnabled(not value)
+        self.fit_window = value
+        self.showImage()
+
     def queueEvent(self, function):
         QTimer.singleShot(0, function)
 
@@ -146,22 +181,27 @@ class MainWindow(QMainWindow, WindowMixin):
                 self.showImage()
             self.statusBar().showMessage(message)
 
-    def showImage(self):
-        if self.image.isNull():
-            return
-        self.imageWidget.setPixmap(self.scaled(QPixmap.fromImage(self.image)))
-        self.imageWidget.show()
-
     def resizeEvent(self, event):
-        if self.imageWidget and self.imageWidget.pixmap():
-            self.imageWidget.setPixmap(self.scaled(self.imageWidget.pixmap()))
+        if self.fit_window and self.canvas and not self.image.isNull():
+            self.showImage()
         super(MainWindow, self).resizeEvent(event)
 
-    def scaled(self, pixmap):
-        width = self.centralWidget().width()
-        height = self.centralWidget().height()
-        return pixmap.scaled(width, height,
-          Qt.KeepAspectRatio, Qt.SmoothTransformation)
+    def showImage(self):
+        if self.image.isNull():
+            return
+        size = self.imageSize()
+        self.canvas.setPixmap(QPixmap.fromImage(self.image.scaled(
+                size, Qt.KeepAspectRatio, Qt.SmoothTransformation)))
+        self.canvas.show()
+
+    def imageSize(self):
+        """Calculate the size of the image based on current settings."""
+        if self.fit_window:
+            width, height = self.centralWidget().width()-2, self.centralWidget().height()-2
+        else: # Follow zoom:
+            s = self.zoom_widget.value() / 100.0
+            width, height = s * self.image.width(), s * self.image.height()
+        return QSize(width, height)
 
     def closeEvent(self, event):
         # TODO: Make sure changes are saved.
@@ -170,6 +210,7 @@ class MainWindow(QMainWindow, WindowMixin):
         s['window/size'] = self.size()
         s['window/position'] = self.pos()
         s['window/state'] = self.saveState()
+        s['line/color'] = self.color
         #s['window/geometry'] = self.saveGeometry()
 
     def updateFileMenu(self):
@@ -192,6 +233,10 @@ class MainWindow(QMainWindow, WindowMixin):
         # TODO: Prompt user to save labels etc.
         return True
 
+    def chooseColor(self):
+        self.color = QColorDialog.getColor(self.color, self,
+                u'Choose line color', QColorDialog.ShowAlphaChannel)
+
 
 class Settings(object):
     """Convenience dict-like wrapper around QSettings."""
@@ -219,6 +264,10 @@ class Settings(object):
         return value
 
 
+class struct(object):
+    def __init__(self, **kwargs):
+        self.__dict__.update(kwargs)
+
 
 def main(argv):
     """Standard boilerplate Qt application code."""

+ 14 - 0
zoomwidget.py

@@ -0,0 +1,14 @@
+
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+
+class ZoomWidget(QSpinBox):
+    def __init__(self, value=100):
+        super(ZoomWidget, self).__init__()
+        self.setButtonSymbols(QAbstractSpinBox.PlusMinus)
+        self.setRange(1, 500)
+        self.setSuffix(' %')
+        self.setValue(value)
+        self.setToolTip(u'Image zoom')
+        self.setStatusTip(self.toolTip())
+