提交 2abdd7c2 编写于 作者: M Michael Pitidis

Add detailed zoom actions

The user can now zoom to fit window or width and also original size. The
logic is slightly different now as well, the user can just change the
zoom level to go out of a mode such as fit window.

Add more icons and change the one for drawing to something more
relevant.
上级 02d3cba8
icons/zoom.png

1.7 KB | W: | H:

icons/zoom.png

1.1 KB | W: | H:

icons/zoom.png
icons/zoom.png
icons/zoom.png
icons/zoom.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -26,6 +26,7 @@ __appname__ = 'labelme'
# FIXME
# - [low] Label validation/postprocessing breaks with TAB.
# - Set max zoom value to something big enough for FitWidth/Window
# TODO:
# - [easy] Add button to Hide/Show all labels.
......@@ -54,6 +55,8 @@ class WindowMixin(object):
class MainWindow(QMainWindow, WindowMixin):
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = range(3)
def __init__(self, filename=None):
super(MainWindow, self).__init__()
self.setWindowTitle(__appname__)
......@@ -70,7 +73,7 @@ class MainWindow(QMainWindow, WindowMixin):
self.dock = QDockWidget(u'Labels', self)
self.dock.setObjectName(u'Labels')
self.dock.setWidget(self.labelList)
self.zoom_widget = ZoomWidget()
self.zoomWidget = ZoomWidget()
self.labelList.setItemDelegate(LabelDelegate())
self.labelList.itemActivated.connect(self.highlightLabel)
......@@ -115,6 +118,26 @@ class MainWindow(QMainWindow, WindowMixin):
'Ctrl+H', 'hide', u'Hide background labels when drawing',
checkable=True)
zoom = QWidgetAction(self)
zoom.setDefaultWidget(self.zoomWidget)
zoomIn = action('Zoom &In', partial(self.addZoom, 10),
'Ctrl++', 'zoom-in', u'Increase zoom level')
zoomOut = action('&Zoom Out', partial(self.addZoom, -10),
'Ctrl+-', 'zoom-out', u'Decrease zoom level')
zoomOrg = action('&Original size', partial(self.setZoom, 100),
'Ctrl+=', 'zoom', u'Zoom to original size')
fitWindow = action('&Fit Window', self.setFitWindow,
'Ctrl+F', 'fit-window', u'Zoom follows window size',
checkable=True)
fitWidth = action('Fit &Width', self.setFitWidth,
'Ctrl+W', 'fit-width', u'Zoom follows window width',
checkable=True)
self.zoomMode = self.MANUAL_ZOOM
self.scalers = {
self.FIT_WINDOW: self.scaleFitWindow,
self.FIT_WIDTH: self.scaleFitWidth,
}
# Custom context menu for the canvas widget:
addActions(self.canvas.menus[0], (label, copy, delete))
addActions(self.canvas.menus[1], (
......@@ -124,30 +147,29 @@ class MainWindow(QMainWindow, WindowMixin):
labels = self.dock.toggleViewAction()
labels.setShortcut('Ctrl+L')
zoom = QWidgetAction(self)
zoom.setDefaultWidget(self.zoom_widget)
# Store actions for further handling.
self.actions = struct(save=save, open=open, color=color,
label=label, delete=delete, zoom=zoom, copy=copy)
label=label, delete=delete, zoom=zoom, copy=copy,
zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg,
fitWindow=fitWindow, fitWidth=fitWidth)
save.setEnabled(False)
fit_window = action('&Fit Window', self.setFitWindow,
'Ctrl+F', 'fit', u'Fit image to window', checkable=True)
self.menus = struct(
file=self.menu('&File'),
edit=self.menu('&Image'),
view=self.menu('&View'))
addActions(self.menus.file, (open, save, quit))
addActions(self.menus.edit, (label, color, fit_window))
addActions(self.menus.view, (labels,))
addActions(self.menus.edit, (label, color, fitWindow, fitWidth))
addActions(self.menus.view, (
labels, None,
zoomIn, zoomOut, zoomOrg, None,
fitWindow, fitWidth))
self.tools = self.toolbar('Tools')
addActions(self.tools, (
open, save, None,
label, delete, color, hide, None,
zoom, fit_window, None,
zoomIn, zoom, zoomOut, fitWindow, fitWidth, None,
quit))
self.statusBar().showMessage('%s started.' % __appname__)
......@@ -189,7 +211,7 @@ class MainWindow(QMainWindow, WindowMixin):
self.queueEvent(partial(self.loadFile, self.filename))
# Callbacks:
self.zoom_widget.editingFinished.connect(self.paintCanvas)
self.zoomWidget.valueChanged.connect(self.paintCanvas)
def shapeSelectionChanged(self, selected=False):
self.actions.delete.setEnabled(selected)
......@@ -273,17 +295,31 @@ class MainWindow(QMainWindow, WindowMixin):
bar = self.scrollBars[orientation]
bar.setValue(bar.value() + bar.singleStep() * units)
def setZoom(self, value):
self.actions.fitWidth.setChecked(False)
self.actions.fitWindow.setChecked(False)
self.zoomMode = self.MANUAL_ZOOM
self.zoomWidget.setValue(value)
def addZoom(self, increment=10):
self.setZoom(self.zoomWidget.value() + increment)
def zoomRequest(self, delta):
if not self.fit_window:
units = delta / (8 * 15)
scale = 10
self.zoom_widget.setValue(self.zoom_widget.value() + scale * units)
self.zoom_widget.editingFinished.emit()
units = delta / (8 * 15)
scale = 10
self.addZoom(scale * units)
def setFitWindow(self, value=True):
self.zoom_widget.setEnabled(not value)
self.fit_window = value
self.paintCanvas()
if value:
self.actions.fitWidth.setChecked(False)
self.zoomMode = self.FIT_WINDOW if value else self.MANUAL_ZOOM
self.adjustScale()
def setFitWidth(self, value=True):
if value:
self.actions.fitWindow.setChecked(False)
self.zoomMode = self.FIT_WIDTH if value else self.MANUAL_ZOOM
self.adjustScale()
def queueEvent(self, function):
QTimer.singleShot(0, function)
......@@ -323,18 +359,21 @@ class MainWindow(QMainWindow, WindowMixin):
self.statusBar().showMessage(message)
def resizeEvent(self, event):
if self.fit_window and self.canvas and not self.image.isNull():
self.paintCanvas()
if self.canvas and not self.image.isNull()\
and self.zoomMode != self.MANUAL_ZOOM:
self.adjustScale()
super(MainWindow, self).resizeEvent(event)
def paintCanvas(self):
assert not self.image.isNull(), "cannot paint null image"
self.canvas.scale = self.fitSize() if self.fit_window\
else 0.01 * self.zoom_widget.value()
self.canvas.scale = 0.01 * self.zoomWidget.value()
self.canvas.adjustSize()
self.canvas.repaint()
def fitSize(self):
def adjustScale(self):
self.zoomWidget.setValue(int(100 * self.scalers[self.zoomMode]()))
def scaleFitWindow(self):
"""Figure out the size of the pixmap in order to fit the main widget."""
e = 2.0 # So that no scrollbars are generated.
w1 = self.centralWidget().width() - e
......@@ -346,6 +385,10 @@ class MainWindow(QMainWindow, WindowMixin):
a2 = w2 / h2
return w1 / w2 if a2 >= a1 else h1 / h2
def scaleFitWidth(self):
# The epsilon does not seem to work too well here.
w = self.centralWidget().width() - 2.0
return w / self.canvas.pixmap.width()
def closeEvent(self, event):
# TODO: Make sure changes are saved.
......@@ -356,8 +399,8 @@ class MainWindow(QMainWindow, WindowMixin):
s['window/state'] = self.saveState()
s['line/color'] = self.color
# ask the use for where to save the labels
#s['window/geometry'] = self.saveGeometry()
def updateFileMenu(self):
"""Populate menu with recent files."""
......
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="new">icons/new.png</file>
<file alias="fit">icons/fit.png</file>
<file alias="new">icons/objects.png</file>
<file alias="fit-width">icons/fit-width.png</file>
<file alias="fit-window">icons/fit-window.png</file>
<file alias="hide">icons/eye.png</file>
<file alias="quit">icons/quit.png</file>
<file alias="open">icons/open.png</file>
<file alias="save">icons/open.png</file>
<file alias="color">icons/color.png</file>
<file alias="zoom">icons/zoom.png</file>
<file alias="zoom-in">icons/zoom-in.png</file>
<file alias="zoom-out">icons/zoom-out.png</file>
<file alias="delete">icons/delete.png</file>
</qresource>
......
......@@ -5,10 +5,17 @@ from PyQt4.QtCore import *
class ZoomWidget(QSpinBox):
def __init__(self, value=100):
super(ZoomWidget, self).__init__()
self.setButtonSymbols(QAbstractSpinBox.PlusMinus)
self.setButtonSymbols(QAbstractSpinBox.NoButtons)
self.setRange(1, 500)
self.setSuffix(' %')
self.setValue(value)
self.setToolTip(u'Image zoom')
self.setToolTip(u'Zoom Level')
self.setStatusTip(self.toolTip())
self.setAlignment(Qt.AlignCenter)
def minimumSizeHint(self):
height = super(ZoomWidget, self).minimumSizeHint().height()
fm = QFontMetrics(self.font())
width = fm.width(str(self.maximum()))
return QSize(width, height)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册