Commit d4e8e2b8 authored by Luke Campagnola's avatar Luke Campagnola
Browse files

Imported major changes from acq4 project.

parent 4d846e2a
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>726</width>
<height>588</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="1" column="0" rowspan="3">
<widget class="GraphicsView" name="graphicsView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>10</horstretch>
<verstretch>10</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="roiBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>R</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="GradientWidget" name="gradientWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>100</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="normBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>N</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QGroupBox" name="normGroup">
<property name="title">
<string>Normalization</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="2">
<widget class="QRadioButton" name="normSubtractRadio">
<property name="text">
<string>Subtract</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="normDivideRadio">
<property name="text">
<string>Divide</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Operation:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Mean:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Blur:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="normROICheck">
<property name="text">
<string>ROI</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="normXBlurSpin"/>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_8">
<property name="text">
<string>X</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Y</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QDoubleSpinBox" name="normYBlurSpin"/>
</item>
<item row="2" column="5">
<widget class="QLabel" name="label_10">
<property name="text">
<string>T</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QRadioButton" name="normOffRadio">
<property name="text">
<string>Off</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QCheckBox" name="normTimeRangeCheck">
<property name="text">
<string>Time range</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="normFrameCheck">
<property name="text">
<string>Frame</string>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QDoubleSpinBox" name="normTBlurSpin"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="PlotWidget" name="roiPlot" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GradientWidget</class>
<extends>QWidget</extends>
<header>pyqtgraph.GradientWidget</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GraphicsView</class>
<extends>QWidget</extends>
<header>GraphicsView</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PlotWidget</class>
<extends>QWidget</extends>
<header>PlotWidget</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
......@@ -5,7 +5,7 @@ Copyright 2010 Luke Campagnola
Distributed under MIT/X11 license. See license.txt for more infomation.
"""
from PyQt4 import QtCore
from Qt import QtCore
import numpy as np
def clip(x, mn, mx):
......@@ -23,12 +23,12 @@ class Point(QtCore.QPointF):
if isinstance(args[0], QtCore.QSizeF):
QtCore.QPointF.__init__(self, float(args[0].width()), float(args[0].height()))
return
elif isinstance(args[0], float) or isinstance(args[0], int):
QtCore.QPointF.__init__(self, float(args[0]), float(args[0]))
return
elif hasattr(args[0], '__getitem__'):
QtCore.QPointF.__init__(self, float(args[0][0]), float(args[0][1]))
return
elif type(args[0]) in [float, int]:
QtCore.QPointF.__init__(self, float(args[0]), float(args[0]))
return
elif len(args) == 2:
QtCore.QPointF.__init__(self, args[0], args[1])
return
......@@ -101,6 +101,10 @@ class Point(QtCore.QPointF):
"""Returns the vector length of this Point."""
return (self[0]**2 + self[1]**2) ** 0.5
def norm(self):
"""Returns a vector in the same direction with unit length."""
return self / self.length()
def angle(self, a):
"""Returns the angle in degrees between this vector and the vector a."""
n1 = self.length()
......@@ -139,4 +143,7 @@ class Point(QtCore.QPointF):
return max(self[0], self[1])
def copy(self):
return Point(self)
\ No newline at end of file
return Point(self)
def toQPoint(self):
return QtCore.QPoint(*self)
\ No newline at end of file
File added
## Do all Qt imports from here to allow easier PyQt / PySide compatibility
from PyQt4 import QtGui, QtCore, QtOpenGL, QtSvg
if not hasattr(QtCore, 'Signal'):
QtCore.Signal = QtCore.pyqtSignal
File added
# -*- coding: utf-8 -*-
from PyQt4 import QtCore
from Qt import QtCore
from ptime import time
__all__ = ['SignalProxy']
class SignalProxy(QtCore.QObject):
"""Object which collects rapid-fire signals and condenses them
into a single signal. Used, for example, to prevent a SpinBox
from generating multiple signals when the mouse wheel is rolled
over it."""
over it.
Emits sigDelayed after input signals have stopped for a certain period of time.
"""
sigDelayed = QtCore.Signal(object)
def __init__(self, source, signal, delay=0.3):
def __init__(self, signal, delay=0.3, slot=None):
"""Initialization arguments:
source - Any QObject that will emit signal, or None if signal is new style
signal - Output of QtCore.SIGNAL(...), or obj.signal for new style
delay - Time (in seconds) to wait for signals to stop before emitting (default 0.3s)"""
signal - a bound Signal or pyqtSignal instance
delay - Time (in seconds) to wait for signals to stop before emitting (default 0.3s)
slot - Optional function to connect sigDelayed to.
"""
QtCore.QObject.__init__(self)
if source is None:
signal.connect(self.signalReceived)
self.signal = QtCore.SIGNAL('signal')
else:
source.connect(source, signal, self.signalReceived)
self.signal = signal
signal.connect(self.signalReceived)
self.signal = signal
self.delay = delay
self.args = None
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.flush)
self.block = False
self.slot = slot
if slot is not None:
self.sigDelayed.connect(slot)
def setDelay(self, delay):
self.delay = delay
......@@ -42,28 +49,39 @@ class SignalProxy(QtCore.QObject):
"""If there is a signal queued up, send it now."""
if self.args is None or self.block:
return False
self.emit(self.signal, *self.args)
#self.emit(self.signal, *self.args)
self.sigDelayed.emit(self.args)
self.args = None
self.timer.stop()
return True
def disconnect(self):
self.block = True
try:
self.signal.disconnect(self.signalReceived)
except:
pass
try:
self.sigDelayed.disconnect(self.slot)
except:
pass
def proxyConnect(source, signal, slot, delay=0.3):
"""Connect a signal to a slot with delay. Returns the SignalProxy
object that was created. Be sure to store this object so it is not
garbage-collected immediately."""
sp = SignalProxy(source, signal, delay)
if source is None:
sp.connect(sp, QtCore.SIGNAL('signal'), slot)
else:
sp.connect(sp, signal, slot)
return sp
#def proxyConnect(source, signal, slot, delay=0.3):
#"""Connect a signal to a slot with delay. Returns the SignalProxy
#object that was created. Be sure to store this object so it is not
#garbage-collected immediately."""
#sp = SignalProxy(source, signal, delay)
#if source is None:
#sp.connect(sp, QtCore.SIGNAL('signal'), slot)
#else:
#sp.connect(sp, signal, slot)
#return sp
if __name__ == '__main__':
from PyQt4 import QtGui
from Qt import QtGui
app = QtGui.QApplication([])
win = QtGui.QMainWindow()
spin = QtGui.QSpinBox()
......@@ -71,8 +89,12 @@ if __name__ == '__main__':
win.show()
def fn(*args):
print "Got signal:", args
print "Raw signal:", args
def fn2(*args):
print "Delayed signal:", args
proxy = proxyConnect(spin, QtCore.SIGNAL('valueChanged(int)'), fn)
spin.valueChanged.connect(fn)
#proxy = proxyConnect(spin, QtCore.SIGNAL('valueChanged(int)'), fn)
proxy = SignalProxy(spin.valueChanged, delay=0.5, slot=fn2)
\ No newline at end of file
File added
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
from Qt import QtCore, QtGui
from Point import Point
import numpy as np
......@@ -108,8 +108,8 @@ class Transform(QtGui.QTransform):
def saveState(self):
p = self._state['pos']
s = self._state['scale']
if s[0] == 0:
raise Exception('Invalid scale')
#if s[0] == 0:
#raise Exception('Invalid scale: %s' % str(s))
return {'pos': (p[0], p[1]), 'scale': (s[0], s[1]), 'angle': self._state['angle']}
def restoreState(self, state):
......
File added
# -*- coding: utf-8 -*-
"""
WidgetGroup.py - WidgetGroup class for easily managing lots of Qt widgets
Copyright 2010 Luke Campagnola
Distributed under MIT/X11 license. See license.txt for more infomation.
This class addresses the problem of having to save and restore the state
of a large group of widgets.
"""
from Qt import QtCore, QtGui
import weakref, inspect
__all__ = ['WidgetGroup']
def splitterState(w):
s = str(w.saveState().toPercentEncoding())
return s
def restoreSplitter(w, s):
if type(s) is list:
w.setSizes(s)
elif type(s) is str:
w.restoreState(QtCore.QByteArray.fromPercentEncoding(s))
else:
print "Can't configure QSplitter using object of type", type(s)
if w.count() > 0: ## make sure at least one item is not collapsed
for i in w.sizes():
if i > 0:
return
w.setSizes([50] * w.count())
def comboState(w):
ind = w.currentIndex()
data = w.itemData(ind)
#if not data.isValid():
if data is not None:
try:
if not data.isValid():
data = None
else:
data = data.toInt()[0]
except AttributeError:
pass
if data is None:
return unicode(w.itemText(ind))
else:
return data
def setComboState(w, v):
if type(v) is int:
#ind = w.findData(QtCore.QVariant(v))
ind = w.findData(v)
if ind > -1:
w.setCurrentIndex(ind)
return
w.setCurrentIndex(w.findText(str(v)))
class WidgetGroup(QtCore.QObject):
"""This class takes a list of widgets and keeps an internal record of their state which is always up to date. Allows reading and writing from groups of widgets simultaneously."""
## List of widget types which can be handled by WidgetGroup.
## The value for each type is a tuple (change signal function, get function, set function, [auto-add children])
## The change signal function that takes an object and returns a signal that is emitted any time the state of the widget changes, not just
## when it is changed by user interaction. (for example, 'clicked' is not a valid signal here)
## If the change signal is None, the value of the widget is not cached.
## Custom widgets not in this list can be made to work with WidgetGroup by giving them a 'widgetGroupInterface' method
## which returns the tuple.
classes = {
QtGui.QSpinBox:
(lambda w: w.valueChanged,
QtGui.QSpinBox.value,
QtGui.QSpinBox.setValue),
QtGui.QDoubleSpinBox:
(lambda w: w.valueChanged,
QtGui.QDoubleSpinBox.value,
QtGui.QDoubleSpinBox.setValue),
QtGui.QSplitter:
(None,
splitterState,
restoreSplitter,
True),
QtGui.QCheckBox:
(lambda w: w.stateChanged,
QtGui.QCheckBox.isChecked,
QtGui.QCheckBox.setChecked),
QtGui.QComboBox:
(lambda w: w.currentIndexChanged,
comboState,
setComboState),
QtGui.QGroupBox:
(lambda w: w.toggled,
QtGui.QGroupBox.isChecked,
QtGui.QGroupBox.setChecked,
True),
QtGui.QLineEdit:
(lambda w: w.editingFinished,
lambda w: str(w.text()),
QtGui.QLineEdit.setText),
QtGui.QRadioButton:
(lambda w: w.toggled,
QtGui.QRadioButton.isChecked,
QtGui.QRadioButton.setChecked),
QtGui.QSlider:
(lambda w: w.valueChanged,
QtGui.QSlider.value,
QtGui.QSlider.setValue),
}
sigChanged = QtCore.Signal(str, object)
def __init__(self, widgetList=None):
"""Initialize WidgetGroup, adding specified widgets into this group.
widgetList can be:
- a list of widget specifications (widget, [name], [scale])
- a dict of name: widget pairs
- any QObject, and all compatible child widgets will be added recursively.
The 'scale' parameter for each widget allows QSpinBox to display a different value than the value recorded
in the group state (for example, the program may set a spin box value to 100e-6 and have it displayed as 100 to the user)
"""
QtCore.QObject.__init__(self)
self.widgetList = weakref.WeakKeyDictionary() # Make sure widgets don't stick around just because they are listed here
self.scales = weakref.WeakKeyDictionary()
self.cache = {} ## name:value pairs
self.uncachedWidgets = weakref.WeakKeyDictionary()
if isinstance(widgetList, QtCore.QObject):
self.autoAdd(widgetList)
elif isinstance(widgetList, list):
for w in widgetList:
self.addWidget(*w)
elif isinstance(widgetList, dict):
for name, w in widgetList.iteritems():
self.addWidget(w, name)
elif widgetList is None:
return
else:
raise Exception("Wrong argument type %s" % type(widgetList))
def addWidget(self, w, name=None, scale=None):
if not self.acceptsType(w):
raise Exception("Widget type %s not supported by WidgetGroup" % type(w))
if name is None: