Example #1
0
class LinearPoti(PluginBase):
    qtcb_position = pyqtSignal(int)

    def __init__(self, ipcon, uid):
        PluginBase.__init__(self, ipcon, uid)

        self.lp = bricklet_linear_poti.LinearPoti(self.uid)
        self.ipcon.add_device(self.lp)
        self.version = ".".join(map(str, self.lp.get_version()[1]))

        self.qtcb_position.connect(self.cb_position)
        self.lp.register_callback(self.lp.CALLBACK_POSITION, self.qtcb_position.emit)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)

        self.position_label = PositionLabel("Position: ")

        self.current_value = 0
        plot_list = [["", Qt.red, self.get_current_value]]
        self.plot_widget = PlotWidget("Position", plot_list)

        layout_h = QHBoxLayout()
        layout_h.addStretch()
        layout_h.addWidget(self.position_label)
        layout_h.addWidget(self.slider)
        layout_h.addStretch()

        layout = QVBoxLayout(self)
        layout.addLayout(layout_h)
        layout.addWidget(self.plot_widget)

    def start(self):
        try:
            self.cb_position(self.lp.get_position())
            self.lp.set_position_callback_period(20)
        except ip_connection.Error:
            return

        self.plot_widget.stop = False

    def stop(self):
        try:
            self.lp.set_position_callback_period(0)
        except ip_connection.Error:
            pass

        self.plot_widget.stop = True

    @staticmethod
    def has_name(name):
        return "Linear Poti Bricklet" in name

    def get_current_value(self):
        return self.current_value

    def cb_position(self, position):
        self.current_value = position
        self.slider.setValue(position)
        self.position_label.setText(str(position))
class SensitivitySlider(QWidget):
	def __init__(self, obj = None, parent = None):
		QWidget.__init__(self, parent)

		if obj is None : return

		self.layout = QVBoxLayout()

		self.sensitivityLabel = QLabel()
		self.layout.addWidget(self.sensitivityLabel)
		self.sensitivitySlider = QSlider()
		self.sensitivitySlider.setRange(0, 200)
		self.sensitivitySlider.setSingleStep(1)
		self.sensitivitySlider.setOrientation(Qt.Horizontal)
		self.sensitivitySlider.valueChanged[int].connect(self.sensitivityDisplay)
		self.layout.addWidget(self.sensitivitySlider)

		self.setLayout(self.layout)
		if obj.config().hasKey("Sensitivity") :
			data_ = obj.config().readEntry("Sensitivity")
			value, state = data_.toInt()
			if not state : value = 100
		else : value = 100
		self.sensitivitySlider.setValue(value)

	def sensitivityDisplay(self, i = 100):
		if i<100 :
			s = 2 + int(float(100-i)/33)
			self.sensitivityLabel.setText('<b><u>Sensitivity of sliders</u>: 1/%s</b>' % s)
		else :
			s = 1 + int(float(i-100)/25)
			self.sensitivityLabel.setText('<b><u>Sensitivity of sliders</u>: %i</b>' % s)
Example #3
0
    def add_parameter(self, name, parameter_data, parameter_change):
        layout = self.frm_parameters.layout()
        qtitle = QLabel(parameter_data[3])
        qslider = QSlider(Qt.Horizontal)
        qmin = QLabel(str(parameter_data[0]))
        qmax = QLabel(str(parameter_data[1]))
        qvalue = QLabel(str(parameter_data[2]))
        qslider.setRange(parameter_data[0], parameter_data[1])
        qslider.setValue(parameter_data[2])
        qtitle.setAlignment(Qt.AlignHCenter)
        qvalue.setAlignment(Qt.AlignHCenter)
        pos = layout.rowCount()
        layout.addWidget(qtitle, pos, 0, 1, 3)
        layout.addWidget(qmin, pos + 1, 0, 1, 1)
        layout.addWidget(qslider, pos + 1, 1, 1, 1)
        layout.addWidget(qmax, pos + 1, 2, 1, 1)
        layout.addWidget(qvalue, pos + 2, 0, 1, 3)

        def value_changed(value):
            v = parameter_change(name, value)
            qvalue.setNum(v)

        qslider.valueChanged.connect(value_changed)
        qslider.setTracking(True)

        self.parameters[name] = qslider
class IntelligentSlider(QWidget):
    ''' A slider that adds a 'name' attribute and calls a callback
    with 'name' as an argument to the registerd callback.

    This allows you to create large groups of sliders in a loop,
    but still keep track of the individual events

    It also prints a label below the slider.

    The range of the slider is hardcoded from zero - 1000,
    but it supports a conversion factor so you can scale the results'''

    def __init__(self, name, a, b, callback):
        QWidget.__init__(self)
        self.name = name
        self.callback = callback
        self.a = a
        self.b = b
        self.manually_triggered = False

        self.slider = QSlider()
        self.slider.setRange(0, 1000)
        self.slider.setValue(500)
        self.slider.valueChanged.connect(self.slider_changed)

        self.name_label = QLabel()
        self.name_label.setText(self.name)
        self.name_label.setAlignment(QtCore.Qt.AlignCenter)

        self.value_label = QLabel()
        self.value_label.setText('%2.2f' % (self.slider.value() * self.a
                                             + self.b))
        self.value_label.setAlignment(QtCore.Qt.AlignCenter)

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.name_label, 0, 0)
        self.layout.addWidget(self.slider, 1, 0, QtCore.Qt.AlignHCenter)
        self.layout.addWidget(self.value_label, 2, 0)

    # bind this to the valueChanged signal of the slider
    def slider_changed(self, val):
        val = self.val()
        self.value_label.setText(str(val)[:4])

        if not self.manually_triggered:
            self.callback(self.name, val)

    def set_conv_fac(self, a, b):
        self.a = a
        self.b = b

    def set_value(self, val):
        self.manually_triggered = True
        self.slider.setValue(int((val - self.b) / self.a))
        self.value_label.setText('%2.2f' % val)
        self.manually_triggered = False

    def val(self):
        return self.slider.value() * self.a + self.b
Example #5
0
class IntelligentSlider(QWidget):
    ''' A slider that adds a 'name' attribute and calls a callback
    with 'name' as an argument to the registerd callback.

    This allows you to create large groups of sliders in a loop,
    but still keep track of the individual events

    It also prints a label below the slider.

    The range of the slider is hardcoded from zero - 1000,
    but it supports a conversion factor so you can scale the results'''

    def __init__(self, name, a, b, callback):
        QWidget.__init__(self)
        self.name = name
        self.callback = callback
        self.a = a
        self.b = b
        self.manually_triggered = False

        self.slider = QSlider()
        self.slider.setRange(0, 1000)
        self.slider.setValue(500)
        self.slider.valueChanged.connect(self.slider_changed)

        self.name_label = QLabel()
        self.name_label.setText(self.name)
        self.name_label.setAlignment(QtCore.Qt.AlignCenter)

        self.value_label = QLabel()
        self.value_label.setText('%2.2f' % (self.slider.value() * self.a + self.b))
        self.value_label.setAlignment(QtCore.Qt.AlignCenter)

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.name_label, 0, 0)
        self.layout.addWidget(self.slider, 1, 0, QtCore.Qt.AlignHCenter)
        self.layout.addWidget(self.value_label, 2, 0)

    # bind this to the valueChanged signal of the slider
    def slider_changed(self, val):
        val = self.val()
        self.value_label.setText(str(val)[:4])

        if not self.manually_triggered:
            self.callback(self.name, val)

    def set_conv_fac(self, a, b):
        self.a = a
        self.b = b

    def set_value(self, val):
        self.manually_triggered = True
        self.slider.setValue(int((val - self.b) / self.a))
        self.value_label.setText('%2.2f' % val)
        self.manually_triggered = False

    def val(self):
        return self.slider.value() * self.a + self.b
Example #6
0
class LinearPoti(PluginBase):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletLinearPoti, *args)
        
        self.lp = self.device

        self.cbe_position = CallbackEmulator(self.lp.get_position,
                                             self.cb_position,
                                             self.increase_error_count)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        
        self.position_label = PositionLabel('Position: ')
        
        self.current_value = None

        plot_list = [['', Qt.red, self.get_current_value]]
        self.plot_widget = PlotWidget('Position', plot_list)
        
        layout_h = QHBoxLayout()
        layout_h.addStretch()
        layout_h.addWidget(self.position_label)
        layout_h.addWidget(self.slider)
        layout_h.addStretch()

        layout = QVBoxLayout(self)
        layout.addLayout(layout_h)
        layout.addWidget(self.plot_widget)
        
    def start(self):
        async_call(self.lp.get_position, None, self.cb_position, self.increase_error_count)
        self.cbe_position.set_period(25)
        
        self.plot_widget.stop = False
        
    def stop(self):
        self.cbe_position.set_period(0)
        
        self.plot_widget.stop = True

    def destroy(self):
        pass

    def get_url_part(self):
        return 'linear_poti'

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletLinearPoti.DEVICE_IDENTIFIER

    def get_current_value(self):
        return self.current_value

    def cb_position(self, position):
        self.current_value = position
        self.slider.setValue(position)
        self.position_label.setText(str(position))
Example #7
0
class LinearPoti(PluginBase):
    qtcb_position = pyqtSignal(int)
    
    def __init__(self, ipcon, uid, version):
        PluginBase.__init__(self, ipcon, uid, 'Linear Poti Bricklet', version)
        
        self.lp = BrickletLinearPoti(uid, ipcon)
        
        self.qtcb_position.connect(self.cb_position)
        self.lp.register_callback(self.lp.CALLBACK_POSITION,
                                  self.qtcb_position.emit) 
        
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        
        self.position_label = PositionLabel('Position: ')
        
        self.current_value = None

        plot_list = [['', Qt.red, self.get_current_value]]
        self.plot_widget = PlotWidget('Position', plot_list)
        
        layout_h = QHBoxLayout()
        layout_h.addStretch()
        layout_h.addWidget(self.position_label)
        layout_h.addWidget(self.slider)
        layout_h.addStretch()

        layout = QVBoxLayout(self)
        layout.addLayout(layout_h)
        layout.addWidget(self.plot_widget)
        
    def start(self):
        async_call(self.lp.get_position, None, self.cb_position, self.increase_error_count)
        
        async_call(self.lp.set_position_callback_period, 20, None, self.increase_error_count)
        
        self.plot_widget.stop = False
        
    def stop(self):
        async_call(self.lp.set_position_callback_period, 0, None, self.increase_error_count)
        
        self.plot_widget.stop = True

    def get_url_part(self):
        return 'linear_poti'

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletLinearPoti.DEVICE_IDENTIFIER

    def get_current_value(self):
        return self.current_value

    def cb_position(self, position):
        self.current_value = position
        self.slider.setValue(position)
        self.position_label.setText(str(position))
Example #8
0
class MusicView(preferences.Group):
    def __init__(self, page):
        super(MusicView, self).__init__(page)
        
        layout = QGridLayout()
        self.setLayout(layout)

        self.magnifierSizeLabel = QLabel()
        self.magnifierSizeSlider = QSlider(Qt.Horizontal, valueChanged=self.changed)
        self.magnifierSizeSlider.setSingleStep(50)
        self.magnifierSizeSlider.setRange(*popplerview.MagnifierSettings.sizeRange)
        self.magnifierSizeSpinBox = QSpinBox()
        self.magnifierSizeSpinBox.setRange(*popplerview.MagnifierSettings.sizeRange)
        self.magnifierSizeSpinBox.valueChanged.connect(self.magnifierSizeSlider.setValue)
        self.magnifierSizeSlider.valueChanged.connect(self.magnifierSizeSpinBox.setValue)
        layout.addWidget(self.magnifierSizeLabel, 0, 0)
        layout.addWidget(self.magnifierSizeSlider, 0, 1)
        layout.addWidget(self.magnifierSizeSpinBox, 0, 2)
        
        self.magnifierScaleLabel = QLabel()
        self.magnifierScaleSlider = QSlider(Qt.Horizontal, valueChanged=self.changed)
        self.magnifierScaleSlider.setSingleStep(50)
        self.magnifierScaleSlider.setRange(*popplerview.MagnifierSettings.scaleRange)
        self.magnifierScaleSpinBox = QSpinBox()
        self.magnifierScaleSpinBox.setRange(*popplerview.MagnifierSettings.scaleRange)
        self.magnifierScaleSpinBox.valueChanged.connect(self.magnifierScaleSlider.setValue)
        self.magnifierScaleSlider.valueChanged.connect(self.magnifierScaleSpinBox.setValue)
        layout.addWidget(self.magnifierScaleLabel, 1, 0)
        layout.addWidget(self.magnifierScaleSlider, 1, 1)
        layout.addWidget(self.magnifierScaleSpinBox, 1, 2)
        
        app.translateUI(self)
        
    def translateUI(self):
        self.setTitle(_("Music View"))
        self.magnifierSizeLabel.setText(_("Magnifier Size:"))
        self.magnifierSizeLabel.setToolTip(_(
            "Size of the magnifier glass (Ctrl+Click in the Music View)."))
        # L10N: as in "400 pixels", appended after number in spinbox, note the leading space
        self.magnifierSizeSpinBox.setSuffix(_(" pixels"))
        self.magnifierScaleLabel.setText(_("Magnifier Scale:"))
        self.magnifierScaleLabel.setToolTip(_(
            "Magnification of the magnifier."))
        self.magnifierScaleSpinBox.setSuffix(_("percent unit sign", "%"))
            
    def loadSettings(self):
        s = popplerview.MagnifierSettings.load()
        self.magnifierSizeSlider.setValue(s.size)
        self.magnifierScaleSlider.setValue(s.scale)
    
    def saveSettings(self):
        s = popplerview.MagnifierSettings()
        s.size = self.magnifierSizeSlider.value()
        s.scale = self.magnifierScaleSlider.value()
        s.save()
Example #9
0
class SpinSlider(QWidget):
	"Boite de spin + curseur avec sauvegarde de la dernière valeur sélectionnée"
	def __init__(self, debut, fin, defaut, optionConfig=None, parent=None):
		QWidget.__init__(self)

		self.spin = QSpinBox()
		self.slider = QSlider(Qt.Horizontal)
		self.spin.setRange(debut, fin)
		self.slider.setRange(debut, fin)

		valeur = None
		if optionConfig:
			self.config = parent.config
			self.idSection = parent.idSection
			self.optionConfig = optionConfig
			try :
				valeur = self.config.get(self.idSection, self.optionConfig)
			except:
				valeur = defaut
				self.config.set(self.idSection, self.optionConfig, valeur)
		erreur = False
		if valeur:
			try: valeur = int(valeur)
			except ValueError: erreur = True
		if not erreur and debut <= valeur <= fin:
			self.spin.setValue(valeur)
			self.slider.setValue(valeur)
		else:
			self.spin.setValue(defaut)
			self.slider.setValue(defaut)
		if optionConfig: self.connect(self.spin, SIGNAL("valueChanged(int)"), self.sauveConfig)
		self.connect(self.spin, SIGNAL("valueChanged(int)"), self.slider,
						SLOT("setValue(int)"))
		self.connect(self.slider, SIGNAL("valueChanged(int)"), self.spin,
						SLOT("setValue(int)"))
		self.connect(self.spin, SIGNAL("valueChanged(int)"), self.changed)
		hbox = QHBoxLayout(self)
		hbox.addWidget(self.spin)
		hbox.addWidget(self.slider)
		hbox.setMargin(0) # pour un meilleur alignement dans un grid

	def changed(self, i):
		self.emit(SIGNAL("valueChanged(int)"), i)

	def sauveConfig(self, i):
		self.config.set(self.idSection, self.optionConfig, str(i))

	def value(self):
		return self.spin.value()

	def setValue(self, i):
		self.spin.setValue(i)
		self.slider.setValue(i)
Example #10
0
def metronome():
    import os, sys, time
    from PyQt4.QtCore import SIGNAL
    from PyQt4.QtGui import QApplication, QPushButton, QSlider, QWidget
    from PyQt4.QtGui import QHBoxLayout
    import scsynth
    import synths
    
    app = QApplication(sys.argv)
    server = scsynth.server.start(verbose=True)
    #server = scsynth.server.connect()
    engine = Engine(server, app)
    server.sendMsg('/dumpOSC', 1)
    engine.tempoclock.set_tempo(120)

    SYNTHDEF_PATH = os.path.join(os.path.expanduser('~'),
                                 '.pksampler', 'synthdefs')
    SYNTHDEFS = ('JASStereoSamplePlayer.scsyndef',
                 'JASSine.scsyndef',
                 )
    for fname in SYNTHDEFS:
        engine.server.sendMsg('/d_load', os.path.join(SYNTHDEF_PATH, fname))
    
    CLICK = '/Users/patrick/.pksampler/clicks/click_1.wav'
    engine.loader.load(CLICK)
    time.sleep(.1)

    notes = [scsynth.Note(i, i+16, 69) for i in (0, )]
    pattern = scsynth.Pattern(notes)
    pattern.beats = 1
    stream = engine.register(synths.Sine(), pattern)
    stream.loop(True)
    engine.start()

    widget = QWidget()
    Layout = QHBoxLayout(widget)
    widget.resize(100, 250)
    widget.show()
    
    def set_tempo(value):
        engine.tempoclock.set_tempo(value)
    slider = QSlider(widget)
    slider.setRange(100, 180)
    slider.setValue(140)
    QObject.connect(slider, SIGNAL('valueChanged(int)'), set_tempo)
    Layout.addWidget(slider)

    button = QPushButton('quit', widget)
    QObject.connect(button, SIGNAL('clicked()'), app.quit)
    Layout.addWidget(button)
    
    app.exec_()
    engine.stop()
Example #11
0
class ControlParameter(object):

    def __init__(self, name, bounds, default_val):
        self.name = name
        self.min_val,self.max_val = bounds
        self.default_val = default_val
        self.current_val = default_val

    def get_slider_index(self, val):
        return int( 100*(val - self.min_val) / (self.max_val - self.min_val) )

    def get_slider_value(self, index):
        frac = index / 100.0
        return (self.max_val - self.min_val)*frac + self.min_val

    def set_slider_value(self, val):
        index = self.get_slider_index(val)
        self.slider.setSliderPosition(index)

    def slider_changed(self, index):
        self.current_val = self.get_slider_value(index)
        #print 'slider changed %s: index=%d, val=%0.6f' % (self.name, index, self.current_val)
        self.update()

    def update(self):
        self.pedit.setText('%0.6f' % self.current_val)
        self.set_slider_value(self.current_val)

    def create_widget(self, parent=None):
        mlayout = QVBoxLayout(parent)

        hlayout = QHBoxLayout()
        plabel = QLabel()
        plabel.setText('%s: ' % self.name)
        hlayout.addWidget(plabel)

        self.pedit = QLineEdit()
        self.pedit.setText('%0.6f' % self.default_val)
        hlayout.addWidget(self.pedit)
        mlayout.addLayout(hlayout)

        spos = self.get_slider_index(self.default_val)
        self.slider = QSlider()
        self.slider.setRange(0, 100)
        self.slider.setSliderPosition(spos)
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.valueChanged.connect(self.slider_changed)
        mlayout.addWidget(self.slider)

        return mlayout
Example #12
0
class LinearPoti(PluginBase):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletLinearPoti, *args)

        self.lp = self.device

        self.cbe_position = CallbackEmulator(self.lp.get_position,
                                             self.cb_position,
                                             self.increase_error_count)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        self.slider.setMinimumWidth(200)

        self.current_position = None

        plots = [('Position', Qt.red, lambda: self.current_position, str)]
        self.plot_widget = PlotWidget('Position',
                                      plots,
                                      extra_key_widgets=[self.slider],
                                      curve_motion_granularity=40,
                                      update_interval=0.025)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)

    def start(self):
        async_call(self.lp.get_position, None, self.cb_position,
                   self.increase_error_count)
        self.cbe_position.set_period(25)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_position.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletLinearPoti.DEVICE_IDENTIFIER

    def cb_position(self, position):
        self.current_position = position
        self.slider.setValue(position)
Example #13
0
class LinearPoti(PluginBase):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletLinearPoti, *args)

        self.lp = self.device

        self.cbe_position = CallbackEmulator(self.lp.get_position,
                                             self.cb_position,
                                             self.increase_error_count)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        self.slider.setMinimumWidth(200)

        self.current_position = None

        plots = [('Position', Qt.red, lambda: self.current_position, str)]
        self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider],
                                      curve_motion_granularity=40, update_interval=0.025)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)

    def start(self):
        async_call(self.lp.get_position, None, self.cb_position, self.increase_error_count)
        self.cbe_position.set_period(25)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_position.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    def get_url_part(self):
        return 'linear_poti'

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletLinearPoti.DEVICE_IDENTIFIER

    def cb_position(self, position):
        self.current_position = position
        self.slider.setValue(position)
Example #14
0
class MainWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
        self.d_plot = Plot(self)
        self.setCentralWidget(self.d_plot)

        self.toolBar = QToolBar(self)
        self.btnPrint = QToolButton(self.toolBar)
        self.btnPrint.setText("Print")
        self.btnPrint.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.toolBar.addWidget(self.btnPrint)
        #self.btnPrint.clicked.connect(self.d_plot.printPlot() )

        self.toolBar.addSeparator()

        self.toolBar.addWidget(QLabel("Color Map "))
        self.mapBox = QComboBox(self.toolBar)
        self.mapBox.addItem("RGB")
        self.mapBox.addItem("Indexed Colors")
        self.mapBox.addItem("Hue")
        self.mapBox.addItem("Alpha")
        self.mapBox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.toolBar.addWidget(self.mapBox)
        self.mapBox.currentIndexChanged['int'].connect(self.d_plot.setColorMap)
        self.toolBar.addWidget(QLabel(" Opacity "))
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 255)
        self.slider.setValue(255)
        self.slider.valueChanged['int'].connect(self.d_plot.setAlpha)
        self.toolBar.addWidget(self.slider)
        self.toolBar.addWidget(QLabel("   "))
        self.btnSpectrogram = QCheckBox("Spectrogram", self.toolBar)
        self.toolBar.addWidget(self.btnSpectrogram)
        self.btnSpectrogram.toggled['bool'].connect(
            self.d_plot.showSpectrogram)

        self.btnContour = QCheckBox("Contour", self.toolBar)
        self.toolBar.addWidget(self.btnContour)
        #self.btnContour.toggled['bool'](self.d_plot.showContour )

        self.addToolBar(self.toolBar)

        self.btnSpectrogram.setChecked(True)
        self.btnContour.setChecked(False)
Example #15
0
class QCustomSlider(QWidget):
    def __init__(self, sliderOrientation=None):
        super(QCustomSlider, self).__init__()
        self._slider = QSlider(sliderOrientation)

        self.setLayout(QVBoxLayout())

        self._labelTicksWidget = QWidget(self)
        self._labelTicksWidget.setLayout(QHBoxLayout())
        self._labelTicksWidget.layout().setContentsMargins(0, 0, 0, 0)

        self.layout().addWidget(self._slider)
        self.layout().addWidget(self._labelTicksWidget)

    def setTickLabels(self, listWithLabels):
        lengthOfList = len(listWithLabels)
        for index, label in enumerate(listWithLabels):
            label = QLabel(str(label))
            label.setContentsMargins(0, 0, 0, 0)
            if index > lengthOfList/3:
                label.setAlignment(QtCore.Qt.AlignCenter)
            if index > 2*lengthOfList/3:
                label.setAlignment(QtCore.Qt.AlignRight)
            self._labelTicksWidget.layout().addWidget(label)

    def setRange(self, mini, maxi):
        self._slider.setRange(mini, maxi)

    def setPageStep(self, value):
        self._slider.setPageStep(value)

    def setTickInterval(self, value):
        self._slider.setTickInterval(value)

    def setTickPosition(self, position):
        self._slider.setTickPosition(position)

    def setValue(self, value):
        self._slider.setValue(value)

    def onValueChangedCall(self, function):
        self._slider.valueChanged.connect(function)
Example #16
0
def create_slider(slider_type, slider_range,  slider_default):
    # Horizontal Slider
    if slider_type == SLDR_TYPE_HSlider:
        slider = QSlider(Qt.Horizontal)
    # Vertical Slider
    elif slider_type == SLDR_TYPE_VSlider:
        slider = QSlider(Qt.Vertical)
    # Dial
    elif slider_type == SLDR_TYPE_Dial:
        slider = QDial()
    # Horizontal Scrollbar
    elif slider_type == SLDR_TYPE_HScrollbar:
        slider = QScrollBar(Qt.Horizontal)
    # Vertical Scrollbar
    elif slider_type == SLDR_TYPE_VScrollbar:
        slider = QScrollbar(Qt.Vertical)
    else:
        raise TypeError("Invalid slider type")

    slider.setRange(slider_range[0], slider_range[1])
    slider.setValue(slider_default)

    return slider
Example #17
0
class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.main_layout = QGridLayout()

        self.steps_spin = QSpinBox()
        self.steps_spin.setRange(1, 12)
        self.steps_label = QLabel("steps:")
        self.steps_slider = QSlider(1)  #horizontal
        self.steps_slider.setRange(1, 12)

        self.smooth_spin = QSpinBox()
        self.smooth_spin.setRange(1, 100)
        self.smooth_label = QLabel("smoothness:")
        self.smooth_slider = QSlider(1)  #horizontal
        self.smooth_slider.setRange(0, 100)
        self.smooth_slider.setSingleStep(1)

        self.dampen_spin = QSpinBox()
        self.dampen_spin.setRange(1, 100)
        self.dampen_label = QLabel("dampening:")
        self.dampen_slider = QSlider(1)  #horizontal
        self.dampen_slider.setRange(0, 100)
        self.dampen_slider.setSingleStep(1)

        self.update_button = QPushButton("update")

        self.view = QGraphicsView()

        self.main_layout.addWidget(self.steps_spin, 0, 0)
        self.main_layout.addWidget(self.steps_label, 0, 1)
        self.main_layout.addWidget(self.steps_slider, 0, 2)

        self.main_layout.addWidget(self.smooth_spin, 1, 0)
        self.main_layout.addWidget(self.smooth_label, 1, 1)
        self.main_layout.addWidget(self.smooth_slider, 1, 2)

        self.main_layout.addWidget(self.dampen_spin, 2, 0)
        self.main_layout.addWidget(self.dampen_label, 2, 1)
        self.main_layout.addWidget(self.dampen_slider, 2, 2)

        self.main_layout.addWidget(self.update_button, 3, 0, 1, 3)

        self.main_layout.addWidget(
            self.view,
            4,
            0,
            1,  #rowSpan
            3)  #columnSpan

        self.setLayout(self.main_layout)
Example #18
0
class MusicView(preferences.Group):
    def __init__(self, page):
        super(MusicView, self).__init__(page)
        
        layout = QGridLayout()
        self.setLayout(layout)
        
        self.newerFilesOnly = QCheckBox(toggled=self.changed)
        layout.addWidget(self.newerFilesOnly, 0, 0, 1, 3)
        
        self.magnifierSizeLabel = QLabel()
        self.magnifierSizeSlider = QSlider(Qt.Horizontal, valueChanged=self.changed)
        self.magnifierSizeSlider.setSingleStep(50)
        self.magnifierSizeSlider.setRange(*popplerview.MagnifierSettings.sizeRange)
        self.magnifierSizeSpinBox = QSpinBox()
        self.magnifierSizeSpinBox.setRange(*popplerview.MagnifierSettings.sizeRange)
        self.magnifierSizeSpinBox.valueChanged.connect(self.magnifierSizeSlider.setValue)
        self.magnifierSizeSlider.valueChanged.connect(self.magnifierSizeSpinBox.setValue)
        layout.addWidget(self.magnifierSizeLabel, 1, 0)
        layout.addWidget(self.magnifierSizeSlider, 1, 1)
        layout.addWidget(self.magnifierSizeSpinBox, 1, 2)
        
        self.magnifierScaleLabel = QLabel()
        self.magnifierScaleSlider = QSlider(Qt.Horizontal, valueChanged=self.changed)
        self.magnifierScaleSlider.setSingleStep(50)
        self.magnifierScaleSlider.setRange(*popplerview.MagnifierSettings.scaleRange)
        self.magnifierScaleSpinBox = QSpinBox()
        self.magnifierScaleSpinBox.setRange(*popplerview.MagnifierSettings.scaleRange)
        self.magnifierScaleSpinBox.valueChanged.connect(self.magnifierScaleSlider.setValue)
        self.magnifierScaleSlider.valueChanged.connect(self.magnifierScaleSpinBox.setValue)
        layout.addWidget(self.magnifierScaleLabel, 2, 0)
        layout.addWidget(self.magnifierScaleSlider, 2, 1)
        layout.addWidget(self.magnifierScaleSpinBox, 2, 2)
        
        self.enableKineticScrolling = QCheckBox(toggled=self.changed)
        layout.addWidget(self.enableKineticScrolling)
        self.showScrollbars = QCheckBox(toggled=self.changed)
        layout.addWidget(self.showScrollbars)
        app.translateUI(self)
        
    def translateUI(self):
        self.setTitle(_("Music View"))
        self.newerFilesOnly.setText(_("Only load updated PDF documents"))
        self.newerFilesOnly.setToolTip(_(
            "If checked, Frescobaldi will not open PDF documents that are not\n"
            "up-to-date (i.e. the source file has been modified later)."))
        self.magnifierSizeLabel.setText(_("Magnifier Size:"))
        self.magnifierSizeLabel.setToolTip(_(
            "Size of the magnifier glass (Ctrl+Click in the Music View)."))
        # L10N: as in "400 pixels", appended after number in spinbox, note the leading space
        self.magnifierSizeSpinBox.setSuffix(_(" pixels"))
        self.magnifierScaleLabel.setText(_("Magnifier Scale:"))
        self.magnifierScaleLabel.setToolTip(_(
            "Magnification of the magnifier."))
        self.magnifierScaleSpinBox.setSuffix(_("percent unit sign", "%"))
        # L10N: "Kinetic Scrolling" is a checkbox label, as in "Enable Kinetic Scrolling"
        self.enableKineticScrolling.setText(_("Kinetic Scrolling"))
        self.showScrollbars.setText(_("Show Scrollbars"))
            
    def loadSettings(self):
        s = popplerview.MagnifierSettings.load()
        self.magnifierSizeSlider.setValue(s.size)
        self.magnifierScaleSlider.setValue(s.scale)
        
        s = QSettings()
        s.beginGroup("musicview")
        newerFilesOnly = s.value("newer_files_only", True, bool)
        self.newerFilesOnly.setChecked(newerFilesOnly)
        kineticScrollingActive = s.value("kinetic_scrolling", True, bool)
        self.enableKineticScrolling.setChecked(kineticScrollingActive)
        showScrollbars = s.value("show_scrollbars", True, bool)
        self.showScrollbars.setChecked(showScrollbars)
    
    def saveSettings(self):
        s = popplerview.MagnifierSettings()
        s.size = self.magnifierSizeSlider.value()
        s.scale = self.magnifierScaleSlider.value()
        s.save()

        s = QSettings()
        s.beginGroup("musicview")
        s.setValue("newer_files_only", self.newerFilesOnly.isChecked())
        s.setValue("kinetic_scrolling", self.enableKineticScrolling.isChecked())
        s.setValue("show_scrollbars", self.showScrollbars.isChecked())
Example #19
0
class LogDialog(QDialogWithDpi):
    """LogDialog for the Freeseer project.

    It is the dialog window for the log.
    There is an instance for every FreeseerApp.
    It has a LogHandler which calls LogDialog's
    message() method when a new log message is received.
    The call to message() causes a call to add_entry()
    which adds the information to a new row in the table.
    """
    def __init__(self, parent=None):
        super(LogDialog, self).__init__(parent)

        self.resize(800, 500)

        self.app = QApplication.instance()

        icon = QIcon()
        icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal,
                       QIcon.Off)
        self.setWindowIcon(icon)

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.level = 0
        self.handler = LogHandler()

        self.table_model = QStandardItemModel(0, 5)
        header_names = ["Date", "Level", "Module", "Message", "LevelNo"]
        date_column = header_names.index("Date")
        level_column = header_names.index("Level")
        module_column = header_names.index("Module")
        self.level_num_column = header_names.index("LevelNo")
        self.table_model.setHorizontalHeaderLabels(header_names)

        self.table_view = QTableView()
        self.table_view.setModel(self.table_model)
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.setColumnWidth(date_column,
                                       self.set_width_with_dpi(125))
        self.table_view.setColumnWidth(level_column,
                                       self.set_width_with_dpi(60))
        self.table_view.setColumnWidth(module_column,
                                       self.set_width_with_dpi(250))
        self.table_view.setColumnHidden(self.level_num_column, True)
        self.table_view.setShowGrid(False)
        self.table_view.horizontalHeader().setClickable(False)
        self.table_view.verticalHeader().hide()
        self.table_view.setStyleSheet("""Qtable_view::item {
            border-bottom: 1px solid lightgrey;
            selection-background-color: white;
            selection-color: black;
            }""")

        top_panel = QHBoxLayout()
        self.log_levels = ["Debug", "Info", "Warning", "Error"]
        self.level_colors = ["#3E4C85", "#269629", "#B0AB21", "#B32020"]

        self.levels_label = QLabel("Filter Level: ")
        self.levels_label.setStyleSheet("QLabel { font-weight: bold }")
        self.current_level_label = QLabel(self.log_levels[0])
        self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(
            self.level_colors[0]))
        self.clear_button = QPushButton("Clear Log")
        self.levels_slider = QSlider(Qt.Horizontal)
        self.levels_slider.setStyleSheet("""
        QSlider::handle:horizontal {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #FFFFFF, stop:1 #E3E3E3);
            border: 1px solid #707070;
            width: 10px;
            margin-top: -4px;
            margin-bottom: -4px;
            border-radius: 4px;
        }

        QSlider::handle:horizontal:hover {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #DEDEDE, stop:1 #C9C9C9);
            border: 1px solid #4F4F4F;
            border-radius: 4px;
        }

        QSlider::sub-page:horizontal {
            background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
                stop: 0 #BFBFBF, stop: 1 #9E9E9E);
            background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
                stop: 0 #9E9E9E, stop: 1 #858585);
            border: 1px solid #777;
            height: 10px;
            border-radius: 4px;
        }

        QSlider::add-page:horizontal {
            background: #fff;
            border: 1px solid #707070;
            height: 10px;
            border-radius: 4px;
        }""")
        self.levels_slider.setRange(0, len(self.log_levels) - 1)
        self.levels_slider.setTickPosition(QSlider.TicksBelow)
        self.levels_slider.setTickInterval(1)

        top_panel.addSpacerItem(self.qspacer_item_with_dpi(10, 0))
        top_panel.addWidget(self.levels_label, 3)
        top_panel.addWidget(self.current_level_label, 2)
        top_panel.addWidget(self.levels_slider, 8)
        top_panel.addSpacerItem(self.qspacer_item_with_dpi(25, 0))
        top_panel.addWidget(self.clear_button, 10)

        layout.addLayout(top_panel)
        layout.addWidget(self.table_view)

        self.connect(self.clear_button, SIGNAL('clicked()'),
                     functools.partial(self.table_model.setRowCount, 0))
        self.connect(self.levels_slider, SIGNAL('valueChanged(int)'),
                     self.slider_set_level)

        self.setWindowTitle("Log")
        self.handler.add_listener(self)

    def __del__(self):
        self.handler.remove_listener(self)

    def retranslate(self):
        self.setWindowTitle(self.app.translate("LogDialog", "Log"))
        self.clear_button.setText(self.app.translate("LogDialog", "Clear Log"))
        self.levels_label.setText("{}: ".format(
            self.app.translate("LogDialog", "Filter Level")))

    def message(self, message):
        """Passes the log fields to add_entry()

        It is called by LogHandler when a log message is received"""
        self.add_entry(message["time"], message["level"],
                       message["full_module_name"], message["message"],
                       str(message["levelno"]))

    def add_entry(self, date, level, module, message, levelno):
        """Adds the given fields to a new row in the log table

        It is called by message() when a log message is received"""
        items = [
            QStandardItem(date),
            QStandardItem(level),
            QStandardItem(module),
            QStandardItem(message),
            QStandardItem(levelno)
        ]
        for item in items:
            item.setEditable(False)
        self.table_model.appendRow(items)

    def slider_set_level(self, level):
        self.current_level_label.setText(self.log_levels[level])
        self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(
            self.level_colors[level]))
        self.set_level(level + 1)

    def set_level(self, level):
        """Sets the current level of the LogDialog.

        Level is based on the selection made in the levels_combo_box.
        It hides all messages with a lower level."""
        self.level = level * 10
        for i in range(self.table_model.rowCount()):
            if int(str(self.table_model.item(
                    i, self.level_num_column).text())) < self.level:
                self.table_view.setRowHidden(i, True)
            else:
                self.table_view.setRowHidden(i, False)
Example #20
0
class MyMainWindow(QMainWindow):
    ' Main Window '
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.statusBar().showMessage(__doc__)
        self.setWindowTitle(__doc__)
        self.setMinimumSize(250, 280)
        self.setMaximumSize(300, 300)
        self.resize(250, 290)
        self.setWindowIcon(QIcon.fromTheme("face-monkey"))
        self.setStyleSheet('''QWidget { color: rgba( 0, 255, 255, 255 );
            background-color: #323232; font-family: 'Ubuntu Light';
            font-size: 14px;
            }

            QToolTip {
                border: 1px solid black;
                background-color: #ffa02f;
                background-image: None;
                padding: 1px;
                border-radius: 3px;
                opacity: 100;
            }

            QWidget:item:hover {
                background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #ffa02f,
                    stop: 1 #ca0619
                );
                color: #000000;
            }

            QWidget:item:selected {
                background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #ffa02f,
                    stop: 1 #d7801a
                );
            }

            QWidget:disabled {
                color: #404040;
                background-color: #323232;
            }

            QWidget:focus {
                background-image: None;
                border: 2px solid QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #ffa02f,
                    stop: 1 #d7801a
                );
            }

            QPushButton {
                background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #565656,
                    stop: 0.1 #525252,
                    stop: 0.5 #4e4e4e,
                    stop: 0.9 #4a4a4a,
                    stop: 1 #464646
                );
                border-width: 1px;
                border-color: #1e1e1e;
                border-style: solid;
                border-radius: 6;
                padding: 3px;
                font-size: 12px;
                padding-left: 5px;
                padding-right: 5px;
                background-image: None;
            }

            QPushButton:pressed {
                background-image: None;
                background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #2d2d2d,
                    stop: 0.1 #2b2b2b,
                    stop: 0.5 #292929,
                    stop: 0.9 #282828,
                    stop: 1 #252525
                );
            }

            QComboBox {
                background-image: None;
                selection-background-color: #ffaa00;
                background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #565656,
                    stop: 0.1 #525252,
                    stop: 0.5 #4e4e4e,
                    stop: 0.9 #4a4a4a,
                    stop: 1 #464646
                );
                border-style: solid;
                border: 1px solid #1e1e1e;
                border-radius: 5;
            }

            QComboBox:hover, QPushButton:hover {
                background-image: url(.bg.png);
                border: 2px solid QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #ffa02f,
                    stop: 1 #d7801a
                );
            }

            QComboBox:on {
                padding-top: 3px;
                padding-left: 4px;
                background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #2d2d2d,
                    stop: 0.1 #2b2b2b,
                    stop: 0.5 #292929,
                    stop: 0.9 #282828,
                    stop: 1 #252525
                );
                selection-background-color: #ffaa00;
                background-image: None;
            }

            QComboBox QAbstractItemView {
                background-image: None;
                border: 2px solid darkgray;
                selection-background-color: QLinearGradient(
                    x1: 0, y1: 0,
                    x2: 0, y2: 1,
                    stop: 0 #ffa02f,
                    stop: 1 #d7801a
                );
            }

            QComboBox::drop-down {
                 subcontrol-origin: padding;
                 subcontrol-position: top right;
                 width: 15px;
                 border-left-width: 0px;
                 border-left-color: darkgray;
                 border-left-style: solid;
                 border-top-right-radius: 3px;
                 border-bottom-right-radius: 3px;
                 background-image: None;
             }

            QComboBox::down-arrow { background-image: None; }

            QSlider {
                border-width: 2px;
                border-color: #1e1e1e;
                border-style: solid;
                padding: 3px;
                font-size: 8px;
                padding-left: 5px;
                padding-right: 5px;
                width: 25px;
                border-radius: 5px;
            }

            QSlider::sub-page:vertical {
                background: red;
                border: none;
                width: 25px;
            }

            QSlider::add-page:vertical {
                background: green;
                border: none;
                width: 25px;
            }

            QSlider::handle:vertical {
                background-color: QLinearGradient(spread:pad, x1:0, y1:0, x2:1,
                    y2:0.273, stop:0 rgba(0, 0, 0, 255),
                    stop:1 rgba(150, 255, 255, 255)
                    );
                width: 10px;
                height: 25px;
                border: 1px solid grey;
                text-align: center;
                border-top-left-radius: 2px;
                border-bottom-left-radius: 2px;
                border-top-right-radius: 2px;
                border-bottom-right-radius 2px;
                margin-left: 2px;
                margin-right: 2px;
            }

            QSlider::handle:vertical:hover {
                border: 2px solid #ffaa00;
                margin-left: 2px;
                margin-right: 2px;
            }

            QSlider::sub-page:vertical:disabled {
                background: #bbb;
                border-color: #999;
            }

            QSlider::add-page:vertical:disabled {
                background: #eee;
                border-color: #999;
            }

            QSlider::handle:vertical:disabled {
                background: #eee;
                border: 1px solid #aaa;
                border-radius: 4px;
            } ''')

        self.label1 = QLabel(self)
        self.label1.setText('Use Debug')
        self.label1.setGeometry(QtCore.QRect(25, 25, 125, 25))

        self.slider1 = QSlider(self)
        self.slider1.setGeometry(QtCore.QRect(150, 25, 25, 25))
        self.slider1.setTickInterval(1)
        self.slider1.setCursor(QCursor(QtCore.Qt.OpenHandCursor))
        self.slider1.TickPosition(QSlider.TicksBothSides)
        self.slider1.setRange(0, 1)
        self.slider1.setValue(1)
        self.sli1lbl = QLabel(str(self.slider1.value()), self.slider1)
        self.sli1lbl.move(9, 5)
        self.sli1lbl.setAutoFillBackground(False)
        self.slider1.valueChanged.connect(
            lambda: self.sli1lbl.setText(str(self.slider1.value())))
        self.slider1.sliderPressed.connect(
            lambda: self.slider1.setCursor(QCursor(QtCore.Qt.ClosedHandCursor)))
        self.slider1.sliderReleased.connect(
            lambda: self.slider1.setCursor(QCursor(QtCore.Qt.OpenHandCursor)))

        self.label2 = QLabel(self)
        self.label2.setText('Make Executable')
        self.label2.setGeometry(QtCore.QRect(25, 75, 125, 25))

        self.slider2 = QSlider(self)
        self.slider2.setGeometry(QtCore.QRect(150, 75, 25, 25))
        self.slider2.setTickInterval(1)
        self.slider2.setCursor(QCursor(QtCore.Qt.OpenHandCursor))
        self.slider2.TickPosition(QSlider.TicksBothSides)
        self.slider2.setRange(0, 1)
        self.slider2.setValue(1)
        self.sli2lbl = QLabel(str(self.slider2.value()), self.slider2)
        self.sli2lbl.move(9, 5)
        self.sli2lbl.setAutoFillBackground(False)
        self.slider2.valueChanged.connect(
            lambda: self.sli2lbl.setText(str(self.slider2.value())))
        self.slider2.sliderPressed.connect(
            lambda: self.slider2.setCursor(QCursor(QtCore.Qt.ClosedHandCursor)))
        self.slider2.sliderReleased.connect(
            lambda: self.slider2.setCursor(QCursor(QtCore.Qt.OpenHandCursor)))

        self.label3 = QLabel(self)
        self.label3.setText('Relative Imports')
        self.label3.setGeometry(QtCore.QRect(25, 125, 125, 25))

        self.slider3 = QSlider(self)
        self.slider3.setGeometry(QtCore.QRect(150, 125, 25, 25))
        self.slider3.setTickInterval(1)
        self.slider3.setCursor(QCursor(QtCore.Qt.OpenHandCursor))
        self.slider3.TickPosition(QSlider.TicksBothSides)
        self.slider3.setRange(0, 1)
        self.slider3.setValue(0)
        self.sli3lbl = QLabel(str(self.slider3.value()), self.slider3)
        self.sli3lbl.move(9, 5)
        self.sli3lbl.setAutoFillBackground(False)
        self.slider3.valueChanged.connect(
            lambda: self.sli3lbl.setText(str(self.slider3.value())))
        self.slider3.sliderPressed.connect(
            lambda: self.slider3.setCursor(QCursor(QtCore.Qt.ClosedHandCursor)))
        self.slider3.sliderReleased.connect(
            lambda: self.slider3.setCursor(QCursor(QtCore.Qt.OpenHandCursor)))

        self.label4 = QLabel(self)
        self.label4.setText('Indent Spaces')
        self.label4.setGeometry(QtCore.QRect(25, 175, 125, 25))

        self.combo1 = QComboBox(self)
        self.combo1.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        self.combo1.addItems(['4', '0', '2', '6', '8'])
        self.combo1.setGeometry(QtCore.QRect(150, 175, 50, 25))

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setGeometry(QtCore.QRect(25, 225, 200, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel |
            QDialogButtonBox.Close | QDialogButtonBox.Help)
        self.buttonBox.setCenterButtons(False)
        self.buttonBox.helpRequested.connect(lambda: QMessageBox.about(
            self, __doc__, str(__doc__ + ', ' + ',\nversion ' + __version__ +
                               '(' + __license__ + '),\nby ' + __author__ + ', '
                               + __email__)))
        self.buttonBox.accepted.connect(self.run)
        self.buttonBox.rejected.connect(self.close)
        palette = self.palette()
        palette.setBrush(QPalette.Base, Qt.transparent)
        self.setPalette(palette)
        self.setAttribute(Qt.WA_OpaquePaintEvent, False)

    def run(self):
        'Run the actual conversion.'
        # Ask the User for the source .ui file as input
        filein = str(QFileDialog.getOpenFileName(
            self, __doc__, path.expanduser("~"), 'UI(*.ui)')).strip()
        # Parse Value of Slider1 as the Debug flag parameter
        if self.slider1.value() == 0:
            arg1 = ''
        else:
            arg1 = '--debug '
        # Parse Value of Slider2 as the Execute flag parameter
        if self.slider2.value() == 0:
            arg2 = ''
        else:
            arg2 = '--execute '
        # Parse Value of Slider3 as the relative imports flag parameter
        if self.slider3.value() == 0:
            arg3 = ''
        else:
            arg3 = '--from-imports '
        # debug
        #print(arg1, arg2, arg3, str(self.combo1.currentText()))
        # run the subprocesses
        subprocess.Popen(
            'nice --adjustment=19 pyuic4 ' + arg1 + arg2 + arg3 +
            '--indent=' + str(self.combo1.currentText()) +
            ' --output=' + str(filein).lower().replace('.ui', '.py') +
            ' ' + filein +
            ' && chmod -v +x ' + str(filein).lower().replace('.ui', '.py'),
            shell=True)

    def paintEvent(self, event):
        ' Paint semi-transparent background '
        painter = QPainter(self)
        painter.fillRect(event.rect(), Qt.transparent)
        painter.setPen(Qt.NoPen)
        painter.setBrush(QColor(0, 0, 0))
        painter.setOpacity(0.75)
        painter.drawRoundedRect(self.rect(), 75, 50)
        painter.end()
Example #21
0
class QTSeedEditor(QDialog):
    """
    DICOM viewer.
    """
    @staticmethod
    def get_line(mode='h'):
        line = QFrame()
        if mode == 'h':
            line.setFrameStyle(QFrame.HLine)
        elif mode == 'v':
            line.setFrameStyle(QFrame.VLine)

        line.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        return line

    def initUI(self, shape, vscale, height=600, mode='seed'):
        """
        Initialize UI.

        Parameters
        ----------
        shape : (int, int, int)
            Shape of data matrix.
        vscale : (float, float, float)
            Voxel scaling.
        height : int
            Maximal slice height in pixels.
        mode : str
            Editor mode.
        """

        self.slab = {}

        # picture
        grid = height / float(shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])
        self.slice_box = SliceBox(shape[:-1], mgrid, mode)
        self.slice_box.setScrollFun(self.scrollSlices)
        self.connect(self.slice_box, SIGNAL('focus_slider'),
                     self.focusSliceSlider)

        # sliders
        self.allow_select_slice = True
        self.n_slices = shape[2]
        self.slider = QSlider(Qt.Vertical)
        self.slider.valueChanged.connect(self.sliderSelectSlice)
        self.slider.label = QLabel()
        self.slider.setRange(1, self.n_slices)

        self.slider_cw = {}
        self.slider_cw['c'] = QSlider(Qt.Horizontal)
        self.slider_cw['c'].valueChanged.connect(self.changeC)
        self.slider_cw['c'].label = QLabel()

        self.slider_cw['w'] = QSlider(Qt.Horizontal)
        self.slider_cw['w'].valueChanged.connect(self.changeW)
        self.slider_cw['w'].label = QLabel()

        self.view_label = QLabel('View size: %d x %d' %
                                 self.img_aview.shape[:-1])
        self.voxel_label = QLabel('Voxel size [mm]:\n  %.2f x %.2f x %.2f'\
                                      % tuple(self.voxel_size[np.array(self.act_transposition)]))

        # combo_view_options = VIEW_TABLE.keys()
        # combo_view = QComboBox(self)
        # combo_view.activated[str].connect(self.setView)
        # combo_view.addItems(combo_view_options)

        #radio button group for choosing seed class ------------------------
        self.current_class = 1
        self.slice_box.seed_mark = self.current_class
        number_group = QGroupBox(QString('Class markers'))
        vbox_NG = QVBoxLayout()
        r1 = QRadioButton('class 1')
        r1.setStyleSheet('QRadioButton {color: red}')
        r1.setChecked(True)
        r2 = QRadioButton('class 2')
        r2.setStyleSheet('QRadioButton {color: green}')
        r3 = QRadioButton('class 3')
        r3.setStyleSheet('QRadioButton {color: blue}')
        r4 = QRadioButton('class 4')
        r4.setStyleSheet('QRadioButton {color: cyan}')
        r5 = QRadioButton('class 5')
        r5.setStyleSheet('QRadioButton {color: magenta}')

        vbox_NG.addWidget(r1)
        vbox_NG.addWidget(r2)
        vbox_NG.addWidget(r3)
        vbox_NG.addWidget(r4)
        vbox_NG.addWidget(r5)

        number_group.setLayout(vbox_NG)

        self.button_group = QButtonGroup()
        self.button_group.addButton(r1, 1)
        self.button_group.addButton(r2, 2)
        self.button_group.addButton(r3, 3)
        self.button_group.addButton(r4, 4)
        self.button_group.addButton(r5, 5)
        self.connect(self.button_group, SIGNAL("buttonClicked(int)"),
                     self.change_seed_class)
        #-------------------------------------------------------------------

        # buttons
        # btn_save = QPushButton('Save', self)
        # btn_save.clicked.connect(self.save)

        btn_quit = QPushButton("Quit", self)
        btn_quit.clicked.connect(self.quit)

        # btn_crop = QPushButton('Crop', self)
        # btn_crop.clicked.connect(self.crop)

        combo_dmask = QComboBox(self)
        combo_dmask.activated.connect(self.changeMask)
        self.mask_points_tab, aux = self.init_draw_mask(DRAW_MASK, mgrid)
        for icon, label in aux:
            combo_dmask.addItem(icon, label)

        self.slice_box.setMaskPoints(
            self.mask_points_tab[combo_dmask.currentIndex()])

        self.status_bar = QStatusBar()

        vopts = []
        vmenu = []
        appmenu = []

        # btn_recalc = QPushButton("Recalculate", self)
        # btn_recalc.clicked.connect(self.recalculate)
        # appmenu.append(QLabel('<b>Segmentation mode</b><br><br><br>' +
        #                       'Select the region of interest<br>' +
        #                       'using the mouse buttons.<br><br>'))
        # appmenu.append(btn_recalc)
        # appmenu.append(QLabel())
        # self.volume_label = QLabel('Volume [mm3]:\n  unknown')
        # appmenu.append(self.volume_label)

        # btn_crop = QPushButton("Crop", self)
        # btn_crop.clicked.connect(self.crop)
        # appmenu.append(btn_crop)

        btn_save = QPushButton("Save Seeds", self)
        btn_save.clicked.connect(self.saveSeeds)
        appmenu.append(btn_save)

        btn_del = QPushButton("Delete Seeds", self)
        btn_del.clicked.connect(self.deleteSliceSeeds)
        appmenu.append(btn_del)

        # combo_contour_options = ['fill', 'contours', 'off']
        # combo_contour = QComboBox(self)
        # combo_contour.activated[str].connect(self.changeContourMode)
        # combo_contour.addItems(combo_contour_options)
        # self.changeContourMode(combo_contour_options[combo_contour.currentIndex()])
        # vopts.append(QLabel('Selection mode:'))
        # vopts.append(combo_contour)

        # btn_reset = QPushButton("Reset Seeds", self)
        # btn_reset.clicked.connect(self.resetSliceDraw)
        # # appmenu.append(None)
        # appmenu.append(btn_reset)

        hbox = QHBoxLayout()
        vbox = QVBoxLayout()
        vbox_left = QVBoxLayout()
        vbox_app = QVBoxLayout()

        hbox.addWidget(self.slice_box)
        hbox.addWidget(self.slider)
        vbox_left.addWidget(self.slider.label)
        vbox_left.addWidget(self.view_label)
        vbox_left.addWidget(self.voxel_label)
        # vbox_left.addWidget(QLabel())
        # vbox_left.addWidget(QLabel('View plane:'))
        # vbox_left.addWidget(combo_view)
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(self.slider_cw['c'].label)
        vbox_left.addWidget(self.slider_cw['c'])
        vbox_left.addWidget(self.slider_cw['w'].label)
        vbox_left.addWidget(self.slider_cw['w'])
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(QLabel('Drawing mask:'))
        vbox_left.addWidget(combo_dmask)

        for ii in vopts:
            vbox_left.addWidget(ii)

        for ii in vmenu:
            if ii is None:
                vbox_left.addStretch(1)

            else:
                vbox_left.addWidget(ii)

        for ii in appmenu:
            if ii is None:
                vbox_app.addStretch(1)

            else:
                vbox_app.addWidget(ii)

        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(number_group)

        # vbox_app.addWidget(btn_crop)

        vbox_app.addStretch(1)
        # vbox_app.addWidget(btn_save)
        vbox_app.addWidget(btn_quit)

        hbox.addLayout(vbox_left)
        hbox.addWidget(self.get_line('v'))
        hbox.addLayout(vbox_app)
        vbox.addLayout(hbox)
        vbox.addWidget(self.status_bar)
        self.setLayout(vbox)

        self.setWindowTitle('Seed Editor')
        self.show()

    def __init__(self,
                 img,
                 seeds_fname='seeds.npy',
                 actualSlice=0,
                 seeds=None,
                 contours=None,
                 mode='seed',
                 modeFun=None,
                 voxelSize=[1, 1, 1]):
        """
        Initiate Editor

        Parameters
        ----------
        img : array
            DICOM data matrix.
        actualSlice : int
            Index of actual slice.
        seeds : array
            Seeds, user defined regions of interest.
        contours : array
            Computed segmentation.
        mode : str
            Editor modes:
               'seed' - seed editor
               'crop' - manual crop
               'draw' - drawing
        modeFun : fun
            Mode function invoked by user button.
        voxelSize : tuple of float
            voxel size [mm]
        """

        QDialog.__init__(self)

        self.mode = mode
        self.mode_fun = modeFun
        self.seeds_fname = seeds_fname
        # self.datapath = datapath

        self.actual_view = 'axial'
        self.act_transposition = VIEW_TABLE[self.actual_view]
        self.last_view_position = {}
        for ii in VIEW_TABLE.iterkeys():
            self.last_view_position[ii] = img.shape[VIEW_TABLE[ii][-1]] - 1

        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)
        self.actual_slice = self.img_aview.shape[-1] - actualSlice - 1
        self.last_view_position[self.actual_view] = self.actual_slice

        # set contours
        self.contours = contours
        if self.contours is None:
            self.contours_aview = None

        else:
            self.contours_aview = self.contours.transpose(
                self.act_transposition)

        self.voxel_size = np.array(voxelSize)
        self.voxel_scale = self.voxel_size / float(np.min(self.voxel_size))
        self.voxel_volume = np.prod(voxelSize)

        # set seeds
        if seeds is None:
            self.seeds = np.zeros(self.img.shape, np.int8)
        else:
            self.seeds = seeds

        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        self.initUI(self.img_aview.shape,
                    self.voxel_scale[np.array(self.act_transposition)], 600,
                    mode)

        if mode == 'draw':
            self.seeds_orig = self.seeds.copy()
            self.slice_box.setEraseFun(self.eraseVolume)

        # set view window values C/W
        lb = np.min(img)
        ub = np.max(img)
        dul = ub - lb
        self.cw_range = {'c': [lb, ub], 'w': [1, dul]}
        self.slider_cw['c'].setRange(lb, ub)
        self.slider_cw['w'].setRange(1, dul)
        self.changeC(lb + dul / 2)
        self.changeW(dul)

        self.offset = np.zeros((3, ), dtype=np.int16)

    def change_seed_class(self, id):
        self.current_class = id
        self.slice_box.seed_mark = self.current_class
        # print 'Current seed class changed to ', id, '.'

    def showStatus(self, msg):
        self.status_bar.showMessage(QString(msg))
        QApplication.processEvents()

    def init_draw_mask(self, draw_mask, grid):
        mask_points = []
        mask_iconlabel = []
        for mask, label in draw_mask:
            w, h = mask.shape
            xx, yy = mask.nonzero()
            mask_points.append((xx - w / 2, yy - h / 2))

            img = QImage(w, h, QImage.Format_ARGB32)
            img.fill(qRgba(255, 255, 255, 0))
            for ii in range(xx.shape[0]):
                img.setPixel(xx[ii], yy[ii], qRgba(0, 0, 0, 255))

            img = img.scaled(QSize(w * grid[0], h * grid[1]))
            icon = QIcon(QPixmap.fromImage(img))
            mask_iconlabel.append((icon, label))

        return mask_points, mask_iconlabel

    def saveSliceSeeds(self):
        aux = self.slice_box.getSliceSeeds()
        if aux is not None:
            self.seeds_aview[..., self.actual_slice] = aux
            self.seeds_modified = True

        else:
            self.seeds_modified = False

    def saveSeeds(self):
        print 'Saving seeds array ... ',
        # aux = np.swapaxes(np.swapaxes(self.seeds_aview, 1, 2), 0, 1)
        aux = np.swapaxes(self.seeds_aview, 0, 2)
        np.save(self.seeds_fname, aux)
        print 'done'

    def updateCropBounds(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp
            self.contours = np.zeros(self.img.shape, np.int8)
            self.contours[cri].fill(1)
            self.contours_aview = self.contours.transpose(
                self.act_transposition)

    def focusSliceSlider(self):
        self.slider.setFocus(True)

    def sliderSelectSlice(self, value):
        self.selectSlice(self.n_slices - value)

    def scrollSlices(self, inc):
        if abs(inc) > 0:
            new = self.actual_slice + inc
            self.selectSlice(new)

    def selectSlice(self, value, force=False):
        if not (self.allow_select_slice):
            return

        if (value < 0) or (value >= self.n_slices):
            return

        if (value != self.actual_slice) or force:
            self.saveSliceSeeds()
            if self.seeds_modified and (self.mode == 'crop'):
                self.updateCropBounds()

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[..., value]

        slider_val = self.n_slices - value
        self.slider.setValue(slider_val)
        self.slider.label.setText('Slice: %d / %d' %
                                  (slider_val, self.n_slices))

        self.slice_box.setSlice(self.img_aview[..., value],
                                self.seeds_aview[..., value], contours)
        self.actual_slice = value

    def getSeeds(self):
        return self.seeds

    def getImg(self):
        return self.img

    def getOffset(self):
        return self.offset * self.voxel_size

    def getSeedsVal(self, label):
        return self.img[self.seeds == label]

    def getContours(self):
        return self.contours

    def setContours(self, contours):
        self.contours = contours
        self.contours_aview = self.contours.transpose(self.act_transposition)

        self.selectSlice(self.actual_slice)

    def changeCW(self, value, key):
        rg = self.cw_range[key]
        if (value < rg[0]) or (value > rg[1]):
            return

        if (value != self.slice_box.getCW()[key]):
            self.slider_cw[key].setValue(value)
            self.slider_cw[key].label.setText('%s: %d' % (key.upper(), value))
            self.slice_box.setCW(value, key)
            self.slice_box.updateSliceCW(self.img_aview[...,
                                                        self.actual_slice])

    def changeC(self, value):
        self.changeCW(value, 'c')

    def changeW(self, value):
        self.changeCW(value, 'w')

    def setView(self, value):
        self.last_view_position[self.actual_view] = self.actual_slice
        # save seeds
        self.saveSliceSeeds()
        if self.seeds_modified and (self.mode == 'crop'):
            self.updateCropBounds(self.seeds_aview[..., self.actual_slice])

        key = str(value)
        self.actual_view = key
        self.actual_slice = self.last_view_position[key]

        self.act_transposition = VIEW_TABLE[key]
        self.img_aview = self.img.transpose(self.act_transposition)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)

        if self.contours is not None:
            self.contours_aview = self.contours.transpose(
                self.act_transposition)
            contours = self.contours_aview[..., self.actual_slice]

        else:
            contours = None

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[..., self.actual_slice],
                                self.seeds_aview[...,
                                                 self.actual_slice], contours)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        slider_val = self.n_slices - self.actual_slice
        self.slider.setValue(slider_val)
        self.slider.setRange(1, self.n_slices)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' %
                                  (slider_val, self.n_slices))
        self.view_label.setText('View size: %d x %d' %
                                self.img_aview.shape[:-1])

    def changeMask(self, val):
        self.slice_box.setMaskPoints(self.mask_points_tab[val])

    def changeContourMode(self, val):
        self.slice_box.contour_mode = str(val)
        self.slice_box.updateSlice()

    def changeEraseMode(self, val):
        self.slice_box.erase_mode = str(val)

    def eraseVolume(self, pos, mode):
        self.showStatus("Processing...")
        xyz = pos + (self.actual_slice, )
        p = tuple(np.array(xyz)[np.array(self.act_transposition)])
        if self.seeds[p] > 0:
            if mode == 'inside':
                erase_reg(self.seeds, p, val=0)

            elif mode == 'outside':
                erase_reg(self.seeds, p, val=-1)
                idxs = np.where(self.seeds < 0)
                self.seeds.fill(0)
                self.seeds[idxs] = 1

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[..., self.actual_slice]

        self.slice_box.setSlice(self.img_aview[..., self.actual_slice],
                                self.seeds_aview[...,
                                                 self.actual_slice], contours)

        self.showStatus("Done")

    def cropUpdate(self, img):

        for ii in VIEW_TABLE.iterkeys():
            self.last_view_position[ii] = 0
        self.actual_slice = 0

        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)

        self.contours = None
        self.contours_aview = None

        self.seeds = np.zeros(self.img.shape, np.int8)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[..., self.actual_slice],
                                self.seeds_aview[..., self.actual_slice], None)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        self.slider.setValue(self.actual_slice + 1)
        self.slider.setRange(1, self.n_slices)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' %
                                  (self.actual_slice + 1, self.n_slices))
        self.view_label.setText('View size: %d x %d' %
                                self.img_aview.shape[:-1])

    def getCropBounds(self):

        nzs = self.seeds.nonzero()
        cri = []
        flag = True
        for ii in range(3):
            if nzs[ii].shape[0] == 0:
                flag = False
                break

            smin, smax = np.min(nzs[ii]), np.max(nzs[ii])
            if smin == smax:
                flag = False
                break

            cri.append((smin, smax))

        if flag:
            cri = np.array(cri)

            out = []
            offset = []
            for jj, ii in enumerate(cri):
                out.append(slice(ii[0], ii[1] + 1))
                offset.append(ii[0])

            return np.array(offset), tuple(out)

        else:
            return None

    def crop(self):
        self.showStatus("Processing...")

        crp = self.getCropBounds()

        if crp is not None:
            offset, cri = crp
            crop = self.img[cri]
            self.img = np.ascontiguousarray(crop)
            self.offset += offset

            self.showStatus('Done')

        else:
            self.showStatus('Region not selected!')

        self.cropUpdate(self.img)

    def recalculate(self, event):
        self.saveSliceSeeds()
        if np.abs(np.min(self.seeds) - np.max(self.seeds)) < 2:
            self.showStatus('At least two regions must be marked!')
            return

        self.showStatus("Processing...")
        # idx = 3
        # s = random_walker(self.img[idx,:,:], self.seeds[idx,:,:])#, mode='cg_mg')
        # plt.figure()
        # plt.imshow(mark_boundaries(self.img[idx,:,:], s))
        # plt.show()
        # self.segmentation = np.zeros(self.img.shape)
        # self.segmentation[idx,:,:] = s
        self.segmentation = random_walker(self.img, self.seeds, mode='cg_mg')
        self.setContours(self.segmentation - 1)
        self.selectSlice(self.actual_slice)
        # self.updateVolume()
        self.showStatus("Done")

    def deleteSliceSeeds(self, event):
        self.seeds_aview[..., self.actual_slice] = 0
        self.slice_box.setSlice(seeds=self.seeds_aview[..., self.actual_slice])
        self.slice_box.updateSlice()

    def resetSliceDraw(self, event):
        seeds_orig_aview = self.seeds_orig.transpose(self.act_transposition)
        self.seeds_aview[..., self.actual_slice] = seeds_orig_aview[
            ..., self.actual_slice]
        self.slice_box.setSlice(seeds=self.seeds_aview[..., self.actual_slice])
        self.slice_box.updateSlice()

    def quit(self, event):
        self.close()

    # def save(self, event):
    #     odp = os.path.expanduser("~/lisa_data")
    #     if not op.exists(odp):
    #         os.makedirs(odp)
    #
    #     data = self.export()
    #     # data['version'] = self.version
    #     # data['experiment_caption'] = self.experiment_caption
    #     # data['lisa_operator_identifier'] = self.lisa_operator_identifier
    #     pth, filename = op.split(op.normpath(self.datapath))
    #     # filename += "-" + self.experiment_caption
    #     filepath = 'org-' + filename + '.pklz'
    #     filepath = op.join(odp, filepath)
    #     filepath = misc.suggest_filename(filepath)
    #     misc.obj_to_file(data, filepath, filetype='pklz')
    #
    #     filepath = 'organ_last.pklz'
    #     filepath = op.join(odp, filepath)
    #     misc.obj_to_file(data, filepath, filetype='pklz')

    # def export(self):
    #     slab = {}
    #     slab['none'] = 0
    #     slab['liver'] = 1
    #     slab['lesions'] = 6
    #     slab.update(self.slab)
    #
    #     data = {}
    #     data['version'] = (1, 0, 1)
    #     data['data3d'] = self.img
    #     # data['crinfo'] = self.crinfo
    #     data['segmentation'] = self.segmentation
    #     data['slab'] = slab
    #     # data['voxelsize_mm'] = self.voxelsize_mm
    #     # data['orig_shape'] = self.orig_shape
    #     # data['processing_time'] = self.processing_time
    #     return data

    def updateVolume(self):
        text = 'Volume [mm3]:\n  unknown'
        if self.voxel_volume is not None:
            if self.mode == 'draw':
                vd = self.seeds

            else:
                vd = self.contours

            if vd is not None:
                nzs = vd.nonzero()
                nn = nzs[0].shape[0]
                text = 'Volume [mm3]:\n  %.2e' % (nn * self.voxel_volume)

        self.volume_label.setText(text)

    def getROI(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp

        else:
            cri = []
            for jj, ii in enumerate(self.img.shape):
                off = self.offset[jj]
                cri.append(slice(off, off + ii))

        return cri
Example #22
0
class LogDialog(QDialog):
    """LogDialog for the Freeseer project.

    It is the dialog window for the log.
    There is an instance for every FreeseerApp.
    It has a LogHandler which calls LogDialog's
    message() method when a new log message is received.
    The call to message() causes a call to add_entry()
    which adds the information to a new row in the table.
    """

    def __init__(self, parent=None):
        super(LogDialog, self).__init__(parent)

        self.resize(800, 500)

        self.app = QApplication.instance()

        icon = QIcon()
        icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.level = 0
        self.handler = LogHandler()

        self.table_model = QStandardItemModel(0, 5)
        header_names = ["Date", "Level", "Module", "Message", "LevelNo"]
        date_column = header_names.index("Date")
        level_column = header_names.index("Level")
        module_column = header_names.index("Module")
        self.level_num_column = header_names.index("LevelNo")
        self.table_model.setHorizontalHeaderLabels(header_names)

        self.table_view = QTableView()
        self.table_view.setModel(self.table_model)
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.setColumnWidth(date_column, 125)
        self.table_view.setColumnWidth(level_column, 60)
        self.table_view.setColumnWidth(module_column, 250)
        self.table_view.setColumnHidden(self.level_num_column, True)
        self.table_view.setShowGrid(False)
        self.table_view.horizontalHeader().setClickable(False)
        self.table_view.verticalHeader().hide()
        self.table_view.setStyleSheet("""Qtable_view::item {
            border-bottom: 1px solid lightgrey;
            selection-background-color: white;
            selection-color: black;
            }""")

        top_panel = QHBoxLayout()
        self.log_levels = ["Debug", "Info", "Warning", "Error"]
        self.level_colors = ["#3E4C85", "#269629", "#B0AB21", "#B32020"]

        self.levels_label = QLabel("Filter Level: ")
        self.levels_label.setStyleSheet("QLabel { font-weight: bold }")
        self.current_level_label = QLabel(self.log_levels[0])
        self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(self.level_colors[0]))
        self.clear_button = QPushButton("Clear Log")
        self.levels_slider = QSlider(Qt.Horizontal)
        self.levels_slider.setStyleSheet("""
        QSlider::handle:horizontal {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #FFFFFF, stop:1 #E3E3E3);
            border: 1px solid #707070;
            width: 10px;
            margin-top: -4px;
            margin-bottom: -4px;
            border-radius: 4px;
        }

        QSlider::handle:horizontal:hover {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #DEDEDE, stop:1 #C9C9C9);
            border: 1px solid #4F4F4F;
            border-radius: 4px;
        }

        QSlider::sub-page:horizontal {
            background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
                stop: 0 #BFBFBF, stop: 1 #9E9E9E);
            background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
                stop: 0 #9E9E9E, stop: 1 #858585);
            border: 1px solid #777;
            height: 10px;
            border-radius: 4px;
        }

        QSlider::add-page:horizontal {
            background: #fff;
            border: 1px solid #707070;
            height: 10px;
            border-radius: 4px;
        }""")
        self.levels_slider.setRange(0, len(self.log_levels) - 1)
        self.levels_slider.setTickPosition(QSlider.TicksBelow)
        self.levels_slider.setTickInterval(1)

        top_panel.addSpacerItem(QSpacerItem(10, 0))
        top_panel.addWidget(self.levels_label, 3)
        top_panel.addWidget(self.current_level_label, 2)
        top_panel.addWidget(self.levels_slider, 8)
        top_panel.addSpacerItem(QSpacerItem(25, 0))
        top_panel.addWidget(self.clear_button, 10)

        layout.addLayout(top_panel)
        layout.addWidget(self.table_view)

        self.connect(self.clear_button, SIGNAL('clicked()'), functools.partial(self.table_model.setRowCount, 0))
        self.connect(self.levels_slider, SIGNAL('valueChanged(int)'), self.slider_set_level)

        self.setWindowTitle("Log")
        self.handler.add_listener(self)

    def __del__(self):
        self.handler.remove_listener(self)

    def retranslate(self):
        self.setWindowTitle(self.app.translate("LogDialog", "Log"))
        self.clear_button.setText(self.app.translate("LogDialog", "Clear Log"))
        self.levels_label.setText("{}: ".format(self.app.translate("LogDialog", "Filter Level")))

    def message(self, message):
        """Passes the log fields to add_entry()

        It is called by LogHandler when a log message is received"""
        self.add_entry(message["time"], message["level"], message["full_module_name"], message["message"], str(message["levelno"]))

    def add_entry(self, date, level, module, message, levelno):
        """Adds the given fields to a new row in the log table

        It is called by message() when a log message is received"""
        items = [QStandardItem(date), QStandardItem(level), QStandardItem(module), QStandardItem(message), QStandardItem(levelno)]
        for item in items:
            item.setEditable(False)
        self.table_model.appendRow(items)

    def slider_set_level(self, level):
        self.current_level_label.setText(self.log_levels[level])
        self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(self.level_colors[level]))
        self.set_level(level + 1)

    def set_level(self, level):
        """Sets the current level of the LogDialog.

        Level is based on the selection made in the levels_combo_box.
        It hides all messages with a lower level."""
        self.level = level * 10
        for i in range(self.table_model.rowCount()):
            if int(str(self.table_model.item(i, self.level_num_column).text())) < self.level:
                self.table_view.setRowHidden(i, True)
            else:
                self.table_view.setRowHidden(i, False)
Example #23
0
class MainWin(QMainWindow):
    def __init__(self, mx, spurs, fef, parent=None, plot_lib='mpl'):
        QMainWindow.__init__(self, parent)

        self.mx = mx
        self.spurset = spurs
        self.fef = fef

        if plot_lib == 'qwt':
            from chart.qwtchart import qwtchart as chart
        elif plot_lib == 'mpl':
            from chart.mplchart import mplchart as chart
        elif plot_lib == 'pg':
            from chart.pyqtgraphchart import pyqtgraphchart as chart
        else:
            raise NotImplementedError

        self.chart = chart(self.spurset, self.fef, self)
        self.create_menu_bar()
        self.create_main_frame()
        self.hookup()

    def hookup(self):
        # connect all the objects that are supposed to be watching each other
        # for changes and updates.
        self.mx.register(self.chart.draw_spurs)
        self.spurset.register(self.chart.draw_spurs)
        self.chart.picker_watch(self.fef)
        self.fef.register(self.chart.draw_fef)
        self.chart.draw_spurs(self.spurset)
        self.chart.draw_fef(self.fef)

    def IF_slide(self, i):
        """ callback method for the IF selection slider"""
        self.IFtextbox.setText(str(i))
        self.mx.IF = i

    def about(self):
        msg = '''
        A frequency-planing tool based on the method of spur distances.
        (A reference to the article will go here)
        For more info, view the README included with this program.

        Patrick Yeon, 2012'''
        QMessageBox.about(self, 'Spur Distance Chart', msg.strip())

    def mxtypecb(self, i):
        """ callback method for mixer configuration selection combobox"""
        self.mx.m, self.mx.n = [(-1, 1), (1, -1), (1, 1)][i]
        # trigger anything watching the mixer
        self.mx.update_watchers()

    def create_main_frame(self):
        self.main_frame = QWidget()
        # Looking at the main frame as two columns. On the left there is the
        # chart and the IF control. In the right column we'll have range
        # settings, mixer settings, and maybe other stuff that comes up?

        self.IFtextbox = QLineEdit()
        self.IFtextbox.setMinimumWidth(6)
        self.IFtextbox.setText(str(self.spurset.mixer.IF))
        # TODO link up the textbox so that it can also be input

        self.IFslider = QSlider(Qt.Horizontal)
        # TODO I'd really like some form of slider that doesn't actually limit
        # the user. Also, if IFtextbox could modify the IF, that'd be nice.
        self.IFslider.setRange(int(self.mx.IF * 0.1), (self.mx.IF * 5))
        self.IFslider.setValue(self.mx.IF)
        self.IFslider.setTracking(True)
        self.IFslider.setTickPosition(QSlider.TicksAbove)
        step = max(1, int(0.01 * self.mx.IF))
        self.IFslider.setSingleStep(step)
        self.IFslider.setPageStep(step * 10)
        self.IFcid = self.connect(self.IFslider, SIGNAL('valueChanged(int)'),
                                  self.IF_slide)

        IFbar = QHBoxLayout()
        IFbar.addWidget(QLabel('IF'))
        IFbar.addWidget(self.IFtextbox)
        IFbar.addWidget(self.IFslider)
        IFbar.addStretch()

        leftcol = QVBoxLayout()
        leftcol.addWidget(self.chart.plot)
        leftcol.addLayout(IFbar)

        # left column done. Now the right-hand side
        rangebox = QVBoxLayout()
        for (prop, name, f) in [(spurset.RFmin, 'RFmin', self.spurset.RFmin),
                                (spurset.RFmax, 'RFmax', self.spurset.RFmax),
                                (spurset.dspan, 'dspan', self.spurset.dspan)]:
            rangebox.addLayout(Fbar(self.spurset, prop, name, f, 0, 10000))
        autocb = QCheckBox('Auto')
        # Disable it, won't be implemented for release
        # but leave it there, to nag me into doing it.
        autocb.setDisabled(True)
        rangebox.addWidget(autocb)

        # a line to report the front-end filter's limits
        fefstat = QHBoxLayout()
        fefstat.addWidget(QLabel('Filter Range: '))
        fefrange = QLabel('%d - %d' % (self.fef.start, self.fef.stop))
        # TODO not sure about the lambda here. Feels like if I give it time,
        # I'll sort out a sensible overall connection scheme.
        self.fef.register(lambda o: fefrange.setText('%d - %d' % (
            self.fef.start, self.fef.stop)))
        fefstat.addWidget(fefrange)

        # mixer high/low-side injection picker
        mxbar = QHBoxLayout()
        mxbar.addWidget(QLabel('IF = '))
        mxtype = QComboBox()
        mxtype.addItem('LO - RF')
        mxtype.addItem('RF - LO')
        mxtype.addItem('RF + LO')
        # TODO this is ugly
        mxtype.setCurrentIndex([(-1, 1), (1, -1), (1, 1)].index(
            (self.mx.m, self.mx.n)))
        self.mxtypecid = self.connect(mxtype,
                                      SIGNAL('currentIndexChanged(int)'),
                                      self.mxtypecb)
        mxbar.addWidget(mxtype)

        # alright, the actual column proper in the layout
        vbar = QVBoxLayout()
        vbar.addLayout(rangebox)
        vbar.addLayout(fefstat)
        vbar.addLayout(mxbar)
        legend = self.chart.legend()
        vbar.addWidget(legend)
        # need to let the legend stretch so that everything fits in it
        vbar.setStretchFactor(legend, 1)
        vbar.addStretch()

        hbox = QHBoxLayout()
        hbox.addLayout(leftcol)
        hbox.addLayout(vbar)
        # make sure the legend doesn't stretch so far horizontally that the
        # chart suffers considerable loss of space.
        hbox.setStretchFactor(leftcol, 5)
        hbox.setStretchFactor(vbar, 1)

        self.main_frame.setLayout(hbox)
        self.setCentralWidget(self.main_frame)

    def create_menu_bar(self):
        filemenu = self.menuBar().addMenu('&File')
        close = QAction('&Quit', self)
        close.setShortcut('Ctrl+W')
        self.connect(close, SIGNAL('triggered()'), self.close)
        filemenu.addAction(close)

        helpmenu = self.menuBar().addMenu('&Help')
        about = QAction('&About', self)
        about.setShortcut('F1')
        self.connect(about, SIGNAL('triggered()'), self.about)
        helpmenu.addAction(about)
Example #24
0
class MusicView(preferences.Group):
    def __init__(self, page):
        super(MusicView, self).__init__(page)

        layout = QGridLayout()
        self.setLayout(layout)

        self.newerFilesOnly = QCheckBox(toggled=self.changed)
        layout.addWidget(self.newerFilesOnly, 0, 0, 1, 3)

        self.magnifierSizeLabel = QLabel()
        self.magnifierSizeSlider = QSlider(Qt.Horizontal,
                                           valueChanged=self.changed)
        self.magnifierSizeSlider.setSingleStep(50)
        self.magnifierSizeSlider.setRange(
            *popplerview.MagnifierSettings.sizeRange)
        self.magnifierSizeSpinBox = QSpinBox()
        self.magnifierSizeSpinBox.setRange(
            *popplerview.MagnifierSettings.sizeRange)
        self.magnifierSizeSpinBox.valueChanged.connect(
            self.magnifierSizeSlider.setValue)
        self.magnifierSizeSlider.valueChanged.connect(
            self.magnifierSizeSpinBox.setValue)
        layout.addWidget(self.magnifierSizeLabel, 1, 0)
        layout.addWidget(self.magnifierSizeSlider, 1, 1)
        layout.addWidget(self.magnifierSizeSpinBox, 1, 2)

        self.magnifierScaleLabel = QLabel()
        self.magnifierScaleSlider = QSlider(Qt.Horizontal,
                                            valueChanged=self.changed)
        self.magnifierScaleSlider.setSingleStep(50)
        self.magnifierScaleSlider.setRange(
            *popplerview.MagnifierSettings.scaleRange)
        self.magnifierScaleSpinBox = QSpinBox()
        self.magnifierScaleSpinBox.setRange(
            *popplerview.MagnifierSettings.scaleRange)
        self.magnifierScaleSpinBox.valueChanged.connect(
            self.magnifierScaleSlider.setValue)
        self.magnifierScaleSlider.valueChanged.connect(
            self.magnifierScaleSpinBox.setValue)
        layout.addWidget(self.magnifierScaleLabel, 2, 0)
        layout.addWidget(self.magnifierScaleSlider, 2, 1)
        layout.addWidget(self.magnifierScaleSpinBox, 2, 2)

        self.enableKineticScrolling = QCheckBox(toggled=self.changed)
        layout.addWidget(self.enableKineticScrolling)
        self.showScrollbars = QCheckBox(toggled=self.changed)
        layout.addWidget(self.showScrollbars)
        app.translateUI(self)

    def translateUI(self):
        self.setTitle(_("Music View"))
        self.newerFilesOnly.setText(_("Only load updated PDF documents"))
        self.newerFilesOnly.setToolTip(
            _("If checked, Frescobaldi will not open PDF documents that are not\n"
              "up-to-date (i.e. the source file has been modified later)."))
        self.magnifierSizeLabel.setText(_("Magnifier Size:"))
        self.magnifierSizeLabel.setToolTip(
            _("Size of the magnifier glass (Ctrl+Click in the Music View)."))
        # L10N: as in "400 pixels", appended after number in spinbox, note the leading space
        self.magnifierSizeSpinBox.setSuffix(_(" pixels"))
        self.magnifierScaleLabel.setText(_("Magnifier Scale:"))
        self.magnifierScaleLabel.setToolTip(
            _("Magnification of the magnifier."))
        self.magnifierScaleSpinBox.setSuffix(_("percent unit sign", "%"))
        # L10N: "Kinetic Scrolling" is a checkbox label, as in "Enable Kinetic Scrolling"
        self.enableKineticScrolling.setText(_("Kinetic Scrolling"))
        self.showScrollbars.setText(_("Show Scrollbars"))

    def loadSettings(self):
        s = popplerview.MagnifierSettings.load()
        self.magnifierSizeSlider.setValue(s.size)
        self.magnifierScaleSlider.setValue(s.scale)

        s = QSettings()
        s.beginGroup("musicview")
        newerFilesOnly = s.value("newer_files_only", True, bool)
        self.newerFilesOnly.setChecked(newerFilesOnly)
        kineticScrollingActive = s.value("kinetic_scrolling", True, bool)
        self.enableKineticScrolling.setChecked(kineticScrollingActive)
        showScrollbars = s.value("show_scrollbars", True, bool)
        self.showScrollbars.setChecked(showScrollbars)

    def saveSettings(self):
        s = popplerview.MagnifierSettings()
        s.size = self.magnifierSizeSlider.value()
        s.scale = self.magnifierScaleSlider.value()
        s.save()

        s = QSettings()
        s.beginGroup("musicview")
        s.setValue("newer_files_only", self.newerFilesOnly.isChecked())
        s.setValue("kinetic_scrolling",
                   self.enableKineticScrolling.isChecked())
        s.setValue("show_scrollbars", self.showScrollbars.isChecked())
Example #25
0
class QTSeedEditor(QDialog):
    """
    DICOM viewer.
    """
    @staticmethod
    def get_line(mode='h'):
        line = QFrame()
        if mode == 'h':
            line.setFrameStyle(QFrame.HLine)
        elif mode == 'v':
            line.setFrameStyle(QFrame.VLine)

        line.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        return line

    def initUI(self, shape, vscale, height=600,
               mode='seed'):
        """
        Initialize UI.

        Parameters
        ----------
        shape : (int, int, int)
            Shape of data matrix.
        vscale : (float, float, float)
            Voxel scaling.
        height : int
            Maximal slice height in pixels.
        mode : str
            Editor mode.
        """

        # picture
        grid = height / float(shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])
        self.slice_box = SliceBox(shape[:-1], mgrid,
                                  mode)
        self.slice_box.setScrollFun(self.scrollSlices)
        self.connect(self.slice_box, SIGNAL('focus_slider'), self.focusSliceSlider)

        # sliders
        self.allow_select_slice = True
        self.n_slices = shape[2]
        self.slider = QSlider(Qt.Vertical)
        self.slider.label = QLabel()
        self.slider.label.setText('Slice: %d / %d' % (self.actual_slice,
                                                      self.n_slices))
        self.slider.setRange(1, self.n_slices)
        self.slider.valueChanged.connect(self.sliderSelectSlice)
        self.slider.setValue(self.actual_slice)

        self.slider_cw = {}
        self.slider_cw['c'] = QSlider(Qt.Horizontal)
        self.slider_cw['c'].valueChanged.connect(self.changeC)
        self.slider_cw['c'].label = QLabel()

        self.slider_cw['w'] = QSlider(Qt.Horizontal)
        self.slider_cw['w'].valueChanged.connect(self.changeW)
        self.slider_cw['w'].label = QLabel()

        self.view_label = QLabel('View size: %d x %d' % self.img_aview.shape[:-1])
        self.voxel_label = QLabel('Voxel size [mm]:\n  %.2f x %.2f x %.2f'\
                                      % tuple(self.voxel_size[np.array(self.act_transposition)]))

        combo_view_options = VIEW_TABLE.keys()
        combo_view = QComboBox(self)
        combo_view.activated[str].connect(self.setView)
        combo_view.addItems(combo_view_options)

        # buttons
        self.btn_quit = QPushButton("Return", self)
        self.btn_quit.clicked.connect(self.quit)

        combo_dmask = QComboBox(self)
        combo_dmask.activated.connect(self.changeMask)
        self.mask_points_tab, aux = self.init_draw_mask(DRAW_MASK, mgrid)
        for icon, label in aux:
            combo_dmask.addItem(icon, label)


        self.slice_box.setMaskPoints(self.mask_points_tab[combo_dmask.currentIndex()])

        self.status_bar = QStatusBar()

        vopts = []
        vmenu = []
        appmenu = []
        if mode == 'seed' and self.mode_fun is not None:
            btn_recalc = QPushButton("Recalculate", self)
            btn_recalc.clicked.connect(self.recalculate)
            appmenu.append(QLabel('<b>Segmentation mode</b><br><br><br>' +
                                  'Select the region of interest<br>' +
                                  'using the mouse buttons:<br><br>' +
                                  '&nbsp;&nbsp;<i>left</i> - inner region<br>' +
                                  '&nbsp;&nbsp;<i>right</i> - outer region<br><br>'))
            appmenu.append(btn_recalc)
            appmenu.append(QLabel())
            self.volume_label = QLabel('Volume:\n  unknown')
            appmenu.append(self.volume_label)

            # Set middle pencil as default (M. Jirik)
            combo_dmask.setCurrentIndex(1)
            self.slice_box.setMaskPoints(
                self.mask_points_tab[combo_dmask.currentIndex()])
            #  -----mjirik---end------

        if mode == 'seed' or mode == 'crop'\
                or mode == 'mask' or mode == 'draw':
            btn_del = QPushButton("Delete Seeds", self)
            btn_del.clicked.connect(self.deleteSliceSeeds)
            vmenu.append(None)
            vmenu.append(btn_del)

            combo_contour_options = ['fill', 'contours', 'off']
            combo_contour = QComboBox(self)
            combo_contour.activated[str].connect(self.changeContourMode)
            combo_contour.addItems(combo_contour_options)
            self.changeContourMode(combo_contour_options[combo_contour.currentIndex()])
            vopts.append(QLabel('Selection mode:'))
            vopts.append(combo_contour)


        if mode == 'mask':
            btn_recalc_mask = QPushButton("Recalculate mask", self)
            btn_recalc_mask.clicked.connect(self.updateMaskRegion_btn)
            btn_all = QPushButton("Select all", self)
            btn_all.clicked.connect(self.maskSelectAll)
            btn_reset = QPushButton("Reset selection", self)
            btn_reset.clicked.connect(self.resetSelection)
            btn_reset_seads = QPushButton("Reset seads", self)
            btn_reset_seads.clicked.connect(self.resetSeads)
            btn_add = QPushButton("Add selection", self)
            btn_add.clicked.connect(self.maskAddSelection)
            btn_rem = QPushButton("Remove selection", self)
            btn_rem.clicked.connect(self.maskRemoveSelection)
            btn_mask = QPushButton("Mask region", self)
            btn_mask.clicked.connect(self.maskRegion)
            appmenu.append(QLabel('<b>Mask mode</b><br><br><br>' +
                                  'Select the region to mask<br>' +
                                  'using the left mouse button<br><br>'))
            appmenu.append(self.get_line('h'))
            appmenu.append(btn_recalc_mask)
            appmenu.append(btn_all)
            appmenu.append(btn_reset)
            appmenu.append(btn_reset_seads)
            appmenu.append(self.get_line('h'))
            appmenu.append(btn_add)
            appmenu.append(btn_rem)
            appmenu.append(self.get_line('h'))
            appmenu.append(btn_mask)
            appmenu.append(self.get_line('h'))
            self.mask_qhull = None

        if mode == 'crop':
            btn_crop = QPushButton("Crop", self)
            btn_crop.clicked.connect(self.crop)
            appmenu.append(QLabel('<b>Crop mode</b><br><br><br>' +
                                  'Select the crop region<br>' +
                                  'using the left mouse button<br><br>'))
            appmenu.append(btn_crop)

        if mode == 'draw':
            appmenu.append(QLabel('<b>Manual segmentation<br> mode</b><br><br><br>' +
                                  'Mark the region of interest<br>' +
                                  'using the mouse buttons:<br><br>' +
                                  '&nbsp;&nbsp;<i>left</i> - draw<br>' +
                                  '&nbsp;&nbsp;<i>right</i> - erase<br>' +
                                  '&nbsp;&nbsp;<i>middle</i> - vol. erase<br><br>'))

            btn_reset = QPushButton("Reset", self)
            btn_reset.clicked.connect(self.resetSliceDraw)
            vmenu.append(None)
            vmenu.append(btn_reset)

            combo_erase_options = ['inside', 'outside']
            combo_erase = QComboBox(self)
            combo_erase.activated[str].connect(self.changeEraseMode)
            combo_erase.addItems(combo_erase_options)
            self.changeEraseMode(combo_erase_options[combo_erase.currentIndex()])
            vopts.append(QLabel('Volume erase mode:'))
            vopts.append(combo_erase)

        hbox = QHBoxLayout()
        vbox = QVBoxLayout()
        vbox_left = QVBoxLayout()
        vbox_app = QVBoxLayout()

        hbox.addWidget(self.slice_box)
        hbox.addWidget(self.slider)
        vbox_left.addWidget(self.slider.label)
        vbox_left.addWidget(self.view_label)
        vbox_left.addWidget(self.voxel_label)
        vbox_left.addWidget(QLabel())
        vbox_left.addWidget(QLabel('View plane:'))
        vbox_left.addWidget(combo_view)
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(self.slider_cw['c'].label)
        vbox_left.addWidget(self.slider_cw['c'])
        vbox_left.addWidget(self.slider_cw['w'].label)
        vbox_left.addWidget(self.slider_cw['w'])
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(QLabel('Drawing mask:'))
        vbox_left.addWidget(combo_dmask)

        for ii in vopts:
            vbox_left.addWidget(ii)

        for ii in vmenu:
            if ii is None:
                vbox_left.addStretch(1)

            else:
                vbox_left.addWidget(ii)

        for ii in appmenu:
            if ii is None:
                vbox_app.addStretch(1)

            else:
                vbox_app.addWidget(ii)

        vbox_app.addStretch(1)
        vbox_app.addWidget(self.btn_quit)

        hbox.addLayout(vbox_left)
        hbox.addWidget(self.get_line('v'))
        hbox.addLayout(vbox_app)
        vbox.addLayout(hbox)
        vbox.addWidget(self.status_bar)
        self.my_layout = vbox
        self.setLayout(vbox)

        self.setWindowTitle('Segmentation Editor')
        self.show()

    def __init__(self, img, viewPositions=None,
                 seeds=None, contours=None,
                 mode='seed', modeFun=None,
                 voxelSize=[1,1,1], volume_unit='mm3'):
        """
        Initiate Editor

        Parameters
        ----------
        img : array
            DICOM data matrix.
        actualSlice : int
            Index of actual slice.
        seeds : array
            Seeds, user defined regions of interest.
        contours : array
            Computed segmentation.
        mode : str
            Editor modes:
               'seed' - seed editor
               'crop' - manual crop
               'draw' - drawing
               'mask' - mask region
        modeFun : fun
            Mode function invoked by user button.
        voxelSize : tuple of float
            voxel size [mm]
        volume_unit : allow select output volume in mililiters or mm3
            [mm, ml]
        """

        QDialog.__init__(self)

        self.mode = mode
        self.mode_fun = modeFun

        self.actual_view = 'axial'
        self.act_transposition = VIEW_TABLE[self.actual_view]
        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)

        self.volume_unit = volume_unit

        self.last_view_position = {}
        for jj, ii in enumerate(VIEW_TABLE.iterkeys()):
            if viewPositions is None:
                viewpos = img.shape[VIEW_TABLE[ii][-1]] / 2

            else:
                viewpos = viewPositions[jj]

            self.last_view_position[ii] =\
                img.shape[VIEW_TABLE[ii][-1]] - viewpos - 1

        self.actual_slice = self.last_view_position[self.actual_view]

        # set contours
        self.contours = contours
        if self.contours is None:
            self.contours_aview = None
        else:
            self.contours_aview = self.contours.transpose(self.act_transposition)

        # masked data - has information about which data were removed
        # 1 == enabled, 0 == deleted
        # How to return:
        #       editorDialog.exec_()
        #       masked_data = editorDialog.masked
        self.masked = np.ones(self.img.shape, np.int8)

        self.voxel_size = np.squeeze(np.asarray(voxelSize))
        self.voxel_scale = self.voxel_size / float(np.min(self.voxel_size))
        self.voxel_volume = np.prod(voxelSize)

        # set seeds
        if seeds is None:
            self.seeds = np.zeros(self.img.shape, np.int8)

        else:
            self.seeds = seeds

        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        self.initUI(self.img_aview.shape,
                    self.voxel_scale[np.array(self.act_transposition)],
                    600, mode)

        if mode == 'draw':
            self.seeds_orig = self.seeds.copy()
            self.slice_box.setEraseFun(self.eraseVolume)

        # set view window values C/W
        lb = np.min(img)
        self.img_min_val = lb
        ub = np.max(img)
        dul = np.double(ub) - np.double(lb)
        self.cw_range = {'c': [lb, ub], 'w': [1, dul]}
        self.slider_cw['c'].setRange(lb, ub)
        self.slider_cw['w'].setRange(1, dul)
        self.changeC(lb + dul / 2)
        self.changeW(dul)

        self.offset = np.zeros((3,), dtype=np.int16)

    def showStatus(self, msg):
        self.status_bar.showMessage(QString(msg))
        QApplication.processEvents()

    def init_draw_mask(self, draw_mask, grid):
        mask_points = []
        mask_iconlabel = []
        for mask, label in draw_mask:
            w, h = mask.shape
            xx, yy = mask.nonzero()
            mask_points.append((xx - w/2, yy - h/2))

            img = QImage(w, h, QImage.Format_ARGB32)
            img.fill(qRgba(255, 255, 255, 0))
            for ii in range(xx.shape[0]):
                img.setPixel(xx[ii], yy[ii], qRgba(0, 0, 0, 255))

            img = img.scaled(QSize(w * grid[0], h * grid[1]))
            icon = QIcon(QPixmap.fromImage(img))
            mask_iconlabel.append((icon, label))

        return mask_points, mask_iconlabel

    def saveSliceSeeds(self):
        aux = self.slice_box.getSliceSeeds()
        if aux is not None:
            self.seeds_aview[...,self.actual_slice] = aux
            self.seeds_modified = True

        else:
            self.seeds_modified = False

    def updateMaskRegion_btn(self):
        self.saveSliceSeeds()
        self.updateMaskRegion()

    def updateMaskRegion(self):
        crp = self.getCropBounds(return_nzs=True)
        if crp is not None:
            off, cri, nzs = crp
            if nzs[0].shape[0] <=5:
                self.showStatus("Not enough points (need >= 5)!")

            else:
                points = np.transpose(nzs)
                hull = Delaunay(points)
                X, Y, Z = np.mgrid[cri[0], cri[1], cri[2]]
                grid = np.vstack([X.ravel(), Y.ravel(), Z.ravel()]).T
                simplex = hull.find_simplex(grid)
                fill = grid[simplex >=0,:]
                fill = (fill[:,0], fill[:,1], fill[:,2])
                if self.contours is None or self.contours_old is None:
                    self.contours = np.zeros(self.img.shape, np.int8)
                    self.contours_old = self.contours.copy()
                else:
                    self.contours[self.contours != 2] = 0
                self.contours[fill] = 1
                self.contours_aview = self.contours.transpose(self.act_transposition)

                self.selectSlice(self.actual_slice)

    def maskRegion(self):
        self.masked[self.contours == 0] = 0

        self.img[self.contours != 2] = self.img_min_val
        self.contours.fill(0)
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def maskAddSelection(self):
        self.updateMaskRegion()
        if self.contours is None:
            return

        self.contours[self.contours == 1] = 2
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def maskRemoveSelection(self):
        self.updateMaskRegion()
        if self.contours is None:
            return

        self.contours[self.contours == 1] = 0
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def maskSelectAll(self):
        self.updateMaskRegion()

        self.seeds[0][0][0] = 1
        self.seeds[0][0][-1] = 1
        self.seeds[0][-1][0] = 1
        self.seeds[0][-1][-1] = 1
        self.seeds[-1][0][0] = 1
        self.seeds[-1][0][-1] = 1
        self.seeds[-1][-1][0] = 1
        self.seeds[-1][-1][-1] = 1

        self.updateMaskRegion()
        self.selectSlice(self.actual_slice)

    def resetSelection(self):
        self.updateMaskRegion()
        if self.contours is None:
            return

        self.contours.fill(0)
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def resetSeads(self):
        self.seeds.fill(0)
        if self.contours is not None:
            self.contours = self.contours_old.copy()
            self.contours_aview = self.contours.transpose(self.act_transposition)
        self.updateMaskRegion()
        self.selectSlice(self.actual_slice)

    def updateCropBounds(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp
            self.contours = np.zeros(self.img.shape, np.int8)
            self.contours[cri].fill(1)
            self.contours_aview = self.contours.transpose(self.act_transposition)

    def focusSliceSlider(self):
        self.slider.setFocus(True)

    def sliderSelectSlice(self, value):
        self.selectSlice(self.n_slices - value)

    def scrollSlices(self, inc):
        if abs(inc) > 0:
            new = self.actual_slice + inc
            self.selectSlice(new)

    def selectSlice(self, value, force=False):
        if not(self.allow_select_slice):
            return

        if (value < 0) or (value >= self.n_slices):
            return

        if (value != self.actual_slice) or force:
            self.saveSliceSeeds()
            if self.seeds_modified:
                if self.mode == 'crop':
                    self.updateCropBounds()

                elif self.mode == 'mask':
                    self.updateMaskRegion()

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[...,value]

        slider_val = self.n_slices - value
        self.slider.setValue(slider_val)
        self.slider.label.setText('Slice: %d / %d' % (slider_val, self.n_slices))

        self.slice_box.setSlice(self.img_aview[...,value],
                                self.seeds_aview[...,value],
                                contours)
        self.actual_slice = value

    def getSeeds(self):
        return self.seeds

    def getImg(self):
        return self.img

    def getOffset(self):
        return self.offset * self.voxel_size

    def getSeedsVal(self, label):
        return self.img[self.seeds==label]

    def getContours(self):
        return self.contours

    def setContours(self, contours):
        self.contours = contours
        self.contours_aview = self.contours.transpose(self.act_transposition)

        self.selectSlice(self.actual_slice)

    def changeCW(self, value, key):
        rg = self.cw_range[key]
        if (value < rg[0]) or (value > rg[1]):
            return

        if (value != self.slice_box.getCW()[key]):
            self.slider_cw[key].setValue(value)
            self.slider_cw[key].label.setText('%s: %d' % (key.upper(), value))
            self.slice_box.setCW(value, key)
            self.slice_box.updateSliceCW(self.img_aview[...,self.actual_slice])


    def changeC(self, value):
        self.changeCW(value, 'c')

    def changeW(self, value):
        self.changeCW(value, 'w')

    def setView(self, value):
        self.last_view_position[self.actual_view] = self.actual_slice
        # save seeds
        self.saveSliceSeeds()
        if self.seeds_modified:
            if self.mode == 'crop':
                self.updateCropBounds()

            elif self.mode == 'mask':
                self.updateMaskRegion()

        key = str(value)
        self.actual_view = key
        self.actual_slice = self.last_view_position[key]

        self.act_transposition = VIEW_TABLE[key]
        self.img_aview = self.img.transpose(self.act_transposition)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)

        if self.contours is not None:
            self.contours_aview = self.contours.transpose(self.act_transposition)
            contours = self.contours_aview[...,self.actual_slice]

        else:
            contours = None

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        # width = (self.img_aview.shape[0] * vscale[0])[0]
        # if width > 800:
        #     height = 400
        #     grid = height / float(self.img_aview.shape[1] * vscale[1])

        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[...,self.actual_slice],
                                self.seeds_aview[...,self.actual_slice],
                                contours)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        slider_val = self.n_slices - self.actual_slice
        self.slider.setRange(1, self.n_slices)
        self.slider.setValue(slider_val)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' % (slider_val,
                                                      self.n_slices))
        self.view_label.setText('View size: %d x %d' % self.img_aview.shape[:-1])

        self.adjustSize()
        self.adjustSize()

    def changeMask(self, val):
        self.slice_box.setMaskPoints(self.mask_points_tab[val])

    def changeContourMode(self, val):
        self.slice_box.contour_mode = str(val)
        self.slice_box.updateSlice()

    def changeEraseMode(self, val):
        self.slice_box.erase_mode = str(val)

    def eraseVolume(self, pos, mode):
        self.showStatus("Processing...")
        xyz = np.array(pos + (self.actual_slice,))
        p = np.zeros_like(xyz)
        p[np.array(self.act_transposition)] = xyz
        p = tuple(p)

        if self.seeds[p] > 0:
            if mode == 'inside':
                erase_reg(self.seeds, p, val=0)

            elif mode == 'outside':
                erase_reg(self.seeds, p, val=-1)
                idxs = np.where(self.seeds < 0)
                self.seeds.fill(0)
                self.seeds[idxs] = 1

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[...,self.actual_slice]

        self.slice_box.setSlice(self.img_aview[...,self.actual_slice],
                                self.seeds_aview[...,self.actual_slice],
                                contours)

        self.showStatus("Done")

    def cropUpdate(self, img):

        for ii in VIEW_TABLE.iterkeys():
            self.last_view_position[ii] = 0
        self.actual_slice = 0

        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)

        self.contours = None
        self.contours_aview = None

        self.seeds = np.zeros(self.img.shape, np.int8)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[...,self.actual_slice],
                                self.seeds_aview[...,self.actual_slice],
                                None)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        self.slider.setValue(self.actual_slice + 1)
        self.slider.setRange(1, self.n_slices)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' % (self.actual_slice + 1,
                                                      self.n_slices))
        self.view_label.setText('View size: %d x %d' % self.img_aview.shape[:-1])

    def getCropBounds(self, return_nzs=False, flat=False):

        nzs = self.seeds.nonzero()
        cri = []
        flag = True
        for ii in range(3):
            if nzs[ii].shape[0] == 0:
                flag = False
                break

            smin, smax = np.min(nzs[ii]), np.max(nzs[ii])
            if not(flat):
                if smin == smax:
                    flag = False
                    break

            cri.append((smin, smax))

        if flag:
            cri = np.array(cri)

            out = []
            offset = []
            for jj, ii in enumerate(cri):
                out.append(slice(ii[0], ii[1] + 1))
                offset.append(ii[0])

            if return_nzs:
                return np.array(offset), tuple(out), nzs

            else:
                return np.array(offset), tuple(out)

        else:
            return None

    def crop(self):
        self.showStatus("Processing...")

        crp = self.getCropBounds()

        if crp is not None:
            offset, cri = crp
            crop = self.img[cri]
            self.img = np.ascontiguousarray(crop)
            self.offset += offset


            self.showStatus('Done')

        else:
            self.showStatus('Region not selected!')

        self.cropUpdate(self.img)

    def recalculate(self, event):
        self.saveSliceSeeds()
        if np.abs(np.min(self.seeds) - np.max(self.seeds)) < 2:
            self.showStatus('Inner and outer regions not defined!')
            return

        self.showStatus("Processing...")
        self.mode_fun(self)
        self.selectSlice(self.actual_slice)
        self.updateVolume()
        self.showStatus("Done")

    def deleteSliceSeeds(self, event):
        self.seeds_aview[...,self.actual_slice] = 0
        self.slice_box.setSlice(seeds=self.seeds_aview[...,self.actual_slice])
        self.slice_box.updateSlice()

    def resetSliceDraw(self, event):
        seeds_orig_aview = self.seeds_orig.transpose(self.act_transposition)
        self.seeds_aview[...,self.actual_slice] = seeds_orig_aview[...,self.actual_slice]
        self.slice_box.setSlice(seeds=self.seeds_aview[...,self.actual_slice])
        self.slice_box.updateSlice()

    def quit(self, event):
        self.close()

    def updateVolume(self):
        text = 'Volume:\n  unknown'
        if self.voxel_volume is not None:
            if self.mode == 'draw':
                vd = self.seeds

            else:
                vd = self.contours

            if vd is not None:
                nzs = vd.nonzero()
                nn = nzs[0].shape[0]
                if self.volume_unit == 'ml':
                    text = 'Volume [ml]:\n  %.2f' %\
                        (nn * self.voxel_volume / 1000)
                else:
                    text = 'Volume [mm3]:\n  %.2e' % (nn * self.voxel_volume)

        self.volume_label.setText(text)

    def getROI(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp

        else:
            cri = []
            for jj, ii in enumerate(self.img.shape):
                off = self.offset[jj]
                cri.append(slice(off, off + ii))

        return cri
Example #26
0
class SoundLabWindow(QtGui.QMainWindow):
    """
    Window that encapsulates the commonly operations with a
    sound lab window that contains a widget (QSignalVisualizer or descendant).
    provides usefull operations that delegates into the widget its implementation
    """

    # region Initialize

    def __init__(self, parent):
        QtGui.QMainWindow.__init__(self, parent)

        self.workSpace = Workspace()

        #  get the status bar to show messages to the user
        self.statusbar = self.statusBar()
        self.statusbar.setSizeGripEnabled(False)

        # action groups of common actions for sound lab window
        self.play_record_actions        = QActionGroup(self)
        self.widgets_visibility_actions = QActionGroup(self)
        self.zoom_actions               = QActionGroup(self)
        self.tools_actions              = QActionGroup(self)
        self.save_images_actions        = QActionGroup(self)

        # play volume bar (disabled for now)
        self.volume_bar = QSlider(QtCore.Qt.Horizontal)
        self.volume_bar.setToolTip(self.tr(u"Volume bar for Play."))
        self.volume_bar.setMaximumWidth(100)
        self.volume_bar.setRange(0, 300)
        self.volume_bar.setValue(100)
        self.volume_bar.valueChanged.connect(self.change_volume)

        # text edit for the signal name on the toolbar
        self.signalNameLineEdit = QtGui.QLineEdit(self)
        self.signalNameLineEdit.setToolTip(self.tr(u"Signal name."))
        self.signalNameLineEdit.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Minimum))

        self.signalPropertiesTextLabel = QtGui.QLabel(self)
        self.signalPropertiesTextLabel.setToolTip(self.tr(u"Signal properties."))
        self.signalPropertiesTextLabel.setAlignment(QtCore.Qt.AlignRight)
        self.signalPropertiesTextLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                                                       QtGui.QSizePolicy.Minimum))

    # endregion

    def configureToolBarActionsGroups(self):
        """
        Configure the actions into groups for best visualization and
        user configuration.
        :return:
        """
        sep1, sep2, sep3, sep4 = [QtGui.QAction(self) for _ in range(4)]

        for sep in [sep1, sep2, sep3, sep4]:
            sep.setSeparator(True)

        # region play record actions
        play_record_actions_list = [self.actionPlay_Sound, self.actionPause_Sound, self.actionStop_Sound,
                                    self.actionRecord, self.actionPlayLoop, sep2]
        for act in play_record_actions_list:
            act.setActionGroup(self.play_record_actions)

        # self.toolBar.addWidget(self.volume_bar)

        # endregion

        # region widgets visibility actions
        widgets_visibility_actions_list = [self.actionOscilogram, self.actionSpectogram, self.actionCombined,
                                           sep3]

        for act in widgets_visibility_actions_list:
            act.setActionGroup(self.widgets_visibility_actions)
        # endregion

        # region zoom actions
        zoom_actions_list = [self.actionZoomIn, self.actionZoom_out,
                             self.actionZoom_out_entire_file, sep4]

        for act in zoom_actions_list:
            act.setActionGroup(self.zoom_actions)

        # endregion

        # region Save Images actions
        save_images_actions_list = [self.actionOsc_Image, self.actionSpecgram_Image,
                                    self.actionCombined_Image]

        for act in save_images_actions_list:
            act.setActionGroup(self.save_images_actions)
        # endregion

        # region Tools actions
        tools_actions_list = [self.actionZoom_Cursor, self.actionPointer_Cursor,
                              self.actionRectangular_Cursor]

        for act in tools_actions_list:
            act.setActionGroup(self.tools_actions)
        # endregion

        actions_groups = [(self.play_record_actions, self.tr(u"Play/Record")),
                          (self.zoom_actions, self.tr(u"Zoom")),
                          (self.widgets_visibility_actions, self.tr(u"Widgets Visibility"))]

        # add to the customizable sound lab toolbar
        for act in actions_groups:
            # method sig addActionGroup(actionGroup, name)
            self.toolBar.addActionGroup(act[0], act[1])

        # add the label for signal name (and edit line) that always wil be visible as an option
        # not like the other groups of actions that the user could customize visibility
        self.toolBar.addWidget(self.signalNameLineEdit)
        self.toolBar.addAction(sep1)
        self.toolBar.addWidget(self.signalPropertiesTextLabel)

    #  region Widget Tools
    @pyqtSlot()
    def on_actionZoom_Cursor_triggered(self):
        """
        Select the Zoom Tool as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionZoom_Cursor, Tools.ZoomTool)

    @pyqtSlot()
    def on_actionRectangular_Cursor_triggered(self):
        """
        Select the Rectangular Cursor as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionRectangular_Cursor, Tools.RectangularZoomTool)

    @pyqtSlot()
    def on_actionRectangular_Eraser_triggered(self):
        """
        Select the Rectangular Eraser as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionRectangular_Eraser, Tools.RectangularEraser)

    @pyqtSlot()
    def on_actionPointer_Cursor_triggered(self):
        """
        Select the Pointer Cursor as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionPointer_Cursor, Tools.PointerTool)

    def deselectToolsActions(self):
        """
        Change the checked status of all the actions tools to False
        """
        self.actionZoom_Cursor.setChecked(False)
        self.actionRectangular_Cursor.setChecked(False)
        self.actionPointer_Cursor.setChecked(False)

    def select_tool(self, tool_action, tool_type):
        """

        :param tool_action: the checkable action that handles the selection of the tool
        :param tool_type: the enum type of the tool to select in the widget
        :return:
        """
        self.deselectToolsActions()
        tool_action.setChecked(True)
        self.widget.setSelectedTool(tool_type)

    #  endregion

    #  region Save widgets Image

    @pyqtSlot()
    def on_actionOsc_Image_triggered(self):
        """
        Save to disc the image of the oscilogram graph.
        :return:
        """
        if not self.widget.visibleOscilogram:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"The Oscilogram plot widget is not visible.") + u"\n" + self.tr(
                                          u"You should see the data that you are going to save."))
            return

        fname = unicode(QFileDialog.getSaveFileName(self, self.tr(u"Save oscilogram graph as an Image"),
                                                u"oscilogram-Duetto-Image", u"*.jpg"))

        if fname:
            save_image(self.widget.axesOscilogram, fname)

    @pyqtSlot()
    def on_actionSpecgram_Image_triggered(self):
        """
        Save to disc the image of the spectrogram graph.
        :return:
        """
        if not self.widget.visibleSpectrogram:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"The Spectrogram plot widget is not visible.") + " \n" + self.tr(
                                          u"You should see the data that you are going to save."))
            return

        path = unicode(QFileDialog.getSaveFileName(self, self.tr(u"Save specgram graph as an Image"),
                                                    u"specgram-Duetto-Image", u"*.jpg"))
        save_image(self.widget.axesSpecgram, path)

    @pyqtSlot()
    def on_actionCombined_Image_triggered(self):
        """
        Save to disc the image of the both (oscilogram and spectrogram)
        visualization graphs.
        :return:
        """
        if not self.widget.visibleOscilogram or not self.widget.visibleSpectrogram:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"One of the plot widgets is not visible.") + " \n" + self.tr(
                                          u"You should see the data that you are going to save."))
            return

        path = unicode(QFileDialog.getSaveFileName(self, self.tr(u"Save graph as an Image"), u"Graph Image", u"*.jpg"))
        save_image(self.widget, path)

    #  endregion

    # region Zoom
    # delegate in the widget the zoom interaction with the signal
    @QtCore.pyqtSlot()
    def on_actionZoomIn_triggered(self):
        self.widget.zoomIn()

    @QtCore.pyqtSlot()
    def on_actionZoom_out_triggered(self):
        self.widget.zoomOut()

    @QtCore.pyqtSlot()
    def on_actionZoom_out_entire_file_triggered(self):
        self.widget.zoomNone()

    # endregion

    #  region Widgets And Window Visibility

    @pyqtSlot()
    def on_actionFull_Screen_triggered(self):
        """
        Action that switch the window visualization state between
        Full Screen and Normal
        :return:
        """
        if self.actionFull_Screen.isChecked():
            self.showFullScreen()
        else:
            self.showNormal()

    @pyqtSlot()
    def on_actionCombined_triggered(self):
        """
        Shows both axes visualization oscilogram and spectrogram.
        :return:
        """
        self.changeWidgetsVisibility(True, True)

    @pyqtSlot()
    def on_actionSpectogram_triggered(self):
        """
        Shows the spectrogram visualization graph only.
        :return:
        """
        self.changeWidgetsVisibility(False, True)

    @pyqtSlot()
    def on_actionOscilogram_triggered(self):
        """
        Shows the oscilogram visualization graph only.
        :return:
        """
        self.changeWidgetsVisibility(True, False)

    def changeWidgetsVisibility(self, visibleOscilogram=True, visibleSpectrogram=True):
        """
        Method that change the visibility of the widgets
        oscilogram and spectrogram on the main widget
        :param visibleOscilogram:  Visibility of the oscilogram
        :param visibleSpectrogram: Visibility of the spectrogram
        :return:
        """
        self.widget.visibleOscilogram = visibleOscilogram
        self.widget.visibleSpectrogram = visibleSpectrogram

        # udpate the workspace
        self.workSpace.visibleOscilogram = visibleOscilogram
        self.workSpace.visibleSpectrogram = visibleSpectrogram

        self.widget.graph()

    # endregion

    #  region Play, Pause, Stop, Record
    # delegate in the widget reproduction actions
    def change_volume(self, volume):
        # change volume in the player of the widget
        if self.widget:
            self.widget.change_volume(volume)

        self.update_status_bar(self.tr(u"The volume has been changed to "+unicode(volume) + u"%."), 1000)

    @pyqtSlot()
    def on_actionPlay_Sound_triggered(self):
        try:
            self.widget.play()

        except Exception as ex:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"There is no selected audio input "
                                              u"device or the selected is unavailable"))

    @pyqtSlot()
    def on_actionPlayLoop_triggered(self):
        self.widget.setPlayLoopEnabled(self.actionPlayLoop.isChecked())

    @pyqtSlot()
    def on_actionStop_Sound_triggered(self):
        self.widget.stop()

        # if previous status was recording the length of signal has changed and must be updated
        self.updateSignalPropertiesLabel()

    @pyqtSlot()
    def on_actionPause_Sound_triggered(self):
        self.widget.pause()

    @pyqtSlot()
    def on_actionSwitchPlayStatus_triggered(self):
        """
        Change the play status of the signal from play-pause and vice versa
        :return:
        """
        self.widget.switchPlayStatus()

    # endregion

    # region Edition and Processing Methods

    # region Undo Redo

    @pyqtSlot()
    def on_actionUndo_triggered(self):
        self.widget.undo()
        self.updateSignalPropertiesLabel()

    @pyqtSlot()
    def on_actionRedo_triggered(self):
        self.widget.redo()
        self.updateSignalPropertiesLabel()

    # endregion

    #  region Cut, Copy, Paste
    @pyqtSlot()
    def on_actionCut_triggered(self):
        self.widget.cut()
        self.updateSignalPropertiesLabel()

    @pyqtSlot()
    def on_actionCopy_triggered(self):
        self.widget.copy()

    @pyqtSlot()
    def on_actionPaste_triggered(self):
        self.widget.paste()
        self.updateSignalPropertiesLabel()

    #  endregion

    # endregion

    def update_status_bar(self, line, time_ms=None):
        """
        Set a new message in the status bar of the window.
        :type time: the time that the line message wouold be visible in status bar.
        :param line: string with the line to show in the status bar
        """
        time_ms = 1500 if time_ms is None else time_ms

        self.statusbar.showMessage(line, time_ms)

    def updateSignalPropertiesLabel(self, signal = None):
        """
        Updates the text of the current signal properties in toolbar.
        :return:
        """
        signal = self.widget.signal if signal is None else signal

        # action signal is a place in the tool bar to show the current signal name
        self.signalNameLineEdit.setText(signal.name)

        sr, bit_depth, channels = signal.samplingRate, signal.bitDepth, signal.channelCount

        properties = u"    " + \
                     u" <b>" + self.tr(u"Sampling Rate: ") + u"</b>" + unicode(sr) + u"  " + \
                     u" <b>" + self.tr(u"Bit Depth: ") + u"</b>" + unicode(bit_depth) + u"  " + \
                     u" <b>" + self.tr(u"Channels: ") + u"</b>" + unicode(channels) + u"  " + \
                     u" <b>" + self.tr(u"Duration(s): ") + u"</b>" + unicode(round(signal.duration, DECIMAL_PLACES)) + \
                     u"    "

        self.signalPropertiesTextLabel.setText(properties)
Example #27
0
class QTSeedEditor(QDialog):
    """
    DICOM viewer.
    """
    @staticmethod
    def get_line(mode='h'):
        line = QFrame()
        if mode == 'h':
            line.setFrameStyle(QFrame.HLine)
        elif mode == 'v':
            line.setFrameStyle(QFrame.VLine)

        line.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        return line

    def initUI(self, shape, vscale, height=600, mode='seed'):
        """
        Initialize UI.

        Parameters
        ----------
        shape : (int, int, int)
            Shape of data matrix.
        vscale : (float, float, float)
            Voxel scaling.
        height : int
            Maximal slice height in pixels.
        mode : str
            Editor mode.
        """

        # picture
        grid = height / float(shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])
        self.slice_box = SliceBox(shape[:-1], mgrid, mode)
        self.slice_box.setScrollFun(self.scrollSlices)
        self.connect(self.slice_box, SIGNAL('focus_slider'),
                     self.focusSliceSlider)

        # sliders
        self.allow_select_slice = True
        self.n_slices = shape[2]
        self.slider = QSlider(Qt.Vertical)
        self.slider.label = QLabel()
        self.slider.label.setText('Slice: %d / %d' %
                                  (self.actual_slice, self.n_slices))
        self.slider.setRange(1, self.n_slices)
        self.slider.valueChanged.connect(self.sliderSelectSlice)
        self.slider.setValue(self.actual_slice)

        self.slider_cw = {}
        self.slider_cw['c'] = QSlider(Qt.Horizontal)
        self.slider_cw['c'].valueChanged.connect(self.changeC)
        self.slider_cw['c'].label = QLabel()

        self.slider_cw['w'] = QSlider(Qt.Horizontal)
        self.slider_cw['w'].valueChanged.connect(self.changeW)
        self.slider_cw['w'].label = QLabel()

        self.view_label = QLabel('View size: %d x %d' %
                                 self.img_aview.shape[:-1])
        self.voxel_label = QLabel('Voxel size [mm]:\n  %.2f x %.2f x %.2f'\
                                      % tuple(self.voxel_size[np.array(self.act_transposition)]))

        combo_view_options = VIEW_TABLE.keys()
        combo_view = QComboBox(self)
        combo_view.activated[str].connect(self.setView)
        combo_view.addItems(combo_view_options)

        # buttons
        self.btn_quit = QPushButton("Return", self)
        self.btn_quit.clicked.connect(self.quit)

        combo_dmask = QComboBox(self)
        combo_dmask.activated.connect(self.changeMask)
        self.mask_points_tab, aux = self.init_draw_mask(DRAW_MASK, mgrid)
        for icon, label in aux:
            combo_dmask.addItem(icon, label)

        self.slice_box.setMaskPoints(
            self.mask_points_tab[combo_dmask.currentIndex()])

        self.status_bar = QStatusBar()

        self.seeds_copy = None
        vopts = []
        vmenu = []
        appmenu = []
        if mode == 'seed' and self.mode_fun is not None:
            btn_recalc = QPushButton("Recalculate", self)
            btn_recalc.clicked.connect(self.recalculate)
            self.btn_save = QPushButton("Save seeds", self)
            self.btn_save.clicked.connect(self.saveload_seeds)
            btn_s2b = QPushButton("Seg. to bckgr.", self)
            btn_s2b.clicked.connect(self.seg_to_background_seeds)
            btn_s2f = QPushButton("Seg. to forgr.", self)
            btn_s2f.clicked.connect(self.seg_to_foreground_seeds)
            appmenu.append(
                QLabel('<b>Segmentation mode</b><br><br><br>' +
                       'Select the region of interest<br>' +
                       'using the mouse buttons:<br><br>' +
                       '&nbsp;&nbsp;<i>left</i> - inner region<br>' +
                       '&nbsp;&nbsp;<i>right</i> - outer region<br><br>'))
            appmenu.append(btn_recalc)
            appmenu.append(self.btn_save)
            appmenu.append(btn_s2f)
            appmenu.append(btn_s2b)
            appmenu.append(QLabel())
            self.volume_label = QLabel('Volume:\n  unknown')
            appmenu.append(self.volume_label)

            # Set middle pencil as default (M. Jirik)
            combo_dmask.setCurrentIndex(1)
            self.slice_box.setMaskPoints(
                self.mask_points_tab[combo_dmask.currentIndex()])
            #  -----mjirik---end------

        if mode == 'seed' or mode == 'crop'\
                or mode == 'mask' or mode == 'draw':

            combo_seed_label_options = ['all', '1', '2', '3', '4']
            combo_seed_label = QComboBox(self)
            combo_seed_label.activated[str].connect(self.changeFocusedLabel)
            combo_seed_label.addItems(combo_seed_label_options)
            self.changeFocusedLabel(
                combo_seed_label_options[combo_seed_label.currentIndex()])
            # vopts.append(QLabel('Label to delete:'))
            # vopts.append(combo_seed_label)
            vmenu.append(QLabel('Label to delete:'))
            vmenu.append(combo_seed_label)

            btn_del = QPushButton("Del Slice Seeds", self)
            btn_del.clicked.connect(self.deleteSliceSeeds)
            vmenu.append(None)
            vmenu.append(btn_del)
            btn_del = QPushButton("Del All Seeds", self)
            btn_del.clicked.connect(self.deleteSeedsInAllImage)
            vmenu.append(None)
            vmenu.append(btn_del)

            combo_contour_options = ['fill', 'contours', 'off']
            combo_contour = QComboBox(self)
            combo_contour.activated[str].connect(self.changeContourMode)
            combo_contour.addItems(combo_contour_options)
            self.changeContourMode(
                combo_contour_options[combo_contour.currentIndex()])
            vopts.append(QLabel('Selection mode:'))
            vopts.append(combo_contour)

        if mode == 'mask':
            btn_recalc_mask = QPushButton("Recalculate mask", self)
            btn_recalc_mask.clicked.connect(self.updateMaskRegion_btn)
            btn_all = QPushButton("Select all", self)
            btn_all.clicked.connect(self.maskSelectAll)
            btn_reset = QPushButton("Reset selection", self)
            btn_reset.clicked.connect(self.resetSelection)
            btn_reset_seads = QPushButton("Reset seads", self)
            btn_reset_seads.clicked.connect(self.resetSeads)
            btn_add = QPushButton("Add selection", self)
            btn_add.clicked.connect(self.maskAddSelection)
            btn_rem = QPushButton("Remove selection", self)
            btn_rem.clicked.connect(self.maskRemoveSelection)
            btn_mask = QPushButton("Mask region", self)
            btn_mask.clicked.connect(self.maskRegion)
            appmenu.append(
                QLabel('<b>Mask mode</b><br><br><br>' +
                       'Select the region to mask<br>' +
                       'using the left mouse button<br><br>'))
            appmenu.append(self.get_line('h'))
            appmenu.append(btn_recalc_mask)
            appmenu.append(btn_all)
            appmenu.append(btn_reset)
            appmenu.append(btn_reset_seads)
            appmenu.append(self.get_line('h'))
            appmenu.append(btn_add)
            appmenu.append(btn_rem)
            appmenu.append(self.get_line('h'))
            appmenu.append(btn_mask)
            appmenu.append(self.get_line('h'))
            self.mask_qhull = None

        if mode == 'crop':
            btn_crop = QPushButton("Crop", self)
            btn_crop.clicked.connect(self.crop)
            appmenu.append(
                QLabel('<b>Crop mode</b><br><br><br>' +
                       'Select the crop region<br>' +
                       'using the left mouse button<br><br>'))
            appmenu.append(btn_crop)

        if mode == 'draw':
            appmenu.append(
                QLabel('<b>Manual segmentation<br> mode</b><br><br><br>' +
                       'Mark the region of interest<br>' +
                       'using the mouse buttons:<br><br>' +
                       '&nbsp;&nbsp;<i>left</i> - draw<br>' +
                       '&nbsp;&nbsp;<i>right</i> - erase<br>' +
                       '&nbsp;&nbsp;<i>middle</i> - vol. erase<br><br>'))

            btn_reset = QPushButton("Reset", self)
            btn_reset.clicked.connect(self.resetSliceDraw)
            vmenu.append(None)
            vmenu.append(btn_reset)

            combo_erase_options = ['inside', 'outside']
            combo_erase = QComboBox(self)
            combo_erase.activated[str].connect(self.changeEraseMode)
            combo_erase.addItems(combo_erase_options)
            self.changeEraseMode(
                combo_erase_options[combo_erase.currentIndex()])
            vopts.append(QLabel('Volume erase mode:'))
            vopts.append(combo_erase)

        hbox = QHBoxLayout()
        vbox = QVBoxLayout()
        vbox_left = QVBoxLayout()
        vbox_app = QVBoxLayout()

        hbox.addWidget(self.slice_box)
        hbox.addWidget(self.slider)
        vbox_left.addWidget(self.slider.label)
        vbox_left.addWidget(self.view_label)
        vbox_left.addWidget(self.voxel_label)
        vbox_left.addWidget(QLabel())
        vbox_left.addWidget(QLabel('View plane:'))
        vbox_left.addWidget(combo_view)
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(self.slider_cw['c'].label)
        vbox_left.addWidget(self.slider_cw['c'])
        vbox_left.addWidget(self.slider_cw['w'].label)
        vbox_left.addWidget(self.slider_cw['w'])
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(QLabel('Drawing mask:'))
        vbox_left.addWidget(combo_dmask)

        for ii in vopts:
            vbox_left.addWidget(ii)

        for ii in vmenu:
            if ii is None:
                vbox_left.addStretch(1)

            else:
                vbox_left.addWidget(ii)

        for ii in appmenu:
            if ii is None:
                vbox_app.addStretch(1)

            else:
                vbox_app.addWidget(ii)

        vbox_app.addStretch(1)
        vbox_app.addWidget(self.btn_quit)

        hbox.addLayout(vbox_left)
        hbox.addWidget(self.get_line('v'))
        hbox.addLayout(vbox_app)
        vbox.addLayout(hbox)
        vbox.addWidget(self.status_bar)
        self.my_layout = vbox
        self.setLayout(vbox)

        self.setWindowTitle('Segmentation Editor')
        self.show()

    def __init__(self,
                 img,
                 viewPositions=None,
                 seeds=None,
                 contours=None,
                 mode='seed',
                 modeFun=None,
                 voxelSize=[1, 1, 1],
                 volume_unit='mm3'):
        """
        Initiate Editor

        Parameters
        ----------
        img : array
            DICOM data matrix.
        actualSlice : int
            Index of actual slice.
        seeds : array
            Seeds, user defined regions of interest.
        contours : array
            Computed segmentation.
        mode : str
            Editor modes:
               'seed' - seed editor
               'crop' - manual crop
               'draw' - drawing
               'mask' - mask region
        modeFun : fun
            Mode function invoked by user button.
        voxelSize : tuple of float
            voxel size [mm]
        volume_unit : allow select output volume in mililiters or mm3
            [mm, ml]
        """

        QDialog.__init__(self)

        self.BACKGROUND_NOMODEL_SEED_LABEL = 4
        self.FOREGROUND_NOMODEL_SEED_LABEL = 3

        self.mode = mode
        self.mode_fun = modeFun

        self.actual_view = 'axial'
        self.act_transposition = VIEW_TABLE[self.actual_view]
        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)

        self.volume_unit = volume_unit

        self.last_view_position = {}
        for jj, ii in enumerate(VIEW_TABLE.keys()):
            if viewPositions is None:
                viewpos = img.shape[VIEW_TABLE[ii][-1]] / 2

            else:
                viewpos = viewPositions[jj]

            self.last_view_position[ii] =\
                img.shape[VIEW_TABLE[ii][-1]] - viewpos - 1

        self.actual_slice = self.last_view_position[self.actual_view]

        # set contours
        self.contours = contours
        if self.contours is None:
            self.contours_aview = None
        else:
            self.contours_aview = self.contours.transpose(
                self.act_transposition)

        # masked data - has information about which data were removed
        # 1 == enabled, 0 == deleted
        # How to return:
        #       editorDialog.exec_()
        #       masked_data = editorDialog.masked
        self.masked = np.ones(self.img.shape, np.int8)

        self.voxel_size = np.squeeze(np.asarray(voxelSize))
        self.voxel_scale = self.voxel_size / float(np.min(self.voxel_size))
        self.voxel_volume = np.prod(voxelSize)

        # set seeds
        if seeds is None:
            self.seeds = np.zeros(self.img.shape, np.int8)
        else:
            self.seeds = seeds

        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        self.initUI(self.img_aview.shape,
                    self.voxel_scale[np.array(self.act_transposition)], 600,
                    mode)

        if mode == 'draw':
            self.seeds_orig = self.seeds.copy()
            self.slice_box.setEraseFun(self.eraseVolume)

        # set view window values C/W
        lb = np.min(img)
        self.img_min_val = lb
        ub = np.max(img)
        dul = np.double(ub) - np.double(lb)
        self.cw_range = {'c': [lb, ub], 'w': [1, dul]}
        self.slider_cw['c'].setRange(lb, ub)
        self.slider_cw['w'].setRange(1, dul)
        self.changeC(lb + dul / 2)
        self.changeW(dul)

        self.offset = np.zeros((3, ), dtype=np.int16)
        # set what labels will be deleted by 'delete seeds' button
        self.textFocusedLabel = "all"

    def showStatus(self, msg):
        self.status_bar.showMessage(QString(msg))
        QApplication.processEvents()

    def init_draw_mask(self, draw_mask, grid):
        mask_points = []
        mask_iconlabel = []
        for mask, label in draw_mask:
            w, h = mask.shape
            xx, yy = mask.nonzero()
            mask_points.append((xx - w / 2, yy - h / 2))

            img = QImage(w, h, QImage.Format_ARGB32)
            img.fill(qRgba(255, 255, 255, 0))
            for ii in range(xx.shape[0]):
                img.setPixel(xx[ii], yy[ii], qRgba(0, 0, 0, 255))

            img = img.scaled(QSize(w * grid[0], h * grid[1]))
            icon = QIcon(QPixmap.fromImage(img))
            mask_iconlabel.append((icon, label))

        return mask_points, mask_iconlabel

    def saveSliceSeeds(self):
        aux = self.slice_box.getSliceSeeds()
        if aux is not None:
            self.seeds_aview[..., self.actual_slice] = aux
            self.seeds_modified = True

        else:
            self.seeds_modified = False

    def updateMaskRegion_btn(self):
        self.saveSliceSeeds()
        self.updateMaskRegion()

    def updateMaskRegion(self):
        crp = self.getCropBounds(return_nzs=True)
        if crp is not None:
            off, cri, nzs = crp
            if nzs[0].shape[0] <= 5:
                self.showStatus("Not enough points (need >= 5)!")

            else:
                points = np.transpose(nzs)
                hull = Delaunay(points)
                X, Y, Z = np.mgrid[cri[0], cri[1], cri[2]]
                grid = np.vstack([X.ravel(), Y.ravel(), Z.ravel()]).T
                simplex = hull.find_simplex(grid)
                fill = grid[simplex >= 0, :]
                fill = (fill[:, 0], fill[:, 1], fill[:, 2])
                if self.contours is None or self.contours_old is None:
                    self.contours = np.zeros(self.img.shape, np.int8)
                    self.contours_old = self.contours.copy()
                else:
                    self.contours[self.contours != 2] = 0
                self.contours[fill] = 1
                self.contours_aview = self.contours.transpose(
                    self.act_transposition)

                self.selectSlice(self.actual_slice)

    def maskRegion(self):
        self.masked[self.contours == 0] = 0

        self.img[self.contours != 2] = self.img_min_val
        self.contours.fill(0)
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def maskAddSelection(self):
        self.updateMaskRegion()
        if self.contours is None:
            return

        self.contours[self.contours == 1] = 2
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def maskRemoveSelection(self):
        self.updateMaskRegion()
        if self.contours is None:
            return

        self.contours[self.contours == 1] = 0
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def maskSelectAll(self):
        self.updateMaskRegion()

        self.seeds[0][0][0] = 1
        self.seeds[0][0][-1] = 1
        self.seeds[0][-1][0] = 1
        self.seeds[0][-1][-1] = 1
        self.seeds[-1][0][0] = 1
        self.seeds[-1][0][-1] = 1
        self.seeds[-1][-1][0] = 1
        self.seeds[-1][-1][-1] = 1

        self.updateMaskRegion()
        self.selectSlice(self.actual_slice)

    def resetSelection(self):
        self.updateMaskRegion()
        if self.contours is None:
            return

        self.contours.fill(0)
        self.contours_old = self.contours.copy()
        self.seeds.fill(0)
        self.selectSlice(self.actual_slice)

    def resetSeads(self):
        self.seeds.fill(0)
        if self.contours is not None:
            self.contours = self.contours_old.copy()
            self.contours_aview = self.contours.transpose(
                self.act_transposition)
        self.updateMaskRegion()
        self.selectSlice(self.actual_slice)

    def updateCropBounds(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp
            self.contours = np.zeros(self.img.shape, np.int8)
            self.contours[cri].fill(1)
            self.contours_aview = self.contours.transpose(
                self.act_transposition)

    def focusSliceSlider(self):
        self.slider.setFocus(True)

    def sliderSelectSlice(self, value):
        self.selectSlice(self.n_slices - value)

    def scrollSlices(self, inc):
        if abs(inc) > 0:
            new = self.actual_slice + inc
            self.selectSlice(new)

    def selectSlice(self, value, force=False):
        if not (self.allow_select_slice):
            return

        if (value < 0) or (value >= self.n_slices):
            return

        if (value != self.actual_slice) or force:
            self.saveSliceSeeds()
            if self.seeds_modified:
                if self.mode == 'crop':
                    self.updateCropBounds()

                elif self.mode == 'mask':
                    self.updateMaskRegion()

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[..., value]

        slider_val = self.n_slices - value
        self.slider.setValue(slider_val)
        self.slider.label.setText('Slice: %d / %d' %
                                  (slider_val, self.n_slices))

        self.slice_box.setSlice(self.img_aview[..., value],
                                self.seeds_aview[..., value], contours)
        self.actual_slice = value

    def getSeeds(self):
        return self.seeds

    def getImg(self):
        return self.img

    def getOffset(self):
        return self.offset * self.voxel_size

    def getSeedsVal(self, label):
        return self.img[self.seeds == label]

    def getContours(self):
        return self.contours

    def setContours(self, contours):
        """
        store segmentation
        :param contours: segmentation
        :return: Nothing
        """
        """
        :param contours:
        :return:
        """
        self.contours = contours
        self.contours_aview = self.contours.transpose(self.act_transposition)

        self.selectSlice(self.actual_slice)

    def changeCW(self, value, key):
        rg = self.cw_range[key]
        if (value < rg[0]) or (value > rg[1]):
            return

        if (value != self.slice_box.getCW()[key]):
            self.slider_cw[key].setValue(value)
            self.slider_cw[key].label.setText('%s: %d' % (key.upper(), value))
            self.slice_box.setCW(value, key)
            self.slice_box.updateSliceCW(self.img_aview[...,
                                                        self.actual_slice])

    def changeC(self, value):
        self.changeCW(value, 'c')

    def changeW(self, value):
        self.changeCW(value, 'w')

    def setView(self, value):
        self.last_view_position[self.actual_view] = self.actual_slice
        # save seeds
        self.saveSliceSeeds()
        if self.seeds_modified:
            if self.mode == 'crop':
                self.updateCropBounds()

            elif self.mode == 'mask':
                self.updateMaskRegion()

        key = str(value)
        self.actual_view = key
        self.actual_slice = self.last_view_position[key]

        self.act_transposition = VIEW_TABLE[key]
        self.img_aview = self.img.transpose(self.act_transposition)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)

        if self.contours is not None:
            self.contours_aview = self.contours.transpose(
                self.act_transposition)
            contours = self.contours_aview[..., self.actual_slice]

        else:
            contours = None

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        # width = (self.img_aview.shape[0] * vscale[0])[0]
        # if width > 800:
        #     height = 400
        #     grid = height / float(self.img_aview.shape[1] * vscale[1])

        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[..., self.actual_slice],
                                self.seeds_aview[...,
                                                 self.actual_slice], contours)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        slider_val = self.n_slices - self.actual_slice
        self.slider.setRange(1, self.n_slices)
        self.slider.setValue(slider_val)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' %
                                  (slider_val, self.n_slices))
        self.view_label.setText('View size: %d x %d' %
                                self.img_aview.shape[:-1])

        self.adjustSize()
        self.adjustSize()

    def changeMask(self, val):
        self.slice_box.setMaskPoints(self.mask_points_tab[val])

    def changeContourMode(self, val):
        self.slice_box.contour_mode = str(val)
        self.slice_box.updateSlice()

    def changeEraseMode(self, val):
        self.slice_box.erase_mode = str(val)

    def eraseVolume(self, pos, mode):
        self.showStatus("Processing...")
        xyz = np.array(pos + (self.actual_slice, ))
        p = np.zeros_like(xyz)
        p[np.array(self.act_transposition)] = xyz
        p = tuple(p)

        if self.seeds[p] > 0:
            if mode == 'inside':
                erase_reg(self.seeds, p, val=0)

            elif mode == 'outside':
                erase_reg(self.seeds, p, val=-1)
                idxs = np.where(self.seeds < 0)
                self.seeds.fill(0)
                self.seeds[idxs] = 1

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[..., self.actual_slice]

        self.slice_box.setSlice(self.img_aview[..., self.actual_slice],
                                self.seeds_aview[...,
                                                 self.actual_slice], contours)

        self.showStatus("Done")

    def cropUpdate(self, img):

        for ii in VIEW_TABLE.keys():
            self.last_view_position[ii] = 0
        self.actual_slice = 0

        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)

        self.contours = None
        self.contours_aview = None

        self.seeds = np.zeros(self.img.shape, np.int8)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[..., self.actual_slice],
                                self.seeds_aview[..., self.actual_slice], None)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        self.slider.setValue(self.actual_slice + 1)
        self.slider.setRange(1, self.n_slices)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' %
                                  (self.actual_slice + 1, self.n_slices))
        self.view_label.setText('View size: %d x %d' %
                                self.img_aview.shape[:-1])

    def getCropBounds(self, return_nzs=False, flat=False):

        nzs = self.seeds.nonzero()
        cri = []
        flag = True
        for ii in range(3):
            if nzs[ii].shape[0] == 0:
                flag = False
                break

            smin, smax = np.min(nzs[ii]), np.max(nzs[ii])
            if not (flat):
                if smin == smax:
                    flag = False
                    break

            cri.append((smin, smax))

        if flag:
            cri = np.array(cri)

            out = []
            offset = []
            for jj, ii in enumerate(cri):
                out.append(slice(ii[0], ii[1] + 1))
                offset.append(ii[0])

            if return_nzs:
                return np.array(offset), tuple(out), nzs

            else:
                return np.array(offset), tuple(out)

        else:
            return None

    def crop(self):
        self.showStatus("Processing...")

        crp = self.getCropBounds()

        if crp is not None:
            offset, cri = crp
            crop = self.img[cri]
            self.img = np.ascontiguousarray(crop)
            self.offset += offset

            self.showStatus('Done')

        else:
            self.showStatus('Region not selected!')

        self.cropUpdate(self.img)

    def seg_to_background_seeds(self, event):
        self.saveSliceSeeds()
        self.seeds[self.seeds < 3] = 0

        from PyQt4.QtCore import pyqtRemoveInputHook
        # pyqtRemoveInputHook()
        # import ipdb; ipdb.set_trace()
        self.seeds[(self.contours == 1)
                   & (self.seeds < 3)] = self.BACKGROUND_NOMODEL_SEED_LABEL
        self.contours[...] = 0

    def seg_to_foreground_seeds(self, event):
        self.saveSliceSeeds()
        self.seeds[self.seeds < 3] = 0
        # from PyQt4.QtCore import pyqtRemoveInputHook
        # pyqtRemoveInputHook()
        # import ipdb; ipdb.set_trace()
        self.seeds[(self.contours == 1)
                   & (self.seeds < 3)] = self.FOREGROUND_NOMODEL_SEED_LABEL
        self.contours[...] = 0

    def saveload_seeds(self, event):
        if self.seeds_copy is None:
            self.seeds_copy = self.seeds.copy()
            self.seeds[...] = 0
            # print "save"
            # from PyQt4.QtCore import pyqtRemoveInputHook
            # pyqtRemoveInputHook()
            # import ipdb; ipdb.set_trace()
            self.btn_save.setText("Load seeds")
        else:
            # from PyQt4.QtCore import pyqtRemoveInputHook
            # pyqtRemoveInputHook()
            # import ipdb; ipdb.set_trace()
            self.seeds[self.seeds_copy > 0] = self.seeds_copy[
                self.seeds_copy > 0]
            self.seeds_copy = None
            self.btn_save.setText("Save seeds")

    def recalculate(self, event):
        self.saveSliceSeeds()
        if np.abs(np.min(self.seeds) - np.max(self.seeds)) < 2:
            self.showStatus('Inner and outer regions not defined!')
            return

        self.showStatus("Processing...")
        self.mode_fun(self)
        self.selectSlice(self.actual_slice)
        self.updateVolume()
        self.showStatus("Done")

    def changeFocusedLabel(self, textlabel):
        self.textFocusedLabel = textlabel
        # logger
        # print " lakjlfkj ", textlabel
        logger.debug(self.textFocusedLabel)

    def deleteSliceSeeds(self, event):
        if self.textFocusedLabel == 'all':
            self.seeds_aview[..., self.actual_slice] = 0
        else:
            # delete only seeds with specific label
            self.seeds_aview[self.seeds_aview[..., self.actual_slice] ==
                             int(self.textFocusedLabel), self.actual_slice] = 0

        self.slice_box.setSlice(seeds=self.seeds_aview[..., self.actual_slice])
        self.slice_box.updateSlice()

    def deleteSeedsInAllImage(self, event):
        if self.textFocusedLabel == 'all':
            self.seeds_aview[...] = 0
        else:
            # delete only seeds with specific label
            self.seeds_aview[self.seeds_aview[...] == int(
                self.textFocusedLabel)] = 0

        self.slice_box.setSlice(seeds=self.seeds_aview[..., self.actual_slice])
        self.slice_box.updateSlice()

    def resetSliceDraw(self, event):
        seeds_orig_aview = self.seeds_orig.transpose(self.act_transposition)
        self.seeds_aview[..., self.actual_slice] = seeds_orig_aview[
            ..., self.actual_slice]
        self.slice_box.setSlice(seeds=self.seeds_aview[..., self.actual_slice])
        self.slice_box.updateSlice()

    def quit(self, event):
        self.close()

    def updateVolume(self):
        text = 'Volume:\n  unknown'
        if self.voxel_volume is not None:
            if self.mode == 'draw':
                vd = self.seeds

            else:
                vd = self.contours

            if vd is not None:
                nzs = vd.nonzero()
                nn = nzs[0].shape[0]
                if self.volume_unit == 'ml':
                    text = 'Volume [ml]:\n  %.2f' %\
                        (nn * self.voxel_volume / 1000)
                else:
                    text = 'Volume [mm3]:\n  %.2e' % (nn * self.voxel_volume)

        self.volume_label.setText(text)

    def getROI(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp

        else:
            cri = []
            for jj, ii in enumerate(self.img.shape):
                off = self.offset[jj]
                cri.append(slice(off, off + ii))

        return cri
Example #28
0
class FitParam(object):
    def __init__(self,
                 name,
                 value,
                 mini,
                 maxi,
                 logscale=False,
                 steps=5000,
                 format='%.3f',
                 size_offset=0,
                 unit=''):
        self.name = name
        self.value = value
        self.min = mini if logscale == False else max(1e-120, mini)
        self.max = maxi
        self.logscale = logscale
        self.steps = steps
        self.format = format
        self.unit = unit
        self.prefix_label = None
        self.lineedit = None
        self.unit_label = None
        self.slider = None
        self.button = None
        self._widgets = []
        self._size_offset = size_offset
        self._refresh_callback = None
        self.dataset = FitParamDataSet(title=_("Curve fitting parameter"))

    def copy(self):
        """Return a copy of this fitparam"""
        return self.__class__(self.name, self.value, self.min, self.max,
                              self.logscale, self.steps, self.format,
                              self._size_offset, self.unit)

    def create_widgets(self, parent, refresh_callback):
        self._refresh_callback = refresh_callback
        self.prefix_label = QLabel()
        font = self.prefix_label.font()
        font.setPointSize(font.pointSize() + self._size_offset)
        self.prefix_label.setFont(font)
        self.button = QPushButton()
        self.button.setIcon(get_icon('settings.png'))
        self.button.setToolTip(
            _("Edit '%s' fit parameter properties") % self.name)
        QObject.connect(self.button, SIGNAL('clicked()'),
                        lambda: self.edit_param(parent))
        self.lineedit = QLineEdit()
        QObject.connect(self.lineedit, SIGNAL('editingFinished()'),
                        self.line_editing_finished)
        self.unit_label = QLabel(self.unit)
        self.slider = QSlider()
        self.slider.setOrientation(Qt.Horizontal)
        self.slider.setRange(0, self.steps - 1)
        QObject.connect(self.slider, SIGNAL("valueChanged(int)"),
                        self.slider_value_changed)
        self.update(refresh=False)
        self.add_widgets([
            self.prefix_label, self.lineedit, self.unit_label, self.slider,
            self.button
        ])

    def add_widgets(self, widgets):
        self._widgets += widgets

    def get_widgets(self):
        return self._widgets

    def set_scale(self, state):
        self.logscale = state > 0
        self.update_slider_value()

    def set_text(self, fmt=None):
        style = "<span style=\'color: #444444\'><b>%s</b></span>"
        self.prefix_label.setText(style % self.name)
        if self.value is None:
            value_str = ''
        else:
            if fmt is None:
                fmt = self.format
            value_str = fmt % self.value
        self.lineedit.setText(value_str)
        self.lineedit.setDisabled(self.value == self.min
                                  and self.max == self.min)

    def line_editing_finished(self):
        try:
            self.value = float(self.lineedit.text())
        except ValueError:
            self.set_text()
        self.update_slider_value()
        self._refresh_callback()

    def slider_value_changed(self, int_value):
        if self.logscale:
            #~ total_delta = np.log10(1+self.max-self.min)
            #~ self.value = self.min+10**(total_delta*int_value/(self.steps-1))-1
            #~ total_delta = np.log10(self.max)-np.log10(self.min)
            ratio = int_value / (self.steps - 1)
            self.value = self.max**ratio * self.min**(1 - ratio)
        else:
            total_delta = self.max - self.min
            self.value = self.min + total_delta * int_value / (self.steps - 1)
        self.set_text()
        self._refresh_callback()

    def update_slider_value(self):
        from numpy import isnan, isinf
        if (self.value is None or self.min is None or self.max is None):
            self.slider.setEnabled(False)
            if self.slider.parent() and self.slider.parent().isVisible():
                self.slider.show()
        elif self.value == self.min and self.max == self.min:
            self.slider.hide()
        else:
            self.slider.setEnabled(True)
            if self.slider.parent() and self.slider.parent().isVisible():
                self.slider.show()
            if self.logscale:
                value_delta = max([np.log10(self.value / self.min), 0.])
                total_delta = np.log10(self.max / self.min)
                if not isnan(self.steps * value_delta / total_delta):
                    intval = int(self.steps * value_delta / total_delta)
                else:
                    intval = int(self.min)
            else:
                value_delta = self.value - self.min
                total_delta = self.max - self.min
                intval = int(self.steps * value_delta / total_delta)
            self.slider.blockSignals(True)
            print intval
            print
            sys.stdout.flush()
            self.slider.setValue(intval)
            self.slider.blockSignals(False)

    def edit_param(self, parent):
        update_dataset(self.dataset, self)
        if self.dataset.edit(parent=parent):
            restore_dataset(self.dataset, self)
            if self.value > self.max:
                self.max = self.value
            if self.value < self.min:
                self.min = self.value
            self.update(True)

    def update(self, refresh=True):
        self.unit_label.setText(self.unit)
        self.slider.setRange(0, self.steps - 1)
        self.update_slider_value()
        self.set_text()
        if refresh:
            self._refresh_callback()
Example #29
0
class Window( QWidget ):
	def __init__(self):
		QWidget.__init__(self)

		self.main_layout = QGridLayout()

		self.steps_spin = QSpinBox()
		self.steps_spin.setRange(1,12)
		self.steps_label = QLabel("steps:")
		self.steps_slider = QSlider(1) #horizontal
		self.steps_slider.setRange(1,12)

		self.smooth_spin = QSpinBox()
		self.smooth_spin.setRange(1,100)
		self.smooth_label = QLabel("smoothness:")
		self.smooth_slider = QSlider(1) #horizontal
		self.smooth_slider.setRange(0,100)
		self.smooth_slider.setSingleStep(1)

		self.dampen_spin = QSpinBox()
		self.dampen_spin.setRange(1,100)
		self.dampen_label = QLabel("dampening:")
		self.dampen_slider = QSlider(1) #horizontal
		self.dampen_slider.setRange(0,100)
		self.dampen_slider.setSingleStep(1)

		self.update_button = QPushButton("update")

		self.view = QGraphicsView()

		self.main_layout.addWidget(
			self.steps_spin,
			0,
			0)
		self.main_layout.addWidget(
			self.steps_label,
			0,
			1)
		self.main_layout.addWidget(
			self.steps_slider,
			0,
			2)

		self.main_layout.addWidget(
			self.smooth_spin,
			1,
			0)
		self.main_layout.addWidget(
			self.smooth_label,
			1,
			1)
		self.main_layout.addWidget(
			self.smooth_slider,
			1,
			2)

		self.main_layout.addWidget(
			self.dampen_spin,
			2,
			0)
		self.main_layout.addWidget(
			self.dampen_label,
			2,
			1)
		self.main_layout.addWidget(
			self.dampen_slider,
			2,
			2)

		self.main_layout.addWidget(
			self.update_button,
			3,
			0,
			1,
			3)

		self.main_layout.addWidget(
			self.view,
			4,
			0,
			1, #rowSpan
			3) #columnSpan

		self.setLayout(
			self.main_layout)
Example #30
0
 def setRange(self, value_lower, value_upper):
   QSlider.setRange(self, self.convert(value_lower), self.convert(value_upper))
class QTSeedEditor(QDialog):
    """
    DICOM viewer.
    """
    @staticmethod
    def get_line(mode='h'):
        line = QFrame()
        if mode == 'h':
            line.setFrameStyle(QFrame.HLine)
        elif mode == 'v':
            line.setFrameStyle(QFrame.VLine)

        line.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)

        return line

    def initUI(self, shape, vscale, height=600,
               mode='seed'):
        """
        Initialize UI.

        Parameters
        ----------
        shape : (int, int, int)
            Shape of data matrix.
        vscale : (float, float, float)
            Voxel scaling.
        height : int
            Maximal slice height in pixels.
        mode : str
            Editor mode.
        """

        self.slab = {}

        # picture
        grid = height / float(shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])
        self.slice_box = SliceBox(shape[:-1], mgrid, mode)
        self.slice_box.setScrollFun(self.scrollSlices)
        self.connect(self.slice_box, SIGNAL('focus_slider'), self.focusSliceSlider)

        # sliders
        self.allow_select_slice = True
        self.n_slices = shape[2]
        self.slider = QSlider(Qt.Vertical)
        self.slider.valueChanged.connect(self.sliderSelectSlice)
        self.slider.label = QLabel()
        self.slider.setRange(1, self.n_slices)

        self.slider_cw = {}
        self.slider_cw['c'] = QSlider(Qt.Horizontal)
        self.slider_cw['c'].valueChanged.connect(self.changeC)
        self.slider_cw['c'].label = QLabel()

        self.slider_cw['w'] = QSlider(Qt.Horizontal)
        self.slider_cw['w'].valueChanged.connect(self.changeW)
        self.slider_cw['w'].label = QLabel()

        self.view_label = QLabel('View size: %d x %d' % self.img_aview.shape[:-1])
        self.voxel_label = QLabel('Voxel size [mm]:\n  %.2f x %.2f x %.2f'\
                                      % tuple(self.voxel_size[np.array(self.act_transposition)]))

        combo_view_options = VIEW_TABLE.keys()
        combo_view = QComboBox(self)
        combo_view.activated[str].connect(self.setView)
        combo_view.addItems(combo_view_options)

        #radio button group for choosing seed class ------------------------
        self.current_class = 1
        self.slice_box.seed_mark = self.current_class
        number_group = QGroupBox(QString('Class markers'))
        vbox_NG = QVBoxLayout()
        r1 = QRadioButton('class 1')
        r1.setStyleSheet('QRadioButton {color: red}')
        r1.setChecked(True)
        r2 = QRadioButton('class 2')
        r2.setStyleSheet('QRadioButton {color: green}')
        r3 = QRadioButton('class 3')
        r3.setStyleSheet('QRadioButton {color: blue}')
        r4 = QRadioButton('class 4')
        r4.setStyleSheet('QRadioButton {color: cyan}')
        r5 = QRadioButton('class 5')
        r5.setStyleSheet('QRadioButton {color: magenta}')

        vbox_NG.addWidget(r1)
        vbox_NG.addWidget(r2)
        vbox_NG.addWidget(r3)
        vbox_NG.addWidget(r4)
        vbox_NG.addWidget(r5)

        number_group.setLayout(vbox_NG)

        self.button_group = QButtonGroup()
        self.button_group.addButton(r1, 1)
        self.button_group.addButton(r2, 2)
        self.button_group.addButton(r3, 3)
        self.button_group.addButton(r4, 4)
        self.button_group.addButton(r5, 5)
        self.connect(self.button_group, SIGNAL("buttonClicked(int)"), self.change_seed_class)
        #-------------------------------------------------------------------

        # buttons
        # btn_save = QPushButton('Save', self)
        # btn_save.clicked.connect(self.save)

        btn_quit = QPushButton("Quit", self)
        btn_quit.clicked.connect(self.quit)

        # btn_crop = QPushButton('Crop', self)
        # btn_crop.clicked.connect(self.crop)

        combo_dmask = QComboBox(self)
        combo_dmask.activated.connect(self.changeMask)
        self.mask_points_tab, aux = self.init_draw_mask(DRAW_MASK, mgrid)
        for icon, label in aux:
            combo_dmask.addItem(icon, label)

        self.slice_box.setMaskPoints(self.mask_points_tab[combo_dmask.currentIndex()])

        self.status_bar = QStatusBar()

        vopts = []
        vmenu = []
        appmenu = []
        if mode == 'seed':
            btn_recalc = QPushButton("Recalculate", self)
            btn_recalc.clicked.connect(self.recalculate)
            appmenu.append(QLabel('<b>Segmentation mode</b><br><br><br>' +
                                  'Select the region of interest<br>' +
                                  'using the mouse buttons.<br><br>'))
            appmenu.append(btn_recalc)
            appmenu.append(QLabel())
            self.volume_label = QLabel('Volume [mm3]:\n  unknown')
            appmenu.append(self.volume_label)

        if mode == 'seed' or mode == 'crop':
            btn_del = QPushButton("Delete Seeds", self)
            btn_del.clicked.connect(self.deleteSliceSeeds)
            vmenu.append(None)
            vmenu.append(btn_del)

            combo_contour_options = ['fill', 'contours', 'off']
            combo_contour = QComboBox(self)
            combo_contour.activated[str].connect(self.changeContourMode)
            combo_contour.addItems(combo_contour_options)
            self.changeContourMode(combo_contour_options[combo_contour.currentIndex()])
            vopts.append(QLabel('Selection mode:'))
            vopts.append(combo_contour)

        if mode == 'crop':
            btn_crop = QPushButton("Crop", self)
            btn_crop.clicked.connect(self.crop)
            appmenu.append(QLabel('<b>Crop mode</b><br><br><br>' +
                                  'Select the crop region<br>' +
                                  'using the left mouse button<br><br>'))
            appmenu.append(btn_crop)

        # if mode == 'draw':
        #     appmenu.append(QLabel('<b>Manual segmentation<br> mode</b><br><br><br>' +
        #                           'Mark the region of interest<br>' +
        #                           'using the mouse buttons:<br><br>' +
        #                           '&nbsp;&nbsp;<i>left</i> - draw<br>' +
        #                           '&nbsp;&nbsp;<i>right</i> - erase<br>' +
        #                           '&nbsp;&nbsp;<i>middle</i> - vol. erase<br><br>'))
        #
        #     btn_reset = QPushButton("Reset", self)
        #     btn_reset.clicked.connect(self.resetSliceDraw)
        #     vmenu.append(None)
        #     vmenu.append(btn_reset)
        #
        #     combo_erase_options = ['inside', 'outside']
        #     combo_erase = QComboBox(self)
        #     combo_erase.activated[str].connect(self.changeEraseMode)
        #     combo_erase.addItems(combo_erase_options)
        #     self.changeEraseMode(combo_erase_options[combo_erase.currentIndex()])
        #     vopts.append(QLabel('Volume erase mode:'))
        #     vopts.append(combo_erase)

        hbox = QHBoxLayout()
        vbox = QVBoxLayout()
        vbox_left = QVBoxLayout()
        vbox_app = QVBoxLayout()

        hbox.addWidget(self.slice_box)
        hbox.addWidget(self.slider)
        vbox_left.addWidget(self.slider.label)
        vbox_left.addWidget(self.view_label)
        vbox_left.addWidget(self.voxel_label)
        vbox_left.addWidget(QLabel())
        vbox_left.addWidget(QLabel('View plane:'))
        vbox_left.addWidget(combo_view)
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(self.slider_cw['c'].label)
        vbox_left.addWidget(self.slider_cw['c'])
        vbox_left.addWidget(self.slider_cw['w'].label)
        vbox_left.addWidget(self.slider_cw['w'])
        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(QLabel('Drawing mask:'))
        vbox_left.addWidget(combo_dmask)

        for ii in vopts:
            vbox_left.addWidget(ii)

        for ii in vmenu:
            if ii is None:
                vbox_left.addStretch(1)

            else:
                vbox_left.addWidget(ii)

        for ii in appmenu:
            if ii is None:
                vbox_app.addStretch(1)

            else:
                vbox_app.addWidget(ii)

        vbox_left.addWidget(self.get_line())
        vbox_left.addWidget(number_group)

        # vbox_app.addWidget(btn_crop)

        vbox_app.addStretch(1)
        # vbox_app.addWidget(btn_save)
        vbox_app.addWidget(btn_quit)

        hbox.addLayout(vbox_left)
        hbox.addWidget(self.get_line('v'))
        hbox.addLayout(vbox_app)
        vbox.addLayout(hbox)
        vbox.addWidget(self.status_bar)
        self.setLayout(vbox)

        self.setWindowTitle('Segmentation Editor')
        self.show()

    def __init__(self, img, actualSlice=0,
                 seeds=None, contours=None,
                 mode='seed', modeFun=None,
                 voxelSize=[1,1,1]):
        """
        Initiate Editor

        Parameters
        ----------
        img : array
            DICOM data matrix.
        actualSlice : int
            Index of actual slice.
        seeds : array
            Seeds, user defined regions of interest.
        contours : array
            Computed segmentation.
        mode : str
            Editor modes:
               'seed' - seed editor
               'crop' - manual crop
               'draw' - drawing
        modeFun : fun
            Mode function invoked by user button.
        voxelSize : tuple of float
            voxel size [mm]
        """

        QDialog.__init__(self)

        self.mode = mode
        self.mode_fun = modeFun
        # self.datapath = datapath

        self.actual_view = 'axial'
        self.act_transposition = VIEW_TABLE[self.actual_view]
        self.last_view_position = {}
        for ii in VIEW_TABLE.iterkeys():
            self.last_view_position[ii] = img.shape[VIEW_TABLE[ii][-1]] - 1

        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)
        self.actual_slice = self.img_aview.shape[-1] - actualSlice - 1
        self.last_view_position[self.actual_view] = self.actual_slice

        # set contours
        self.contours = contours
        if self.contours is None:
            self.contours_aview = None

        else:
            self.contours_aview = self.contours.transpose(self.act_transposition)

        self.voxel_size = np.array(voxelSize)
        self.voxel_scale = self.voxel_size / float(np.min(self.voxel_size))
        self.voxel_volume = np.prod(voxelSize)

        # set seeds
        if seeds is None:
            self.seeds = np.zeros(self.img.shape, np.int8)
        else:
            self.seeds = seeds

        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        self.initUI(self.img_aview.shape,
                    self.voxel_scale[np.array(self.act_transposition)],
                    600, mode)

        if mode == 'draw':
            self.seeds_orig = self.seeds.copy()
            self.slice_box.setEraseFun(self.eraseVolume)

        # set view window values C/W
        lb = np.min(img)
        ub = np.max(img)
        dul = ub - lb
        self.cw_range = {'c': [lb, ub], 'w': [1, dul]}
        self.slider_cw['c'].setRange(lb, ub)
        self.slider_cw['w'].setRange(1, dul)
        self.changeC(lb + dul / 2)
        self.changeW(dul)

        self.offset = np.zeros((3,), dtype=np.int16)

    def change_seed_class(self, id):
        self.current_class = id
        self.slice_box.seed_mark = self.current_class
        # print 'Current seed class changed to ', id, '.'

    def showStatus(self, msg):
        self.status_bar.showMessage(QString(msg))
        QApplication.processEvents()

    def init_draw_mask(self, draw_mask, grid):
        mask_points = []
        mask_iconlabel = []
        for mask, label in draw_mask:
            w, h = mask.shape
            xx, yy = mask.nonzero()
            mask_points.append((xx - w/2, yy - h/2))

            img = QImage(w, h, QImage.Format_ARGB32)
            img.fill(qRgba(255, 255, 255, 0))
            for ii in range(xx.shape[0]):
                img.setPixel(xx[ii], yy[ii], qRgba(0, 0, 0, 255))

            img = img.scaled(QSize(w * grid[0], h * grid[1]))
            icon = QIcon(QPixmap.fromImage(img))
            mask_iconlabel.append((icon, label))

        return mask_points, mask_iconlabel

    def saveSliceSeeds(self):
        aux = self.slice_box.getSliceSeeds()
        if aux is not None:
            self.seeds_aview[...,self.actual_slice] = aux
            self.seeds_modified = True

        else:
            self.seeds_modified = False

    def updateCropBounds(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp
            self.contours = np.zeros(self.img.shape, np.int8)
            self.contours[cri].fill(1)
            self.contours_aview = self.contours.transpose(self.act_transposition)

    def focusSliceSlider(self):
        self.slider.setFocus(True)

    def sliderSelectSlice(self, value):
        self.selectSlice(self.n_slices - value)

    def scrollSlices(self, inc):
        if abs(inc) > 0:
            new = self.actual_slice + inc
            self.selectSlice(new)

    def selectSlice(self, value, force=False):
        if not(self.allow_select_slice):
            return

        if (value < 0) or (value >= self.n_slices):
            return

        if (value != self.actual_slice) or force:
            self.saveSliceSeeds()
            if self.seeds_modified and (self.mode == 'crop'):
                self.updateCropBounds()

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[...,value]

        slider_val = self.n_slices - value
        self.slider.setValue(slider_val)
        self.slider.label.setText('Slice: %d / %d' % (slider_val, self.n_slices))

        self.slice_box.setSlice(self.img_aview[...,value],
                                self.seeds_aview[...,value],
                                contours)
        self.actual_slice = value

    def getSeeds(self):
        return self.seeds

    def getImg(self):
        return self.img

    def getOffset(self):
        return self.offset * self.voxel_size

    def getSeedsVal(self, label):
        return self.img[self.seeds==label]

    def getContours(self):
        return self.contours

    def setContours(self, contours):
        self.contours = contours
        self.contours_aview = self.contours.transpose(self.act_transposition)

        self.selectSlice(self.actual_slice)

    def changeCW(self, value, key):
        rg = self.cw_range[key]
        if (value < rg[0]) or (value > rg[1]):
            return

        if (value != self.slice_box.getCW()[key]):
            self.slider_cw[key].setValue(value)
            self.slider_cw[key].label.setText('%s: %d' % (key.upper(), value))
            self.slice_box.setCW(value, key)
            self.slice_box.updateSliceCW(self.img_aview[...,self.actual_slice])


    def changeC(self, value):
        self.changeCW(value, 'c')

    def changeW(self, value):
        self.changeCW(value, 'w')

    def setView(self, value):
        self.last_view_position[self.actual_view] = self.actual_slice
        # save seeds
        self.saveSliceSeeds()
        if self.seeds_modified and (self.mode == 'crop'):
            self.updateCropBounds(self.seeds_aview[...,self.actual_slice])

        key = str(value)
        self.actual_view = key
        self.actual_slice = self.last_view_position[key]

        self.act_transposition = VIEW_TABLE[key]
        self.img_aview = self.img.transpose(self.act_transposition)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)

        if self.contours is not None:
            self.contours_aview = self.contours.transpose(self.act_transposition)
            contours = self.contours_aview[...,self.actual_slice]

        else:
            contours = None

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[...,self.actual_slice],
                                self.seeds_aview[...,self.actual_slice],
                                contours)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        slider_val = self.n_slices - self.actual_slice
        self.slider.setValue(slider_val)
        self.slider.setRange(1, self.n_slices)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' % (slider_val,
                                                      self.n_slices))
        self.view_label.setText('View size: %d x %d' % self.img_aview.shape[:-1])

    def changeMask(self, val):
        self.slice_box.setMaskPoints(self.mask_points_tab[val])

    def changeContourMode(self, val):
        self.slice_box.contour_mode = str(val)
        self.slice_box.updateSlice()

    def changeEraseMode(self, val):
        self.slice_box.erase_mode = str(val)

    def eraseVolume(self, pos, mode):
        self.showStatus("Processing...")
        xyz = pos + (self.actual_slice,)
        p = tuple(np.array(xyz)[np.array(self.act_transposition)])
        if self.seeds[p] > 0:
            if mode == 'inside':
                erase_reg(self.seeds, p, val=0)

            elif mode == 'outside':
                erase_reg(self.seeds, p, val=-1)
                idxs = np.where(self.seeds < 0)
                self.seeds.fill(0)
                self.seeds[idxs] = 1

        if self.contours is None:
            contours = None

        else:
            contours = self.contours_aview[...,self.actual_slice]

        self.slice_box.setSlice(self.img_aview[...,self.actual_slice],
                                self.seeds_aview[...,self.actual_slice],
                                contours)

        self.showStatus("Done")

    def cropUpdate(self, img):

        for ii in VIEW_TABLE.iterkeys():
            self.last_view_position[ii] = 0
        self.actual_slice = 0

        self.img = img
        self.img_aview = self.img.transpose(self.act_transposition)

        self.contours = None
        self.contours_aview = None

        self.seeds = np.zeros(self.img.shape, np.int8)
        self.seeds_aview = self.seeds.transpose(self.act_transposition)
        self.seeds_modified = False

        vscale = self.voxel_scale[np.array(self.act_transposition)]
        height = self.slice_box.height()
        grid = height / float(self.img_aview.shape[1] * vscale[1])
        mgrid = (grid * vscale[0], grid * vscale[1])

        self.slice_box.resizeSlice(new_slice_size=self.img_aview.shape[:-1],
                                   new_grid=mgrid)

        self.slice_box.setSlice(self.img_aview[...,self.actual_slice],
                                self.seeds_aview[...,self.actual_slice],
                                None)

        self.allow_select_slice = False
        self.n_slices = self.img_aview.shape[2]
        self.slider.setValue(self.actual_slice + 1)
        self.slider.setRange(1, self.n_slices)
        self.allow_select_slice = True

        self.slider.label.setText('Slice: %d / %d' % (self.actual_slice + 1,
                                                      self.n_slices))
        self.view_label.setText('View size: %d x %d' % self.img_aview.shape[:-1])

    def getCropBounds(self):

        nzs = self.seeds.nonzero()
        cri = []
        flag = True
        for ii in range(3):
            if nzs[ii].shape[0] == 0:
                flag = False
                break

            smin, smax = np.min(nzs[ii]), np.max(nzs[ii])
            if smin == smax:
                flag = False
                break

            cri.append((smin, smax))

        if flag:
            cri = np.array(cri)

            out = []
            offset = []
            for jj, ii in enumerate(cri):
                out.append(slice(ii[0], ii[1] + 1))
                offset.append(ii[0])

            return np.array(offset), tuple(out)

        else:
            return None

    def crop(self):
        self.showStatus("Processing...")

        crp = self.getCropBounds()

        if crp is not None:
            offset, cri = crp
            crop = self.img[cri]
            self.img = np.ascontiguousarray(crop)
            self.offset += offset


            self.showStatus('Done')

        else:
            self.showStatus('Region not selected!')

        self.cropUpdate(self.img)

    def recalculate(self, event):
        self.saveSliceSeeds()
        if np.abs(np.min(self.seeds) - np.max(self.seeds)) < 2:
            self.showStatus('At least two regions must be marked!')
            return

        self.showStatus("Processing...")
        # idx = 3
        # s = random_walker(self.img[idx,:,:], self.seeds[idx,:,:])#, mode='cg_mg')
        # plt.figure()
        # plt.imshow(mark_boundaries(self.img[idx,:,:], s))
        # plt.show()
        # self.segmentation = np.zeros(self.img.shape)
        # self.segmentation[idx,:,:] = s
        self.segmentation = random_walker(self.img, self.seeds, mode='cg_mg')
        self.setContours(self.segmentation - 1)
        self.selectSlice(self.actual_slice)
        # self.updateVolume()
        self.showStatus("Done")

    def deleteSliceSeeds(self, event):
        self.seeds_aview[...,self.actual_slice] = 0
        self.slice_box.setSlice(seeds=self.seeds_aview[...,self.actual_slice])
        self.slice_box.updateSlice()

    def resetSliceDraw(self, event):
        seeds_orig_aview = self.seeds_orig.transpose(self.act_transposition)
        self.seeds_aview[...,self.actual_slice] = seeds_orig_aview[...,self.actual_slice]
        self.slice_box.setSlice(seeds=self.seeds_aview[...,self.actual_slice])
        self.slice_box.updateSlice()

    def quit(self, event):
        self.close()

    # def save(self, event):
    #     odp = os.path.expanduser("~/lisa_data")
    #     if not op.exists(odp):
    #         os.makedirs(odp)
    #
    #     data = self.export()
    #     # data['version'] = self.version
    #     # data['experiment_caption'] = self.experiment_caption
    #     # data['lisa_operator_identifier'] = self.lisa_operator_identifier
    #     pth, filename = op.split(op.normpath(self.datapath))
    #     # filename += "-" + self.experiment_caption
    #     filepath = 'org-' + filename + '.pklz'
    #     filepath = op.join(odp, filepath)
    #     filepath = misc.suggest_filename(filepath)
    #     misc.obj_to_file(data, filepath, filetype='pklz')
    #
    #     filepath = 'organ_last.pklz'
    #     filepath = op.join(odp, filepath)
    #     misc.obj_to_file(data, filepath, filetype='pklz')

    # def export(self):
    #     slab = {}
    #     slab['none'] = 0
    #     slab['liver'] = 1
    #     slab['lesions'] = 6
    #     slab.update(self.slab)
    #
    #     data = {}
    #     data['version'] = (1, 0, 1)
    #     data['data3d'] = self.img
    #     # data['crinfo'] = self.crinfo
    #     data['segmentation'] = self.segmentation
    #     data['slab'] = slab
    #     # data['voxelsize_mm'] = self.voxelsize_mm
    #     # data['orig_shape'] = self.orig_shape
    #     # data['processing_time'] = self.processing_time
    #     return data

    def updateVolume(self):
        text = 'Volume [mm3]:\n  unknown'
        if self.voxel_volume is not None:
            if self.mode == 'draw':
                vd = self.seeds

            else:
                vd = self.contours

            if vd is not None:
                nzs = vd.nonzero()
                nn = nzs[0].shape[0]
                text = 'Volume [mm3]:\n  %.2e' % (nn * self.voxel_volume)

        self.volume_label.setText(text)

    def getROI(self):
        crp = self.getCropBounds()
        if crp is not None:
            _, cri = crp

        else:
            cri = []
            for jj, ii in enumerate(self.img.shape):
                off = self.offset[jj]
                cri.append(slice(off, off + ii))

        return cri
Example #32
0
class XZoomSlider(QWidget):
    zoomAmountChanged   = Signal(int)
    
    def __init__(self, parent=None):
        super(XZoomSlider, self).__init__(parent)
        
        # define the interface
        in_icon  = projexui.resources.find('img/zoom_in.png')
        out_icon = projexui.resources.find('img/zoom_out.png')
        
        self._zoomInButton = QToolButton(self)
        self._zoomInButton.setAutoRaise(True)
        self._zoomInButton.setToolTip('Zoom In')
        self._zoomInButton.setIcon(QIcon(in_icon))
        
        self._zoomOutButton = QToolButton(self)
        self._zoomOutButton.setAutoRaise(True)
        self._zoomOutButton.setToolTip('Zoom Out')
        self._zoomOutButton.setIcon(QIcon(out_icon))
        
        self._zoomSlider = QSlider(Qt.Horizontal, self)
        self._zoomSlider.setRange(10, 100)
        self._zoomSlider.setValue(100)
        
        # define the layout
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addWidget(self._zoomOutButton)
        layout.addWidget(self._zoomSlider)
        layout.addWidget(self._zoomInButton)
        
        self.setLayout(layout)
        
        # create connections
        self._zoomSlider.valueChanged.connect(self.emitZoomAmountChanged)
        self._zoomInButton.clicked.connect(self.zoomIn)
        self._zoomOutButton.clicked.connect(self.zoomOut)
    
    def emitZoomAmountChanged(self):
        """
        Emits the current zoom amount, provided the signals are not being
        blocked.
        """
        if not self.signalsBlocked():
            self.zoomAmountChanged.emit(self.zoomAmount())
    
    def maximum(self):
        """
        Returns the maximum zoom level for this widget.
        
        :return     <int>
        """
        return self._zoomSlider.maximum()
    
    def minimum(self):
        """
        Returns the minimum zoom level for this widget.
        
        :return     <int>
        """
        return self._zoomSlider.minimum()
    
    def setMaximum(self, maximum):
        """
        Sets the maximum zoom level for this widget.
        
        :param      maximum | <int>
        """
        self._zoomSlider.setMaximum(minimum)
    
    def setMinimum(self, minimum):
        """
        Sets the minimum zoom level for this widget.
        
        :param      minimum | <int>
        """
        self._zoomSlider.setMinimum(minimum)
    
    def setZoomStep(self, amount):
        """
        Sets how much a single step for the zoom in/out will be.
        
        :param      amount | <int>
        """
        self._zoomSlider.setPageStep(amount)
    
    @Slot(int)
    def setZoomAmount(self, amount):
        """
        Sets the zoom amount for this widget to the inputed amount.
        
        :param      amount | <int>
        """
        self._zoomSlider.setValue(amount)
    
    def zoomAmount(self):
        """
        Returns the current zoom amount for this widget.
        
        :return     <int>
        """
        return self._zoomSlider.value()
    
    @Slot()
    def zoomIn(self):
        """
        Zooms in by a single page step.
        """
        self._zoomSlider.triggerAction(QSlider.SliderPageStepAdd)
    
    def zoomInButton(self):
        """
        Returns the zoom in button from the left side of this widget.
        
        :return     <QToolButton>
        """
        return self._zoomInButton
    
    @Slot()
    def zoomOut(self):
        """
        Zooms out by a single page step.
        """
        self._zoomSlider.triggerAction(QSlider.SliderPageStepSub)
    
    def zoomOutButton(self):
        """
        Returns the zoom out button from the right side of this widget.
        
        :return     <QToolButton>
        """
        return self._zoomOutButton
    
    def zoomSlider(self):
        """
        Returns the slider widget of this zoom slider.
        
        :return     <QSlider>
        """
        return self._zoomSlider
    
    def zoomStep(self):
        """
        Returns the amount for a single step when the user clicks the zoom in/
        out amount.
        
        :return     <int>
        """
        return self._zoomSlider.pageStep()
    
    x_maximum  = Property(int, maximum, setMaximum)
    x_minimum  = Property(int, minimum, setMinimum)
    z_zoomStep = Property(int, zoomStep, setZoomStep)
Example #33
0
class EditGeometryProperties(QDialog):
    force = True
    allow_update = True
    def __init__(self, data, win_parent=None):
        """
        +------------------+
        | Edit Actor Props |
        +------------------+------+
        |  Name1                  |
        |  Name2                  |
        |  Name3                  |
        |  Name4                  |
        |                         |
        |  Active_Name    main    |
        |  Color          box     |
        |  Line_Width     2       |
        |  Point_Size     2       |
        |  Bar_Scale      2       |
        |  Opacity        0.5     |
        |  Show/Hide              |
        |                         |
        |    Apply   OK   Cancel  |
        +-------------------------+
        """
        QDialog.__init__(self, win_parent)
        self.setWindowTitle('Edit Geometry Properties')

        #default
        self.win_parent = win_parent
        self.out_data = data

        self.keys = sorted(data.keys())
        self.keys = data.keys()
        keys = self.keys
        nrows = len(keys)
        self.active_key = 'main'#keys[0]

        items = keys

        header_labels = ['Groups']
        table_model = Model(items, header_labels, self)
        view = CustomQTableView(self) #Call your custom QTableView here
        view.setModel(table_model)
        if qt_version == 4:
            view.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)

        self.table = view

        actor_obj = data[self.active_key]
        name = actor_obj.name
        line_width = actor_obj.line_width
        point_size = actor_obj.point_size
        bar_scale = actor_obj.bar_scale
        opacity = actor_obj.opacity
        color = actor_obj.color
        show = actor_obj.is_visible
        self.representation = actor_obj.representation

        # table
        header = self.table.horizontalHeader()
        header.setStretchLastSection(True)

        self._default_is_apply = False
        self.name = QLabel("Name:")
        self.name_edit = QLineEdit(str(name))
        self.name_edit.setDisabled(True)

        self.color = QLabel("Color:")
        self.color_edit = QPushButton()
        #self.color_edit.setFlat(True)

        color = self.out_data[self.active_key].color
        qcolor = QtGui.QColor()
        qcolor.setRgb(*color)
        #print('color =%s' % str(color))
        palette = QtGui.QPalette(self.color_edit.palette()) # make a copy of the palette
        #palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Base, \
                         #qcolor)
        palette.setColor(QtGui.QPalette.Background, QtGui.QColor('blue'))  # ButtonText
        self.color_edit.setPalette(palette)

        self.color_edit.setStyleSheet("QPushButton {"
                                      "background-color: rgb(%s, %s, %s);" % tuple(color) +
                                      #"border:1px solid rgb(255, 170, 255); "
                                      "}")

        self.use_slider = True
        self.is_opacity_edit_active = False
        self.is_opacity_edit_slider_active = False

        self.is_line_width_edit_active = False
        self.is_line_width_edit_slider_active = False

        self.is_point_size_edit_active = False
        self.is_point_size_edit_slider_active = False

        self.is_bar_scale_edit_active = False
        self.is_bar_scale_edit_slider_active = False

        self.opacity = QLabel("Opacity:")
        self.opacity_edit = QDoubleSpinBox(self)
        self.opacity_edit.setRange(0.1, 1.0)
        self.opacity_edit.setDecimals(1)
        self.opacity_edit.setSingleStep(0.1)
        self.opacity_edit.setValue(opacity)
        if self.use_slider:
            self.opacity_slider_edit = QSlider(QtCore.Qt.Horizontal)
            self.opacity_slider_edit.setRange(1, 10)
            self.opacity_slider_edit.setValue(opacity * 10)
            self.opacity_slider_edit.setTickInterval(1)
            self.opacity_slider_edit.setTickPosition(QSlider.TicksBelow)

        self.line_width = QLabel("Line Width:")
        self.line_width_edit = QSpinBox(self)
        self.line_width_edit.setRange(1, 15)
        self.line_width_edit.setSingleStep(1)
        self.line_width_edit.setValue(line_width)
        if self.use_slider:
            self.line_width_slider_edit = QSlider(QtCore.Qt.Horizontal)
            self.line_width_slider_edit.setRange(1, 15)
            self.line_width_slider_edit.setValue(line_width)
            self.line_width_slider_edit.setTickInterval(1)
            self.line_width_slider_edit.setTickPosition(QSlider.TicksBelow)

        if self.representation in ['point', 'surface']:
            self.line_width.setEnabled(False)
            self.line_width_edit.setEnabled(False)
            self.line_width_slider_edit.setEnabled(False)

        self.point_size = QLabel("Point Size:")
        self.point_size_edit = QSpinBox(self)
        self.point_size_edit.setRange(1, 15)
        self.point_size_edit.setSingleStep(1)
        self.point_size_edit.setValue(point_size)
        self.point_size.setVisible(False)
        self.point_size_edit.setVisible(False)
        if self.use_slider:
            self.point_size_slider_edit = QSlider(QtCore.Qt.Horizontal)
            self.point_size_slider_edit.setRange(1, 15)
            self.point_size_slider_edit.setValue(point_size)
            self.point_size_slider_edit.setTickInterval(1)
            self.point_size_slider_edit.setTickPosition(QSlider.TicksBelow)
            self.point_size_slider_edit.setVisible(False)

        if self.representation in ['wire', 'surface']:
            self.point_size.setEnabled(False)
            self.point_size_edit.setEnabled(False)
            if self.use_slider:
                self.point_size_slider_edit.setEnabled(False)

        self.bar_scale = QLabel("Bar Scale:")
        self.bar_scale_edit = QDoubleSpinBox(self)
        #self.bar_scale_edit.setRange(0.01, 1.0)  # was 0.1
        #self.bar_scale_edit.setRange(0.05, 5.0)
        self.bar_scale_edit.setDecimals(1)
        #self.bar_scale_edit.setSingleStep(bar_scale / 10.)
        self.bar_scale_edit.setSingleStep(0.1)
        self.bar_scale_edit.setValue(bar_scale)

        #if self.use_slider:
            #self.bar_scale_slider_edit = QSlider(QtCore.Qt.Horizontal)
            #self.bar_scale_slider_edit.setRange(1, 100)  # 1/0.05 = 100/5.0
            #self.bar_scale_slider_edit.setValue(opacity * 0.05)
            #self.bar_scale_slider_edit.setTickInterval(10)
            #self.bar_scale_slider_edit.setTickPosition(QSlider.TicksBelow)

        if self.representation != 'bar':
            self.bar_scale.setEnabled(False)
            self.bar_scale_edit.setEnabled(False)
            self.bar_scale.setVisible(False)
            self.bar_scale_edit.setVisible(False)
            #self.bar_scale_slider_edit.setVisible(False)
            #self.bar_scale_slider_edit.setEnabled(False)

        # show/hide
        self.checkbox_show = QCheckBox("Show")
        self.checkbox_hide = QCheckBox("Hide")
        self.checkbox_show.setChecked(show)
        self.checkbox_hide.setChecked(not show)

        if name == 'main':
            self.color.setEnabled(False)
            self.color_edit.setEnabled(False)
            self.point_size.setEnabled(False)
            self.point_size_edit.setEnabled(False)
            if self.use_slider:
                self.point_size_slider_edit.setEnabled(False)


        # closing
        # self.apply_button = QPushButton("Apply")
        #if self._default_is_apply:
            #self.apply_button.setDisabled(True)

        # self.ok_button = QPushButton("OK")
        self.cancel_button = QPushButton("Close")

        self.create_layout()
        self.set_connections()

    def on_update_geometry_properties_window(self, data):
        """Not Implemented"""
        return
        new_keys = sorted(data.keys())
        if self.active_key in new_keys:
            i = new_keys.index(self.active_key)
        else:
            i = 0
        self.table.update_data(new_keys)
        self.out_data = data
        self.update_active_key(i)

    def update_active_key(self, index):
        """
        Parameters
        ----------
        index : PyQt4.QtCore.QModelIndex
            the index of the list

        Internal Parameters
        -------------------
        name : str
            the name of obj
        obj : CoordProperties, AltGeometry
            the storage object for things like line_width, point_size, etc.
        """
        old_obj = self.out_data[self.active_key]
        old_obj.line_width = self.line_width_edit.value()
        old_obj.point_size = self.point_size_edit.value()
        old_obj.bar_scale = self.bar_scale_edit.value()
        old_obj.opacity = self.opacity_edit.value()
        old_obj.is_visible = self.checkbox_show.isChecked()

        if qt_version == 4:
            name = str(index.data().toString())
        else:
            name = str(index.data())
            print('name = %r' % name)
        #i = self.keys.index(self.active_key)

        self.active_key = name
        self.name_edit.setText(name)
        obj = self.out_data[name]
        if isinstance(obj, CoordProperties):
            opacity = 1.0
            representation = 'coord'
            is_visible = obj.is_visible
        elif isinstance(obj, AltGeometry):
            line_width = obj.line_width
            point_size = obj.point_size
            bar_scale = obj.bar_scale
            opacity = obj.opacity
            representation = obj.representation
            is_visible = obj.is_visible

            self.color_edit.setStyleSheet("QPushButton {"
                                          "background-color: rgb(%s, %s, %s);" % tuple(obj.color) +
                                          #"border:1px solid rgb(255, 170, 255); "
                                          "}")
            self.allow_update = False
            self.force = False
            self.line_width_edit.setValue(line_width)
            self.point_size_edit.setValue(point_size)
            self.bar_scale_edit.setValue(bar_scale)
            self.force = True
            self.allow_update = True
        else:
            raise NotImplementedError(obj)

        allowed_representations = [
            'main', 'surface', 'coord', 'toggle', 'wire', 'point', 'bar']

        if self.representation != representation:
            self.representation = representation
            if representation not in allowed_representations:
                msg = 'name=%r; representation=%r is invalid\nrepresentations=%r' % (
                    name, representation, allowed_representations)

            if self.representation == 'coord':
                self.color.setVisible(False)
                self.color_edit.setVisible(False)
                self.line_width.setVisible(False)
                self.line_width_edit.setVisible(False)
                self.point_size.setVisible(False)
                self.point_size_edit.setVisible(False)
                self.bar_scale.setVisible(False)
                self.bar_scale_edit.setVisible(False)
                self.opacity.setVisible(False)
                self.opacity_edit.setVisible(False)
                if self.use_slider:
                    self.opacity_slider_edit.setVisible(False)
                    self.point_size_slider_edit.setVisible(False)
                    self.line_width_slider_edit.setVisible(False)
                    #self.bar_scale_slider_edit.setVisible(False)
            else:
                self.color.setVisible(True)
                self.color_edit.setVisible(True)
                self.line_width.setVisible(True)
                self.line_width_edit.setVisible(True)
                self.point_size.setVisible(True)
                self.point_size_edit.setVisible(True)
                self.bar_scale.setVisible(True)
                #self.bar_scale_edit.setVisible(True)
                self.opacity.setVisible(True)
                self.opacity_edit.setVisible(True)
                if self.use_slider:
                    self.opacity_slider_edit.setVisible(True)
                    self.line_width_slider_edit.setVisible(True)
                    self.point_size_slider_edit.setVisible(True)
                    #self.bar_scale_slider_edit.setVisible(True)

                if name == 'main':
                    self.color.setEnabled(False)
                    self.color_edit.setEnabled(False)
                    self.point_size.setEnabled(False)
                    self.point_size_edit.setEnabled(False)
                    self.line_width.setEnabled(True)
                    self.line_width_edit.setEnabled(True)
                    self.bar_scale.setEnabled(False)
                    self.bar_scale_edit.setEnabled(False)
                    show_points = False
                    show_line_width = True
                    show_bar_scale = False
                    if self.use_slider:
                        self.line_width_slider_edit.setEnabled(True)
                        #self.bar_scale_slider_edit.setVisible(False)
                else:
                    self.color.setEnabled(True)
                    self.color_edit.setEnabled(True)

                    show_points = False
                    if self.representation in ['point', 'wire+point']:
                        show_points = True

                    show_line_width = False
                    if self.representation in ['wire', 'wire+point', 'bar']:
                        show_line_width = True

                    if representation == 'bar':
                        show_bar_scale = True
                    else:
                        show_bar_scale = False
                    #self.bar_scale_button.setVisible(show_bar_scale)
                    #self.bar_scale_edit.setSingleStep(bar_scale / 10.)
                    #if self.use_slider:
                        #self.bar_scale_slider_edit.setEnabled(False)

                self.point_size.setEnabled(show_points)
                self.point_size_edit.setEnabled(show_points)
                self.point_size.setVisible(show_points)
                self.point_size_edit.setVisible(show_points)

                self.line_width.setEnabled(show_line_width)
                self.line_width_edit.setEnabled(show_line_width)

                self.bar_scale.setEnabled(show_bar_scale)
                self.bar_scale_edit.setEnabled(show_bar_scale)
                self.bar_scale.setVisible(show_bar_scale)
                self.bar_scale_edit.setVisible(show_bar_scale)
                if self.use_slider:
                    self.point_size_slider_edit.setEnabled(show_points)
                    self.point_size_slider_edit.setVisible(show_points)
                    self.line_width_slider_edit.setEnabled(show_line_width)


            #if self.representation in ['wire', 'surface']:

        self.opacity_edit.setValue(opacity)
        #if self.use_slider:
            #self.opacity_slider_edit.setValue(opacity*10)
        self.checkbox_show.setChecked(is_visible)
        self.checkbox_hide.setChecked(not is_visible)

        passed = self.on_validate()
        #self.on_apply(force=True)  # TODO: was turned on...do I want this???
        #self.allow_update = True

    #def on_name_select(self):
        #print('on_name_select')
        #return

    def create_layout(self):
        ok_cancel_box = QHBoxLayout()
        # ok_cancel_box.addWidget(self.apply_button)
        # ok_cancel_box.addWidget(self.ok_button)
        ok_cancel_box.addWidget(self.cancel_button)

        grid = QGridLayout()

        irow = 0
        grid.addWidget(self.name, irow, 0)
        grid.addWidget(self.name_edit, irow, 1)
        irow += 1

        grid.addWidget(self.color, irow, 0)
        grid.addWidget(self.color_edit, irow, 1)
        irow += 1

        grid.addWidget(self.opacity, irow, 0)
        if self.use_slider:
            grid.addWidget(self.opacity_edit, irow, 2)
            grid.addWidget(self.opacity_slider_edit, irow, 1)
        else:
            grid.addWidget(self.opacity_edit, irow, 1)
        irow += 1

        grid.addWidget(self.line_width, irow, 0)
        if self.use_slider:
            grid.addWidget(self.line_width_edit, irow, 2)
            grid.addWidget(self.line_width_slider_edit, irow, 1)
        else:
            grid.addWidget(self.line_width_edit, irow, 1)
        irow += 1

        grid.addWidget(self.point_size, irow, 0)
        if self.use_slider:
            grid.addWidget(self.point_size_edit, irow, 2)
            grid.addWidget(self.point_size_slider_edit, irow, 1)
        else:
            grid.addWidget(self.point_size_edit, irow, 1)
        irow += 1

        grid.addWidget(self.bar_scale, irow, 0)
        if self.use_slider and 0:
            grid.addWidget(self.bar_scale_edit, irow, 2)
            grid.addWidget(self.bar_scale_slider_edit, irow, 1)
        else:
            grid.addWidget(self.bar_scale_edit, irow, 1)
        irow += 1

        checkboxs = QButtonGroup(self)
        checkboxs.addButton(self.checkbox_show)
        checkboxs.addButton(self.checkbox_hide)

        vbox = QVBoxLayout()
        vbox.addWidget(self.table)
        vbox.addLayout(grid)

        if 0:
            vbox.addWidget(self.checkbox_show)
            vbox.addWidget(self.checkbox_hide)
        else:
            vbox1 = QVBoxLayout()
            vbox1.addWidget(self.checkbox_show)
            vbox1.addWidget(self.checkbox_hide)
            vbox.addLayout(vbox1)

        vbox.addStretch()
        #vbox.addWidget(self.check_apply)
        vbox.addLayout(ok_cancel_box)
        self.setLayout(vbox)

    def set_connections(self):
        # self.opacity_edit.connect(arg0, QObject, arg1)
        if qt_version == 4:
            self.connect(self.opacity_edit, QtCore.SIGNAL('valueChanged(double)'), self.on_opacity)
                #self.connect(self.opacity_slider_edit, QtCore.SIGNAL('valueChanged(double)'), self.on_opacity)
                #grid.addWidget(self.opacity_slider_edit, irow, 1)

            # self.connect(self.line_width, QtCore.SIGNAL('valueChanged(int)'), self.on_line_width)
            # self.connect(self.point_size, QtCore.SIGNAL('valueChanged(int)'), self.on_point_size)

            # self.connect(self.line_width, QtCore.SIGNAL('valueChanged(const QString&)'), self.on_line_width)
            # self.connect(self.point_size, QtCore.SIGNAL('valueChanged(const QString&)'), self.on_point_size)
            self.connect(self.line_width_edit, QtCore.SIGNAL('valueChanged(int)'), self.on_line_width)
            self.connect(self.point_size_edit, QtCore.SIGNAL('valueChanged(int)'), self.on_point_size)
            self.connect(self.bar_scale_edit, QtCore.SIGNAL('valueChanged(double)'), self.on_bar_scale)
        else:
            self.opacity_edit.valueChanged.connect(self.on_opacity)
            self.line_width_edit.valueChanged.connect(self.on_line_width)
            self.point_size_edit.valueChanged.connect(self.on_point_size)
            self.bar_scale_edit.valueChanged.connect(self.on_bar_scale)

        if self.use_slider:
            self.opacity_slider_edit.valueChanged.connect(self.on_opacity_slider)
            self.line_width_slider_edit.valueChanged.connect(self.on_line_width_slider)
            self.point_size_slider_edit.valueChanged.connect(self.on_point_size_slider)
            #self.bar_scale_slider_edit.valueChanged.connect(self.on_bar_scale_slider)



        # self.connect(self.opacity_edit, QtCore.SIGNAL('clicked()'), self.on_opacity)
        # self.connect(self.line_width, QtCore.SIGNAL('clicked()'), self.on_line_width)
        # self.connect(self.point_size, QtCore.SIGNAL('clicked()'), self.on_point_size)

        if qt_version == 4:
            self.connect(self.color_edit, QtCore.SIGNAL('clicked()'), self.on_color)
            self.connect(self.checkbox_show, QtCore.SIGNAL('clicked()'), self.on_show)
            self.connect(self.checkbox_hide, QtCore.SIGNAL('clicked()'), self.on_hide)
            #self.connect(self.check_apply, QtCore.SIGNAL('clicked()'), self.on_check_apply)

            # self.connect(self.apply_button, QtCore.SIGNAL('clicked()'), self.on_apply)
            # self.connect(self.ok_button, QtCore.SIGNAL('clicked()'), self.on_ok)
            self.connect(self.cancel_button, QtCore.SIGNAL('clicked()'), self.on_cancel)
            self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent)
        else:
            self.color_edit.clicked.connect(self.on_color)
            self.checkbox_show.clicked.connect(self.on_show)
            self.checkbox_hide.clicked.connect(self.on_hide)
            self.cancel_button.clicked.connect(self.on_cancel)
            # closeEvent

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.close()

    def closeEvent(self, event):
        self.on_cancel()

    def on_color(self):
        name = self.active_key
        obj = self.out_data[name]
        rgb_color_ints = obj.color

        msg = name
        col = QtGui.QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self, "Choose a %s color" % msg)
        if col.isValid():
            color = col.getRgbF()[:3]
            obj.color = color
            #print('new_color =', color)
            self.color_edit.setStyleSheet("QPushButton {"
                                          "background-color: rgb(%s, %s, %s);" % tuple(obj.color) +
                                          #"border:1px solid rgb(255, 170, 255); "
                                          "}")
        self.on_apply(force=self.force)

    def on_show(self):
        name = self.active_key
        is_checked = self.checkbox_show.isChecked()
        self.out_data[name].is_visible = is_checked
        self.on_apply(force=self.force)

    def on_hide(self):
        name = self.active_key
        is_checked = self.checkbox_hide.isChecked()
        self.out_data[name].is_visible = not is_checked
        self.on_apply(force=self.force)

    def on_line_width(self):
        self.is_line_width_edit_active = True
        name = self.active_key
        line_width = self.line_width_edit.value()
        self.out_data[name].line_width = line_width
        if not self.is_line_width_edit_slider_active:
            if self.use_slider:
                self.line_width_slider_edit.setValue(line_width)
            self.is_line_width_edit_active = False
        self.on_apply(force=self.force)
        self.is_line_width_edit_active = False

    def on_line_width_slider(self):
        self.is_line_width_edit_slider_active = True
        name = self.active_key
        line_width = self.line_width_slider_edit.value()
        if not self.is_line_width_edit_active:
            self.line_width_edit.setValue(line_width)
        self.is_line_width_edit_slider_active = False

    def on_point_size(self):
        self.is_point_size_edit_active = True
        name = self.active_key
        point_size = self.point_size_edit.value()
        self.out_data[name].point_size = point_size
        if not self.is_point_size_edit_slider_active:
            if self.use_slider:
                self.point_size_slider_edit.setValue(point_size)
            self.is_point_size_edit_active = False
        self.on_apply(force=self.force)
        self.is_point_size_edit_active = False

    def on_point_size_slider(self):
        self.is_point_size_edit_slider_active = True
        name = self.active_key
        point_size = self.point_size_slider_edit.value()
        if not self.is_point_size_edit_active:
            self.point_size_edit.setValue(point_size)
        self.is_point_size_edit_slider_active = False

    def on_bar_scale(self):
        self.is_bar_scale_edit_active = True
        name = self.active_key
        float_bar_scale = self.bar_scale_edit.value()
        self.out_data[name].bar_scale = float_bar_scale
        if not self.is_bar_scale_edit_slider_active:
            int_bar_scale = int(round(float_bar_scale * 20, 0))
            #if self.use_slider:
                #self.bar_scale_slider_edit.setValue(int_bar_scale)
            self.is_bar_scale_edit_active = False
        self.on_apply(force=self.force)
        self.is_bar_scale_edit_active = False

    def on_bar_scale_slider(self):
        self.is_bar_scale_edit_slider_active = True
        name = self.active_key
        int_bar_scale = self.bar_scale_slider_edit.value()
        if not self.is_bar_scale_edit_active:
            float_bar_scale = int_bar_scale / 20.
            self.bar_scale_edit.setValue(float_bar_scale)
        self.is_bar_scale_edit_slider_active = False

    def on_opacity(self):
        self.is_opacity_edit_active = True
        name = self.active_key
        float_opacity = self.opacity_edit.value()
        self.out_data[name].opacity = float_opacity
        if not self.is_opacity_edit_slider_active:
            int_opacity = int(round(float_opacity * 10, 0))
            if self.use_slider:
                self.opacity_slider_edit.setValue(int_opacity)
            self.is_opacity_edit_active = False
        self.on_apply(force=self.force)
        self.is_opacity_edit_active = False

    def on_opacity_slider(self):
        self.is_opacity_edit_slider_active = True
        name = self.active_key
        int_opacity = self.opacity_slider_edit.value()
        if not self.is_opacity_edit_active:
            float_opacity = int_opacity / 10.
            self.opacity_edit.setValue(float_opacity)
        self.is_opacity_edit_slider_active = False

    #def on_axis(self, text):
        ##print(self.combo_axis.itemText())
        #self._axis = str(text)
        #self.plane.setText('Point on %s? Plane:' % self._axis)
        #self.point_a.setText('Point on %s Axis:' % self._axis)
        #self.point_b.setText('Point on %s%s Plane:' % (self._axis, self._plane))

    #def on_plane(self, text):
        #self._plane = str(text)
        #self.point_b.setText('Point on %s%s Plane:' % (self._axis, self._plane))

    def on_check_apply(self):
        is_checked = self.check_apply.isChecked()
        self.apply_button.setDisabled(is_checked)

    def _on_float(self, field):
        try:
            eval_float_from_string(field.text())
            field.setStyleSheet("QLineEdit{background: white;}")
        except ValueError:
            field.setStyleSheet("QLineEdit{background: red;}")

    #def on_default_name(self):
        #self.name_edit.setText(str(self._default_name))
        #self.name_edit.setStyleSheet("QLineEdit{background: white;}")

    #def check_float(self, cell):
        #text = cell.text()
        #try:
            #value = eval_float_from_string(text)
            #cell.setStyleSheet("QLineEdit{background: white;}")
            #return value, True
        #except ValueError:
            #cell.setStyleSheet("QLineEdit{background: red;}")
            #return None, False

    #def check_name(self, cell):
        #text = str(cell.text()).strip()
        #if len(text):
            #cell.setStyleSheet("QLineEdit{background: white;}")
            #return text, True
        #else:
            #cell.setStyleSheet("QLineEdit{background: red;}")
            #return None, False

    def on_validate(self):
        self.out_data['clicked_ok'] = True
        self.out_data['clicked_cancel'] = False

        old_obj = self.out_data[self.active_key]
        old_obj.line_width = self.line_width_edit.value()
        old_obj.point_size = self.point_size_edit.value()
        old_obj.bar_scale = self.bar_scale_edit.value()
        old_obj.opacity = self.opacity_edit.value()
        old_obj.is_visible = self.checkbox_show.isChecked()
        return True
        #name_value, flag0 = self.check_name(self.name_edit)
        #ox_value, flag1 = self.check_float(self.transparency_edit)
        #if flag0 and flag1:
            #self.out_data['clicked_ok'] = True
            #return True
        #return False

    def on_apply(self, force=False):
        passed = self.on_validate()
        if (passed or force) and self.allow_update:
            self.win_parent.on_update_geometry_properties(self.out_data)
        return passed

    def on_cancel(self):
        passed = self.on_apply(force=True)
        if passed:
            self.close()
Example #34
0
def metronome():
    import os, sys, time
    from PyQt4.QtCore import SIGNAL
    from PyQt4.QtGui import QApplication, QPushButton, QSlider, QWidget
    from PyQt4.QtGui import QHBoxLayout, QLabel
    import synths

    START = False
    
    app = QApplication(sys.argv)
    if START:
        server = scsynth.server.start(verbose=True, spew=True)
    else:
        server = scsynth.server.connect(verbose=True, spew=True)
    engine = Engine(server, app, spew=True, quit_on_delete=START)
    server.sendMsg('/dumpOSC', 1)
    engine.tempoclock.set_tempo(120)

    SYNTHDEF_PATH = os.path.join(os.path.expanduser('~'),
                                 '.pksampler', 'synthdefs')
    SYNTHDEFS = ('JASStereoSamplePlayer.scsyndef',
                 'JASSine.scsyndef',
                 )
    for fname in SYNTHDEFS:
        engine.server.sendMsg('/d_load', os.path.join(SYNTHDEF_PATH, fname))
    
    FPATH = '/Users/patrick/.pksampler/clicks/click_1.wav'
    click = synths.Synth()
    click.name = 'JASStereoSamplePlayer'
    click['bufnum'] = engine.loader.load(FPATH)
    click['rateSCale'] = 1.2
    click['loopIt'] = 0
    time.sleep(.1)

    pattern = Pattern(beats=1)
    pattern.add(Note(0, 64, 69))
    pattern.synth = click
    stream = engine.insert(pattern)
    stream.loop(True)

    widget = QWidget()
    Layout = QHBoxLayout(widget)
    widget.resize(100, 250)
    widget.show()

    label = QLabel(widget)
    label.setText(str(engine.tempoclock.bpm))
    Layout.addWidget(label)
    
    def set_tempo(value):
        engine.tempoclock.set_tempo(value)
        label.setText(str(value))

    slider = QSlider(widget)
    slider.setRange(100, 180)
    slider.setValue(140)
    QObject.connect(slider, SIGNAL('valueChanged(int)'), set_tempo)
    Layout.addWidget(slider)

    button = QPushButton('quit', widget)
    QObject.connect(button, SIGNAL('clicked()'), app.quit)
    Layout.addWidget(button)

    engine.start()
    app.exec_()
    engine.stop()
from PyQt4.QtCore import Qt, QObject, SIGNAL, SLOT
from PyQt4.QtGui import QApplication
from PyQt4.QtGui import QWidget, QSpinBox, QSlider, QHBoxLayout
import sys

if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = QWidget()
    window.setWindowTitle("Enter Your Age")

    spinBox = QSpinBox()
    slider = QSlider(Qt.Horizontal)
    spinBox.setRange(0, 130)
    slider.setRange(0, 130)

    QObject.connect(spinBox, SIGNAL("valueChanged(int)"), slider,
                    SLOT("setValue(int)"))

    QObject.connect(slider, SIGNAL("valueChanged(int)"), spinBox,
                    SLOT("setValue(int)"))

    spinBox.setValue(35)

    layout = QHBoxLayout()  # 水平布局
    layout.addWidget(spinBox)  # 添加 水平 布局
    layout.addWidget(slider)  # 添加 水平 布局

    window.setLayout(layout)
Example #36
0
class Player(QWidget):
    def __init__(self,app):
        super(Player,self).__init__()
        self.mpd   = app.mpd
        self.ih    = app.imagehelper
        self.timer = None
        self.initGUI()
        self.initState()
        
    def initGUI(self):
        self.setWindowTitle(QApplication.applicationName())
        self.fmt = QFontMetrics(QFont())
        layout = QVBoxLayout()
        
        toplayout = QHBoxLayout()
        currentLayout = QGridLayout()
        currentLayout.setContentsMargins(0,20,0,20)
        currentLayout.setHorizontalSpacing(100)
        currentLayout.setVerticalSpacing(20)
        # current song information
        currentLayout.addWidget(QLabel("<b>Artist</b>"),1,0)
        self.artist = QLabel()
        currentLayout.addWidget(self.artist,1,1)
        currentLayout.addWidget(QLabel("<b>Title</b>"),2,0)
        self.title  = QLabel()
        currentLayout.addWidget(self.title,2,1)
        currentLayout.addWidget(QLabel("<b>Albumartist</b>"),3,0)
        self.albumartist = QLabel()
        currentLayout.addWidget(self.albumartist,3,1)
        currentLayout.addWidget(QLabel("<b>Album</b>"),4,0)
        self.album  = QLabel()
        currentLayout.addWidget(self.album,4,1)
        # playlist and song position
        self.playlistposition = QLabel()
        currentLayout.addWidget(self.playlistposition,5,0)
        poslayout = QHBoxLayout()
        poslayout.setSpacing(10)
        self.time = QLabel("00:00")
        poslayout.addWidget(self.time)
        self.position = QSlider(Qt.Horizontal)
        self.position.setTracking(False)
        self.position.setSingleStep(10)
        self.position.sliderReleased.connect( self.seek)
        self.position.sliderMoved.connect(
            lambda x: self.time.setText(self.mpd.timeString(x)))
        poslayout.addWidget(self.position)
        self.length = QLabel("00:00")
        poslayout.addWidget(self.length)
        currentLayout.addLayout(poslayout,5,1)
        toplayout.addLayout(currentLayout)
        layout.addLayout(toplayout)
        layout.addStretch(1)
        
        self.settingsWidget = QMenu()
        self.consumeBtn = self.settingsWidget.addAction("Consume")
        self.consumeBtn.setCheckable(True)
        self.consumeBtn.triggered.connect( lambda x: self.mpd.consume(int(x)))
        self.singleBtn  = self.settingsWidget.addAction("Single")
        self.singleBtn.setCheckable(True)
        self.singleBtn.triggered.connect( lambda x: self.mpd.single(int(x)))
        
        toolLayout = QHBoxLayout()
        self.settingsBtn = QToolButton()
        self.settingsBtn.setFixedSize(64,64)
        self.settingsBtn.setIcon( self.ih.settingsButton)
        self.settingsBtn.clicked.connect(self.showAdditionalControls)
        toolLayout.addWidget(self.settingsBtn)

        
        toolWidget = QStackedWidget()
        transpWidget = QWidget()
        transpLayout = QHBoxLayout()
        self.prevBtn = self.createButton(
            self.ih.prevButton, self.ih.prevButtonPressed)
        self.prevBtn.clicked.connect( lambda x: self.mpd.previous())
        transpLayout.addWidget(self.prevBtn)
        self.playBtn = self.createCheckButton(
            self.ih.playButton, self.ih.pauseButton)
        self.playBtn.clicked.connect( self.playPressed)
        transpLayout.addWidget(self.playBtn)
        self.stopBtn = self.createButton(
            self.ih.stopButton, self.ih.stopButtonPressed)
        self.stopBtn.clicked.connect( lambda x: self.mpd.stop())
        transpLayout.addWidget(self.stopBtn)
        self.nextBtn = self.createButton(
            self.ih.nextButton, self.ih.nextButtonPressed)
        self.nextBtn.clicked.connect( lambda x: self.mpd.next())
        transpLayout.addWidget(self.nextBtn)
        self.shuffleBtn = self.createCheckButton(
            self.ih.shuffleButton, self.ih.shuffleButtonPressed)
        self.shuffleBtn.toggled.connect(
            lambda x: self.mpd.random(1) if x else self.mpd.random(0))
        transpLayout.addWidget(self.shuffleBtn)
        self.repeatBtn = self.createCheckButton(
            self.ih.repeatButton, self.ih.repeatButtonPressed)
        self.repeatBtn.toggled.connect(
            lambda x: self.mpd.repeat(1) if x else self.mpd.repeat(0))
        transpLayout.addWidget(self.repeatBtn)
        transpLayout.addSpacing(64)
        transpWidget.setLayout(transpLayout)
        toolWidget.addWidget( transpWidget)
        
        self.volume = QSlider(Qt.Horizontal)
        self.volume.valueChanged.connect(self.mpd.setvol)
        toolWidget.addWidget(self.volume)
        
        toolLayout.addWidget(toolWidget)
        self.volumeBtn = QToolButton()
        self.volumeBtn.setFixedSize(64,64)
        self.volumeBtn.setCheckable(True)
        self.volumeBtn.setIcon( self.ih.volumeButton)
        self.volumeBtn.toggled.connect(
            lambda x: toolWidget.setCurrentIndex(x))
        toolLayout.addWidget(self.volumeBtn)
        layout.addLayout(toolLayout)
        self.setLayout(layout)

    def showAdditionalControls(self):
        pos = self.settingsBtn.pos()
        pos.setY( pos.y()-self.settingsWidget.sizeHint().height())
        self.settingsWidget.popup( self.mapToGlobal(pos))

    def createCheckButton(self, offIcon, onIcon):
        i = QIcon()
        i.addPixmap( offIcon.pixmap(64), QIcon.Normal, QIcon.Off)
        i.addPixmap(  onIcon.pixmap(64), QIcon.Normal, QIcon.On)
        b = QToolButton()
        b.setFixedSize(64,64)
        b.setCheckable(True)
        b.setIcon(i)
        b.setStyleSheet("* { background: transparent }")
        return b

    def createButton(self, normal, pressed):
        b = QToolButton()
        b.setFixedSize(64,64)
        b.setIcon(normal)
        b.setStyleSheet("* { background: transparent }")
        b.pressed.connect( lambda: b.setIcon(pressed))
        b.released.connect( lambda: b.setIcon(normal))
        return b
    
    def playPressed(self,state):
        if   self.state == 'stop': self.mpd.play()
        else: self.mpd.pause(int(not state))
        
    def initState(self):
        self.songid  = -1
        self.state = 'stop'
        self.artist.setText("Unknown Artist")
        self.title.setText("Unknown Title")
        self.albumartist.setText("Unknown Artist")
        self.album.setText("Unknown Album")
        self.position.setRange(0,0)
        self.position.setValue(0)
        self.position.setEnabled(False)
        self.length.setText("00:00")
        self.playlistposition.setText("0/0")
        self.setStopState()
        
    def setStopState(self):
        self.playBtn.setChecked(False)
        self.time.setText("00:00")
        self.position.setValue(0)
        self.volume.setEnabled(False)

    def updateStatus(self):
        status = self.mpd.status()
        self.repeatBtn.setChecked(int(status['repeat']))
        self.shuffleBtn.setChecked(int(status['random']))
        self.consumeBtn.setChecked(int(status['consume']))
        self.singleBtn.setChecked(int(status['single']))
        if not status.has_key('songid') and self.songid != -1:
            self.initState()
            return
        stateChanged = False
        state = status['state']
        if state != self.state:
            stateChanged = True
        self.state = state
        volume = int(status['volume'])
        if self.state == 'play' or self.state == 'pause':
            self.playBtn.setChecked(True if self.state == 'play' else False)
            songid = int(status['songid'])
            if songid != self.songid:
                self.songid = songid
                self.updateCurrentSong()
            playlistlength = int(status['playlistlength'])
            song = int(status.get('song',-1))
            self.playlistposition.setText("%d/%d" % (song+1,playlistlength))
            playlistlength = int(status['playlistlength'])
            elapsed = float(status['elapsed'])
            if not self.position.isSliderDown():
                timeString = self.mpd.timeString(round(elapsed))
                self.time.setFixedSize(
                    (len(timeString)+1)*self.fmt.averageCharWidth(),
                    self.fmt.height())
                self.time.setText(timeString)
                if self.position.maximum() > 0:
                    self.position.setSliderPosition(round(elapsed))
            if stateChanged:
                self.volume.setEnabled(True)
            if not self.volume.isSliderDown():
                self.volume.setValue(volume)
            #nextsong = int(status['nextsong'])
        else:
            if self.songid == -1: return
            self.setStopState()
            
    def updateCurrentSong(self):
        currentsong = self.mpd.unifySongInfo(self.mpd.currentsong())
        self.artist.setText(      currentsong['artist'])
        self.title.setText(       currentsong['title'])
        self.albumartist.setText( currentsong['albumartist'])
        self.album.setText(       currentsong['album'])
        self.length.setText(      currentsong['length'])
        self.position.setRange(0,currentsong['time'])
        self.position.setEnabled(True if self.position.maximum() > 0 else False)
        self.position.setValue(0)
        self.time.setText("00:00")
        self.volume.setEnabled(True)

    def seek(self):
        secs = self.position.sliderPosition()
        if self.songid == -1: return
        self.mpd.seekid(self.songid, secs)
       
    def hideEvent(self, ev):
        if self.timer:
            self.killTimer( self.timer)
            self.timer = None
        super(Player,self).hideEvent(ev)

    def showEvent(self,ev):
        if not self.timer:
            self.updateStatus()
            self.timer = self.startTimer(1000)
        super(Player,self).showEvent(ev)

    def timerEvent(self,ev):
        try:
            self.updateStatus()
        except ConnectionError, e:
            self.hide()
            QMaemo5InformationBox.information(
                self, "Connection Error: %s" % str(e),
                QMaemo5InformationBox.DefaultTimeout)
        except socket.error, e:
            QMaemo5InformationBox.information(
                self, "Connection Error: %s" % e[1],
                QMaemo5InformationBox.DefaultTimeout)
            self.hide()
Example #37
0
class MotorizedPoti(PluginBase):
    def __init__(self, *args):
        PluginBase.__init__(self, BrickletMotorizedPoti, *args)

        self.mp = self.device

        self.cbe_position = CallbackEmulator(self.mp.get_position,
                                             self.cb_position,
                                             self.increase_error_count)

        self.current_position = None

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        self.slider.setMinimumWidth(200)

        plots = [('Position', Qt.red, lambda: self.current_position, str)]
        self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider],
                                      curve_motion_granularity=40, update_interval=0.025)

        self.motor_slider = QSlider(Qt.Horizontal)
        self.motor_slider.setRange(0, 100)
        self.motor_slider.sliderReleased.connect(self.motor_slider_released)
        self.motor_slider.sliderMoved.connect(self.motor_slider_moved)
        self.motor_enable = QCheckBox("Enable Motor")
        self.motor_enable.stateChanged.connect(self.motor_enable_changed)

        self.motor_position_label = MotorPositionLabel('Motor Position: ')

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.motor_position_label)
        hlayout.addWidget(self.motor_slider)
        hlayout.addWidget(self.motor_enable)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(hlayout)

    def start(self):
        async_call(self.mp.get_position, None, self.cb_position, self.increase_error_count)
        async_call(self.mp.get_motor_position, None, self.cb_motor_position, self.increase_error_count)
        async_call(self.mp.is_motor_enabled, None, self.cb_is_motor_enabled, self.increase_error_count)

        self.cbe_position.set_period(25)
        self.plot_widget.stop = False

    def stop(self):
        self.cbe_position.set_period(0)
        self.plot_widget.stop = True

    def destroy(self):
        pass

    def get_url_part(self):
        return 'motorized_poti'

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletMotorizedPoti.DEVICE_IDENTIFIER

    def cb_position(self, position):
        self.current_position = position
        self.slider.setValue(position)

    def cb_motor_position(self, motor_position):
        self.motor_slider.setValue(motor_position.position)
        self.motor_slider_moved(motor_position.position)

    def cb_is_motor_enabled(self, enabled):
        self.motor_enable.setChecked(enabled)

    def motor_slider_moved(self, position):
        self.motor_position_label.setText(str(position))

    def motor_slider_released(self):
        self.mp.set_motor_position(self.motor_slider.value(), False)

    def motor_enable_changed(self, state):
        if self.motor_enable.isChecked():
            self.mp.enable_motor()
        else:
            self.mp.disable_motor()
Example #38
0
class MainWin(QMainWindow):
    def __init__(self, mx, spurs, fef, parent=None, plot_lib='mpl'):
        QMainWindow.__init__(self, parent)

        self.mx = mx
        self.spurset = spurs
        self.fef = fef
    
        if plot_lib == 'qwt':
            from chart.qwtchart import qwtchart as chart
        elif plot_lib == 'mpl':
            from chart.mplchart import mplchart as chart
        elif plot_lib == 'pg':
            from chart.pyqtgraphchart import pyqtgraphchart as chart
        else:
            raise NotImplementedError

        self.chart = chart(self.spurset, self.fef, self)
        self.create_menu_bar()
        self.create_main_frame()
        self.hookup()

    def hookup(self):
        # connect all the objects that are supposed to be watching each other
        # for changes and updates.
        self.mx.register(self.chart.draw_spurs)
        self.spurset.register(self.chart.draw_spurs)
        self.chart.picker_watch(self.fef)
        self.fef.register(self.chart.draw_fef)
        self.chart.draw_spurs(self.spurset)
        self.chart.draw_fef(self.fef)

    def IF_slide(self, i):
        """ callback method for the IF selection slider"""
        self.IFtextbox.setText(str(i))
        self.mx.IF = i

    def about(self):
        msg = '''
        A frequency-planing tool based on the method of spur distances.
        (A reference to the article will go here)
        For more info, view the README included with this program.

        Patrick Yeon, 2012'''
        QMessageBox.about(self, 'Spur Distance Chart', msg.strip())

    def mxtypecb(self, i):
        """ callback method for mixer configuration selection combobox"""
        self.mx.m, self.mx.n = [(-1, 1), (1, -1), (1,1)][i]
        # trigger anything watching the mixer
        self.mx.update_watchers()

    def create_main_frame(self):
        self.main_frame = QWidget()
        # Looking at the main frame as two columns. On the left there is the
        # chart and the IF control. In the right column we'll have range
        # settings, mixer settings, and maybe other stuff that comes up?

        self.IFtextbox = QLineEdit()
        self.IFtextbox.setMinimumWidth(6)
        self.IFtextbox.setText(str(self.spurset.mixer.IF))
        # TODO link up the textbox so that it can also be input

        self.IFslider = QSlider(Qt.Horizontal)
        # TODO I'd really like some form of slider that doesn't actually limit
        # the user. Also, if IFtextbox could modify the IF, that'd be nice.
        self.IFslider.setRange(int(self.mx.IF * 0.1), (self.mx.IF * 5))
        self.IFslider.setValue(self.mx.IF)
        self.IFslider.setTracking(True)
        self.IFslider.setTickPosition(QSlider.TicksAbove)
        step = max(1, int(0.01 * self.mx.IF))
        self.IFslider.setSingleStep(step)
        self.IFslider.setPageStep(step * 10)
        self.IFcid = self.connect(self.IFslider, SIGNAL('valueChanged(int)'),
                                  self.IF_slide)

        IFbar = QHBoxLayout()
        IFbar.addWidget(QLabel('IF'))
        IFbar.addWidget(self.IFtextbox)
        IFbar.addWidget(self.IFslider)
        IFbar.addStretch()

        leftcol = QVBoxLayout()
        leftcol.addWidget(self.chart.plot)
        leftcol.addLayout(IFbar)

        # left column done. Now the right-hand side
        rangebox = QVBoxLayout()
        for (prop, name, f) in [(spurset.RFmin, 'RFmin', self.spurset.RFmin),
                                (spurset.RFmax, 'RFmax', self.spurset.RFmax),
                                (spurset.dspan, 'dspan', self.spurset.dspan)]:
            rangebox.addLayout(Fbar(self.spurset, prop,
                                    name, f, 0, 10000))
        autocb = QCheckBox('Auto')
        # Disable it, won't be implemented for release
        # but leave it there, to nag me into doing it.
        autocb.setDisabled(True)
        rangebox.addWidget(autocb)

        # a line to report the front-end filter's limits
        fefstat = QHBoxLayout()
        fefstat.addWidget(QLabel('Filter Range: '))
        fefrange = QLabel('%d - %d' % (self.fef.start, self.fef.stop))
        # TODO not sure about the lambda here. Feels like if I give it time,
        # I'll sort out a sensible overall connection scheme.
        self.fef.register(lambda o: fefrange.setText('%d - %d' % 
                                                     (self.fef.start,
                                                      self.fef.stop)))
        fefstat.addWidget(fefrange)

        # mixer high/low-side injection picker
        mxbar = QHBoxLayout()
        mxbar.addWidget(QLabel('IF = '))
        mxtype = QComboBox()
        mxtype.addItem('LO - RF')
        mxtype.addItem('RF - LO')
        mxtype.addItem('RF + LO')
        # TODO this is ugly
        mxtype.setCurrentIndex([(-1, 1), (1, -1), (1,1)].index((self.mx.m,
                                                                self.mx.n)))
        self.mxtypecid = self.connect(mxtype,
                                      SIGNAL('currentIndexChanged(int)'),
                                      self.mxtypecb)
        mxbar.addWidget(mxtype)

        # alright, the actual column proper in the layout
        vbar = QVBoxLayout()
        vbar.addLayout(rangebox)
        vbar.addLayout(fefstat)
        vbar.addLayout(mxbar)
        legend = self.chart.legend()
        vbar.addWidget(legend)
        # need to let the legend stretch so that everything fits in it
        vbar.setStretchFactor(legend, 1)
        vbar.addStretch()

        hbox = QHBoxLayout()
        hbox.addLayout(leftcol)
        hbox.addLayout(vbar)
        # make sure the legend doesn't stretch so far horizontally that the
        # chart suffers considerable loss of space.
        hbox.setStretchFactor(leftcol, 5)
        hbox.setStretchFactor(vbar, 1)

        self.main_frame.setLayout(hbox)
        self.setCentralWidget(self.main_frame)

    def create_menu_bar(self):
        filemenu = self.menuBar().addMenu('&File')
        close = QAction('&Quit', self)
        close.setShortcut('Ctrl+W')
        self.connect(close, SIGNAL('triggered()'), self.close)
        filemenu.addAction(close)

        helpmenu = self.menuBar().addMenu('&Help')
        about  = QAction('&About', self)
        about.setShortcut('F1')
        self.connect(about, SIGNAL('triggered()'), self.about)
        helpmenu.addAction(about)
Example #39
0
class EditGeometryProperties(PyDialog):
    force = True

    def __init__(self, data, win_parent=None):
        """
        +------------------+
        | Edit Actor Props |
        +------------------+------+
        |  Name1                  |
        |  Name2                  |
        |  Name3                  |
        |  Name4                  |
        |                         |
        |  Active_Name    main    |
        |  Color          box     |
        |  Line_Width     2       |
        |  Point_Size     2       |
        |  Bar_Scale      2       |
        |  Opacity        0.5     |
        |  Show/Hide              |
        |                         |
        |    Apply   OK   Cancel  |
        +-------------------------+
        """
        PyDialog.__init__(self, data, win_parent)
        self.set_font_size(data['font_size'])
        del self.out_data['font_size']
        self.setWindowTitle('Edit Geometry Properties')
        self.allow_update = True

        #default
        #self.win_parent = win_parent
        #self.out_data = data

        self.keys = sorted(data.keys())
        self.keys = data.keys()
        keys = self.keys
        nrows = len(keys)
        self.active_key = 'main'  #keys[0]

        items = keys

        header_labels = ['Groups']
        table_model = Model(items, header_labels, self)
        view = CustomQTableView(self)  #Call your custom QTableView here
        view.setModel(table_model)
        if qt_version == 4:
            view.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)

        self.table = view

        actor_obj = data[self.active_key]
        name = actor_obj.name
        line_width = actor_obj.line_width
        point_size = actor_obj.point_size
        bar_scale = actor_obj.bar_scale
        opacity = actor_obj.opacity
        color = actor_obj.color
        show = actor_obj.is_visible
        self.representation = actor_obj.representation

        # table
        header = self.table.horizontalHeader()
        header.setStretchLastSection(True)

        self._default_is_apply = False
        self.name = QLabel("Name:")
        self.name_edit = QLineEdit(str(name))
        self.name_edit.setDisabled(True)

        self.color = QLabel("Color:")
        self.color_edit = QPushButton()
        #self.color_edit.setFlat(True)

        color = self.out_data[self.active_key].color
        qcolor = QtGui.QColor()
        qcolor.setRgb(*color)
        #print('color =%s' % str(color))
        palette = QtGui.QPalette(
            self.color_edit.palette())  # make a copy of the palette
        #palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Base, \
        #qcolor)
        palette.setColor(QtGui.QPalette.Background,
                         QtGui.QColor('blue'))  # ButtonText
        self.color_edit.setPalette(palette)

        self.color_edit.setStyleSheet("QPushButton {"
                                      "background-color: rgb(%s, %s, %s);" %
                                      tuple(color) +
                                      #"border:1px solid rgb(255, 170, 255); "
                                      "}")

        self.use_slider = True
        self.is_opacity_edit_active = False
        self.is_opacity_edit_slider_active = False

        self.is_line_width_edit_active = False
        self.is_line_width_edit_slider_active = False

        self.is_point_size_edit_active = False
        self.is_point_size_edit_slider_active = False

        self.is_bar_scale_edit_active = False
        self.is_bar_scale_edit_slider_active = False

        self.opacity = QLabel("Opacity:")
        self.opacity_edit = QDoubleSpinBox(self)
        self.opacity_edit.setRange(0.1, 1.0)
        self.opacity_edit.setDecimals(1)
        self.opacity_edit.setSingleStep(0.1)
        self.opacity_edit.setValue(opacity)
        if self.use_slider:
            self.opacity_slider_edit = QSlider(QtCore.Qt.Horizontal)
            self.opacity_slider_edit.setRange(1, 10)
            self.opacity_slider_edit.setValue(opacity * 10)
            self.opacity_slider_edit.setTickInterval(1)
            self.opacity_slider_edit.setTickPosition(QSlider.TicksBelow)

        self.line_width = QLabel("Line Width:")
        self.line_width_edit = QSpinBox(self)
        self.line_width_edit.setRange(1, 15)
        self.line_width_edit.setSingleStep(1)
        self.line_width_edit.setValue(line_width)
        if self.use_slider:
            self.line_width_slider_edit = QSlider(QtCore.Qt.Horizontal)
            self.line_width_slider_edit.setRange(1, 15)
            self.line_width_slider_edit.setValue(line_width)
            self.line_width_slider_edit.setTickInterval(1)
            self.line_width_slider_edit.setTickPosition(QSlider.TicksBelow)

        if self.representation in ['point', 'surface']:
            self.line_width.setEnabled(False)
            self.line_width_edit.setEnabled(False)
            self.line_width_slider_edit.setEnabled(False)

        self.point_size = QLabel("Point Size:")
        self.point_size_edit = QSpinBox(self)
        self.point_size_edit.setRange(1, 15)
        self.point_size_edit.setSingleStep(1)
        self.point_size_edit.setValue(point_size)
        self.point_size.setVisible(False)
        self.point_size_edit.setVisible(False)
        if self.use_slider:
            self.point_size_slider_edit = QSlider(QtCore.Qt.Horizontal)
            self.point_size_slider_edit.setRange(1, 15)
            self.point_size_slider_edit.setValue(point_size)
            self.point_size_slider_edit.setTickInterval(1)
            self.point_size_slider_edit.setTickPosition(QSlider.TicksBelow)
            self.point_size_slider_edit.setVisible(False)

        if self.representation in ['wire', 'surface']:
            self.point_size.setEnabled(False)
            self.point_size_edit.setEnabled(False)
            if self.use_slider:
                self.point_size_slider_edit.setEnabled(False)

        self.bar_scale = QLabel("Bar Scale:")
        self.bar_scale_edit = QDoubleSpinBox(self)
        #self.bar_scale_edit.setRange(0.01, 1.0)  # was 0.1
        #self.bar_scale_edit.setRange(0.05, 5.0)
        self.bar_scale_edit.setDecimals(1)
        #self.bar_scale_edit.setSingleStep(bar_scale / 10.)
        self.bar_scale_edit.setSingleStep(0.1)
        self.bar_scale_edit.setValue(bar_scale)

        #if self.use_slider:
        #self.bar_scale_slider_edit = QSlider(QtCore.Qt.Horizontal)
        #self.bar_scale_slider_edit.setRange(1, 100)  # 1/0.05 = 100/5.0
        #self.bar_scale_slider_edit.setValue(opacity * 0.05)
        #self.bar_scale_slider_edit.setTickInterval(10)
        #self.bar_scale_slider_edit.setTickPosition(QSlider.TicksBelow)

        if self.representation != 'bar':
            self.bar_scale.setEnabled(False)
            self.bar_scale_edit.setEnabled(False)
            self.bar_scale.setVisible(False)
            self.bar_scale_edit.setVisible(False)
            #self.bar_scale_slider_edit.setVisible(False)
            #self.bar_scale_slider_edit.setEnabled(False)

        # show/hide
        self.checkbox_show = QCheckBox("Show")
        self.checkbox_hide = QCheckBox("Hide")
        self.checkbox_show.setChecked(show)
        self.checkbox_hide.setChecked(not show)

        if name == 'main':
            self.color.setEnabled(False)
            self.color_edit.setEnabled(False)
            self.point_size.setEnabled(False)
            self.point_size_edit.setEnabled(False)
            if self.use_slider:
                self.point_size_slider_edit.setEnabled(False)

        self.cancel_button = QPushButton("Close")

        self.create_layout()
        self.set_connections()

    def on_update_geometry_properties_window(self, data):
        """Not Implemented"""
        return
        #new_keys = sorted(data.keys())
        #if self.active_key in new_keys:
        #i = new_keys.index(self.active_key)
        #else:
        #i = 0
        #self.table.update_data(new_keys)
        #self.out_data = data
        #self.update_active_key(i)

    def update_active_key(self, index):
        """
        Parameters
        ----------
        index : PyQt4.QtCore.QModelIndex
            the index of the list

        Internal Parameters
        -------------------
        name : str
            the name of obj
        obj : CoordProperties, AltGeometry
            the storage object for things like line_width, point_size, etc.
        """
        if qt_version == 4:
            name = str(index.data().toString())
        else:
            name = str(index.data())
            print('name = %r' % name)
        #i = self.keys.index(self.active_key)

        self.active_key = name
        self.name_edit.setText(name)
        obj = self.out_data[name]
        if isinstance(obj, CoordProperties):
            opacity = 1.0
            representation = 'coord'
            is_visible = obj.is_visible
        elif isinstance(obj, AltGeometry):
            line_width = obj.line_width
            point_size = obj.point_size
            bar_scale = obj.bar_scale
            opacity = obj.opacity
            representation = obj.representation
            is_visible = obj.is_visible

            self.color_edit.setStyleSheet(
                "QPushButton {"
                "background-color: rgb(%s, %s, %s);" % tuple(obj.color) +
                #"border:1px solid rgb(255, 170, 255); "
                "}")
            self.allow_update = False
            self.force = False
            self.line_width_edit.setValue(line_width)
            self.point_size_edit.setValue(point_size)
            self.bar_scale_edit.setValue(bar_scale)
            self.force = True
            self.allow_update = True
        else:
            raise NotImplementedError(obj)

        allowed_representations = [
            'main', 'surface', 'coord', 'toggle', 'wire', 'point', 'bar'
        ]

        if self.representation != representation:
            self.representation = representation
            if representation not in allowed_representations:
                msg = 'name=%r; representation=%r is invalid\nrepresentations=%r' % (
                    name, representation, allowed_representations)

            if self.representation == 'coord':
                self.color.setVisible(False)
                self.color_edit.setVisible(False)
                self.line_width.setVisible(False)
                self.line_width_edit.setVisible(False)
                self.point_size.setVisible(False)
                self.point_size_edit.setVisible(False)
                self.bar_scale.setVisible(False)
                self.bar_scale_edit.setVisible(False)
                self.opacity.setVisible(False)
                self.opacity_edit.setVisible(False)
                if self.use_slider:
                    self.opacity_slider_edit.setVisible(False)
                    self.point_size_slider_edit.setVisible(False)
                    self.line_width_slider_edit.setVisible(False)
                    #self.bar_scale_slider_edit.setVisible(False)
            else:
                self.color.setVisible(True)
                self.color_edit.setVisible(True)
                self.line_width.setVisible(True)
                self.line_width_edit.setVisible(True)
                self.point_size.setVisible(True)
                self.point_size_edit.setVisible(True)
                self.bar_scale.setVisible(True)
                #self.bar_scale_edit.setVisible(True)
                self.opacity.setVisible(True)
                self.opacity_edit.setVisible(True)
                if self.use_slider:
                    self.opacity_slider_edit.setVisible(True)
                    self.line_width_slider_edit.setVisible(True)
                    self.point_size_slider_edit.setVisible(True)
                    #self.bar_scale_slider_edit.setVisible(True)

                if name == 'main':
                    self.color.setEnabled(False)
                    self.color_edit.setEnabled(False)
                    self.point_size.setEnabled(False)
                    self.point_size_edit.setEnabled(False)
                    self.line_width.setEnabled(True)
                    self.line_width_edit.setEnabled(True)
                    self.bar_scale.setEnabled(False)
                    self.bar_scale_edit.setEnabled(False)
                    show_points = False
                    show_line_width = True
                    show_bar_scale = False
                    if self.use_slider:
                        self.line_width_slider_edit.setEnabled(True)
                        #self.bar_scale_slider_edit.setVisible(False)
                else:
                    self.color.setEnabled(True)
                    self.color_edit.setEnabled(True)

                    show_points = False
                    if self.representation in ['point', 'wire+point']:
                        show_points = True

                    show_line_width = False
                    if self.representation in ['wire', 'wire+point', 'bar']:
                        show_line_width = True

                    if representation == 'bar':
                        show_bar_scale = True
                    else:
                        show_bar_scale = False
                    #self.bar_scale_button.setVisible(show_bar_scale)
                    #self.bar_scale_edit.setSingleStep(bar_scale / 10.)
                    #if self.use_slider:
                    #self.bar_scale_slider_edit.setEnabled(False)

                self.point_size.setEnabled(show_points)
                self.point_size_edit.setEnabled(show_points)
                self.point_size.setVisible(show_points)
                self.point_size_edit.setVisible(show_points)

                self.line_width.setEnabled(show_line_width)
                self.line_width_edit.setEnabled(show_line_width)

                self.bar_scale.setEnabled(show_bar_scale)
                self.bar_scale_edit.setEnabled(show_bar_scale)
                self.bar_scale.setVisible(show_bar_scale)
                self.bar_scale_edit.setVisible(show_bar_scale)
                if self.use_slider:
                    self.point_size_slider_edit.setEnabled(show_points)
                    self.point_size_slider_edit.setVisible(show_points)
                    self.line_width_slider_edit.setEnabled(show_line_width)

            #if self.representation in ['wire', 'surface']:

        self.opacity_edit.setValue(opacity)
        #if self.use_slider:
        #self.opacity_slider_edit.setValue(opacity*10)
        self.checkbox_show.setChecked(is_visible)
        self.checkbox_hide.setChecked(not is_visible)

        passed = self.on_validate()
        #self.on_apply(force=True)  # TODO: was turned on...do I want this???
        #self.allow_update = True

    #def on_name_select(self):
    #print('on_name_select')
    #return

    def create_layout(self):
        ok_cancel_box = QHBoxLayout()
        ok_cancel_box.addWidget(self.cancel_button)

        grid = QGridLayout()

        irow = 0
        grid.addWidget(self.name, irow, 0)
        grid.addWidget(self.name_edit, irow, 1)
        irow += 1

        grid.addWidget(self.color, irow, 0)
        grid.addWidget(self.color_edit, irow, 1)
        irow += 1

        grid.addWidget(self.opacity, irow, 0)
        if self.use_slider:
            grid.addWidget(self.opacity_edit, irow, 2)
            grid.addWidget(self.opacity_slider_edit, irow, 1)
        else:
            grid.addWidget(self.opacity_edit, irow, 1)
        irow += 1

        grid.addWidget(self.line_width, irow, 0)
        if self.use_slider:
            grid.addWidget(self.line_width_edit, irow, 2)
            grid.addWidget(self.line_width_slider_edit, irow, 1)
        else:
            grid.addWidget(self.line_width_edit, irow, 1)
        irow += 1

        grid.addWidget(self.point_size, irow, 0)
        if self.use_slider:
            grid.addWidget(self.point_size_edit, irow, 2)
            grid.addWidget(self.point_size_slider_edit, irow, 1)
        else:
            grid.addWidget(self.point_size_edit, irow, 1)
        irow += 1

        grid.addWidget(self.bar_scale, irow, 0)
        if self.use_slider and 0:
            grid.addWidget(self.bar_scale_edit, irow, 2)
            grid.addWidget(self.bar_scale_slider_edit, irow, 1)
        else:
            grid.addWidget(self.bar_scale_edit, irow, 1)
        irow += 1

        checkboxs = QButtonGroup(self)
        checkboxs.addButton(self.checkbox_show)
        checkboxs.addButton(self.checkbox_hide)

        vbox = QVBoxLayout()
        vbox.addWidget(self.table)
        vbox.addLayout(grid)

        if 0:
            vbox.addWidget(self.checkbox_show)
            vbox.addWidget(self.checkbox_hide)
        else:
            vbox1 = QVBoxLayout()
            vbox1.addWidget(self.checkbox_show)
            vbox1.addWidget(self.checkbox_hide)
            vbox.addLayout(vbox1)

        vbox.addStretch()
        #vbox.addWidget(self.check_apply)
        vbox.addLayout(ok_cancel_box)
        self.setLayout(vbox)

    def set_connections(self):
        self.opacity_edit.valueChanged.connect(self.on_opacity)
        self.line_width_edit.valueChanged.connect(self.on_line_width)
        self.point_size_edit.valueChanged.connect(self.on_point_size)
        self.bar_scale_edit.valueChanged.connect(self.on_bar_scale)

        if self.use_slider:
            self.opacity_slider_edit.valueChanged.connect(
                self.on_opacity_slider)
            self.line_width_slider_edit.valueChanged.connect(
                self.on_line_width_slider)
            self.point_size_slider_edit.valueChanged.connect(
                self.on_point_size_slider)
            #self.bar_scale_slider_edit.valueChanged.connect(self.on_bar_scale_slider)

        # self.connect(self.opacity_edit, QtCore.SIGNAL('clicked()'), self.on_opacity)
        # self.connect(self.line_width, QtCore.SIGNAL('clicked()'), self.on_line_width)
        # self.connect(self.point_size, QtCore.SIGNAL('clicked()'), self.on_point_size)

        if qt_version == 4:
            self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent)
        self.color_edit.clicked.connect(self.on_color)
        self.checkbox_show.clicked.connect(self.on_show)
        self.checkbox_hide.clicked.connect(self.on_hide)
        self.cancel_button.clicked.connect(self.on_cancel)
        # closeEvent

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.close()

    def closeEvent(self, event):
        self.on_cancel()

    def on_color(self):
        """called when the user clicks on the color box"""
        name = self.active_key
        obj = self.out_data[name]
        rgb_color_ints = obj.color

        msg = name
        col = QColorDialog.getColor(QtGui.QColor(*rgb_color_ints), self,
                                    "Choose a %s color" % msg)
        if col.isValid():
            color_float = col.getRgbF()[:3]
            obj.color = color_float
            color_int = [int(colori * 255) for colori in color_float]
            self.color_edit.setStyleSheet(
                "QPushButton {"
                "background-color: rgb(%s, %s, %s);" % tuple(color_int) +
                #"border:1px solid rgb(255, 170, 255); "
                "}")
        self.on_apply(force=self.force)
        #print(self.allow_update)

    def on_show(self):
        """shows the actor"""
        name = self.active_key
        is_checked = self.checkbox_show.isChecked()
        self.out_data[name].is_visible = is_checked
        self.on_apply(force=self.force)

    def on_hide(self):
        """hides the actor"""
        name = self.active_key
        is_checked = self.checkbox_hide.isChecked()
        self.out_data[name].is_visible = not is_checked
        self.on_apply(force=self.force)

    def on_line_width(self):
        """increases/decreases the wireframe (for solid bodies) or the bar thickness"""
        self.is_line_width_edit_active = True
        name = self.active_key
        line_width = self.line_width_edit.value()
        self.out_data[name].line_width = line_width
        if not self.is_line_width_edit_slider_active:
            if self.use_slider:
                self.line_width_slider_edit.setValue(line_width)
            self.is_line_width_edit_active = False
        self.on_apply(force=self.force)
        self.is_line_width_edit_active = False

    def on_line_width_slider(self):
        """increases/decreases the wireframe (for solid bodies) or the bar thickness"""
        self.is_line_width_edit_slider_active = True
        #name = self.active_key
        line_width = self.line_width_slider_edit.value()
        if not self.is_line_width_edit_active:
            self.line_width_edit.setValue(line_width)
        self.is_line_width_edit_slider_active = False

    def on_point_size(self):
        """increases/decreases the point size"""
        self.is_point_size_edit_active = True
        name = self.active_key
        point_size = self.point_size_edit.value()
        self.out_data[name].point_size = point_size
        if not self.is_point_size_edit_slider_active:
            if self.use_slider:
                self.point_size_slider_edit.setValue(point_size)
            self.is_point_size_edit_active = False
        self.on_apply(force=self.force)
        self.is_point_size_edit_active = False

    def on_point_size_slider(self):
        """increases/decreases the point size"""
        self.is_point_size_edit_slider_active = True
        name = self.active_key
        point_size = self.point_size_slider_edit.value()
        if not self.is_point_size_edit_active:
            self.point_size_edit.setValue(point_size)
        self.is_point_size_edit_slider_active = False

    def on_bar_scale(self):
        """
        Vectors start at some xyz coordinate and can increase in length.
        Increases/decreases the length scale factor.
        """
        self.is_bar_scale_edit_active = True
        name = self.active_key
        float_bar_scale = self.bar_scale_edit.value()
        self.out_data[name].bar_scale = float_bar_scale
        if not self.is_bar_scale_edit_slider_active:
            int_bar_scale = int(round(float_bar_scale * 20, 0))
            #if self.use_slider:
            #self.bar_scale_slider_edit.setValue(int_bar_scale)
            self.is_bar_scale_edit_active = False
        self.on_apply(force=self.force)
        self.is_bar_scale_edit_active = False

    def on_bar_scale_slider(self):
        """
        Vectors start at some xyz coordinate and can increase in length.
        Increases/decreases the length scale factor.
        """
        self.is_bar_scale_edit_slider_active = True
        name = self.active_key
        int_bar_scale = self.bar_scale_slider_edit.value()
        if not self.is_bar_scale_edit_active:
            float_bar_scale = int_bar_scale / 20.
            self.bar_scale_edit.setValue(float_bar_scale)
        self.is_bar_scale_edit_slider_active = False

    def on_opacity(self):
        """
        opacity = 1.0 (solid/opaque)
        opacity = 0.0 (invisible)
        """
        self.is_opacity_edit_active = True
        name = self.active_key
        float_opacity = self.opacity_edit.value()
        self.out_data[name].opacity = float_opacity
        if not self.is_opacity_edit_slider_active:
            int_opacity = int(round(float_opacity * 10, 0))
            if self.use_slider:
                self.opacity_slider_edit.setValue(int_opacity)
            self.is_opacity_edit_active = False
        self.on_apply(force=self.force)
        self.is_opacity_edit_active = False

    def on_opacity_slider(self):
        """
            opacity = 1.0 (solid/opaque)
            opacity = 0.0 (invisible)
            """
        self.is_opacity_edit_slider_active = True
        name = self.active_key
        int_opacity = self.opacity_slider_edit.value()
        if not self.is_opacity_edit_active:
            float_opacity = int_opacity / 10.
            self.opacity_edit.setValue(float_opacity)
        self.is_opacity_edit_slider_active = False

    #def on_axis(self, text):
    ##print(self.combo_axis.itemText())
    #self._axis = str(text)
    #self.plane.setText('Point on %s? Plane:' % self._axis)
    #self.point_a.setText('Point on %s Axis:' % self._axis)
    #self.point_b.setText('Point on %s%s Plane:' % (self._axis, self._plane))

    #def on_plane(self, text):
    #self._plane = str(text)
    #self.point_b.setText('Point on %s%s Plane:' % (self._axis, self._plane))

    #def _on_float(self, field):
    #try:
    #eval_float_from_string(field.text())
    #field.setStyleSheet("QLineEdit{background: white;}")
    #except ValueError:
    #field.setStyleSheet("QLineEdit{background: red;}")

    #def on_default_name(self):
    #self.name_edit.setText(str(self._default_name))
    #self.name_edit.setStyleSheet("QLineEdit{background: white;}")

    #def check_float(self, cell):
    #text = cell.text()
    #try:
    #value = eval_float_from_string(text)
    #cell.setStyleSheet("QLineEdit{background: white;}")
    #return value, True
    #except ValueError:
    #cell.setStyleSheet("QLineEdit{background: red;}")
    #return None, False

    #def check_name(self, cell):
    #text = str(cell.text()).strip()
    #if len(text):
    #cell.setStyleSheet("QLineEdit{background: white;}")
    #return text, True
    #else:
    #cell.setStyleSheet("QLineEdit{background: red;}")
    #return None, False

    def on_validate(self):
        self.out_data['clicked_ok'] = True
        self.out_data['clicked_cancel'] = False

        old_obj = self.out_data[self.active_key]
        old_obj.line_width = self.line_width_edit.value()
        old_obj.point_size = self.point_size_edit.value()
        old_obj.bar_scale = self.bar_scale_edit.value()
        old_obj.opacity = self.opacity_edit.value()
        #old_obj.color = self.color_edit
        old_obj.is_visible = self.checkbox_show.isChecked()
        return True
        #name_value, flag0 = self.check_name(self.name_edit)
        #ox_value, flag1 = self.check_float(self.transparency_edit)
        #if flag0 and flag1:
        #self.out_data['clicked_ok'] = True
        #return True
        #return False

    def on_apply(self, force=False):
        passed = self.on_validate()
        #print("passed=%s force=%s allow=%s" % (passed, force, self.allow_update))
        if (passed or force) and self.allow_update and hasattr(
                self.win_parent, 'on_update_geometry_properties'):
            #print('obj = %s' % self.out_data[self.active_key])
            self.win_parent.on_update_geometry_properties(self.out_data,
                                                          name=self.active_key)
        return passed

    def on_cancel(self):
        passed = self.on_apply(force=True)
        if passed:
            self.close()
from PyQt4.QtCore import Qt, QObject, SIGNAL, SLOT
from PyQt4.QtGui import QApplication
from PyQt4.QtGui import QWidget, QSpinBox, QSlider, QHBoxLayout
import sys


if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = QWidget()
    window.setWindowTitle("Enter Your Age")

    spinBox = QSpinBox()
    slider = QSlider(Qt.Horizontal)
    spinBox.setRange(0, 130)
    slider.setRange(0, 130)

    QObject.connect(spinBox, SIGNAL("valueChanged(int)"),
                     slider, SLOT("setValue(int)"))

    QObject.connect(slider, SIGNAL("valueChanged(int)"),
                     spinBox, SLOT("setValue(int)"))

    spinBox.setValue(35)

    layout = QHBoxLayout()    # 水平布局
    layout.addWidget(spinBox) # 添加 水平 布局
    layout.addWidget(slider)  # 添加 水平 布局

    window.setLayout(layout)
Example #41
0
class dbsMiscControlsDialog(QDialog):
    def __init__(self, callback, parent=None):
        QDialog.__init__(self, parent)
        self.callback = callback
        self.create_widgets()
        self.layout_widgets()
        self.create_connections()
        self.setModal(False)
        self.setWindowTitle('Misc. Controls')
        
    def create_widgets(self):        
        self.op_pick_label = QLabel('Picking Opacity Isoval')
        self.op_pick_sbox = QDoubleSpinBox()
        self.op_pick_sbox.setRange(0, 1.0)
        self.op_pick_sbox.setSingleStep(0.02)
        self.op_pick_sbox.setValue(0.5)
        
        self.vta_combox_label = QLabel('Statistic')
        self.vta_stats_combox = QComboBox()
        self.vta_stats_combox.insertItem(0, 'Mean')
        self.vta_stats_combox.insertItem(1, 'Var')
        self.vta_stats_combox.insertItem(2, 'Min')
        self.vta_stats_combox.insertItem(3, 'Max')
        self.vta_stats_combox.insertItem(4, 'Mean-Var')
        self.vta_stats_combox.insertItem(5, 'Min-Var')
        self.vta_stats_combox.insertItem(6, 'Max-Var')
        self.vta_stats_combox.insertItem(7, 'NumSamples')
        
        self.__setupWidgetsForClippingPlanes()
        
    def layout_widgets(self):
        misc_controls_gl = QGridLayout()
        
        misc_controls_gl.addWidget(self.vta_combox_label, 0, 0)
        misc_controls_gl.addWidget(self.vta_stats_combox, 0, 1)
        
        misc_controls_gl.addWidget(self.op_pick_label, 1, 0)
        misc_controls_gl.addWidget(self.op_pick_sbox, 1, 1)
        
        misc_controls_gl.addWidget(self.cpl_xmax_label, 2, 0)
        misc_controls_gl.addWidget(self.cpl_xmax, 2, 1)
        misc_controls_gl.addWidget(self.cpl_ymax_label, 3, 0)
        misc_controls_gl.addWidget(self.cpl_ymax, 3, 1)
        misc_controls_gl.addWidget(self.cpl_zmax_label, 4, 0)
        misc_controls_gl.addWidget(self.cpl_zmax, 4, 1)
        
        self.setLayout(misc_controls_gl)
        self.layout().setSizeConstraint( QLayout.SetFixedSize )


    def create_connections(self):
        self.op_pick_sbox.valueChanged.connect(self.__setVolOpacityForPicking)
        self.cpl_ymax.valueChanged.connect(self.__setClippingPlaneYmax)
        self.cpl_xmax.valueChanged.connect(self.__setClippingPlaneXmax)
        self.cpl_zmax.valueChanged.connect(self.__setClippingPlaneZmax)
        self.vta_stats_combox.currentIndexChanged.connect(self.__setVolToRender)
        
    def getStatComboBoxIndex(self, stat):
        ''' Returns index of statistic. '''
        
        if stat == 'Mean':
            return 0
        elif stat == 'Var':
            return 1
        elif stat == 'Min':
            return 2
        elif stat == 'Max':
            return 3
        elif stat == 'Mean-Var':
            return 4
        elif stat == 'Min-Var':
            return 5
        elif stat == 'Max-Var':
            return 6
        elif stat == 'NumSamples':
            return 6
        
        
    def updateWidgetValues(self):
        ''' Allows application to set values on widget controls. '''
        
        par = self.parent()
        actv = self.parent().active_vol
        
        self.cpl_xmax.setValue(par._vdata[actv].volumeClipXmax.GetOrigin()[0])
        self.cpl_ymax.setValue(par._vdata[actv].volumeClipYmax.GetOrigin()[1])
        self.cpl_zmax.setValue(par._vdata[actv].volumeClipXmax.GetOrigin()[2])
        
        self.op_pick_sbox.setValue(par._vdata[actv].picking_opacity)
        
        stat = QString(par._vdata[actv].curr_statistic)
        idx = self.getStatComboBoxIndex(stat)
        self.vta_stats_combox.setCurrentIndex(idx)
        
        
    def __setupWidgetsForClippingPlanes(self): 
        self.cpl_xmax_label = QLabel( 'Clipping Plane X' )
        self.cpl_xmax = QSlider(Qt.Horizontal)
        self.cpl_xmax.setRange(-30.000000, -30 + 120 * 0.252) # data set dependent
        # todo - set this with loadable dimensions config file with data

        self.cpl_ymax_label = QLabel( 'Clipping Plane Y' )
        self.cpl_ymax = QSlider(Qt.Horizontal)
        self.cpl_ymax.setRange(-15.000000, -15 + 120 * 0.252)
        
        self.cpl_zmax_label = QLabel( 'Clipping Plane Z' )
        self.cpl_zmax = QSlider(Qt.Horizontal)
        self.cpl_zmax.setRange(-30.000000, -30 + 120 * 0.252)
        
        
    def __setVolOpacityForPicking(self):
        op = self.op_pick_sbox.value()
        av = self.parent().active_vol
        self.parent()._vdata[av].picking_opacity = op
        self.parent()._picker.SetVolumeOpacityIsovalue(op)


    def __setClippingPlaneYmax(self):
        av = self.parent().active_vol
        self.parent()._vdata[av].yclip = self.cpl_ymax.value() 
        self.parent()._vdata[av].volumeClipYmax.SetOrigin(-30, self.cpl_ymax.value(), -30)        
        self.apply()
        
    def __setClippingPlaneXmax(self):
        av = self.parent().active_vol
        self.parent()._vdata[av].xclip = self.cpl_xmax.value()
        self.parent()._vdata[av].volumeClipXmax.SetOrigin(self.cpl_xmax.value(), -10, -30)
        self.apply()
    
    
    def __setClippingPlaneZmax(self):
        av = self.parent().active_vol
        self.parent()._vdata[av].zclip = self.cpl_zmax.value()
        self.parent()._vdata[av].volumeClipZmax.SetOrigin(-30, -10, self.cpl_zmax.value())
        self.apply()
        
        
    def __setVolToRender(self):
        par = self.parent()
        stat = self.vta_stats_combox.currentText()
        av = par.active_vol 
        
        vol_to_renderer = str(stat)
        par._vdata[av].curr_statistic = vol_to_renderer
        par._vdata[av].assignVolumeProperties()        
        par._colorControlsDialog.setTFChart( par._vdata[av].chart )
        
        self.__setClippingPlaneXmax()
        self.__setClippingPlaneYmax()
        self.__setClippingPlaneZmax()
        
        self.apply()


    def apply(self):
        av = self.parent().active_vol
        self.parent().vol_qvtk_widgets[av].update()
Example #42
0
class PlotLcm(QMainWindow):
    """ A class to plot an LCM type over time. """
    
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('LCM Plotter')

        self.createMenu()
        self.createMainFrame()
        
        # Each channel has data and axis associated with it. 
        # Dictionary key is the channel name and property.
        self.data = {}
        self.axes = {}
        self.lastPlot = None
        
        # Stop the program if CTRL-C is received
        self._stopEvent = threading.Event()
        signal.signal(signal.SIGINT, self.handleSigint)
        
        self._lcm = lcm.LCM()
        self.handlerThread = threading.Thread(target=self.pollLcm)
        self.handlerThread.setDaemon(True)
        self.handlerThread.start()
        
        self.connect(self, SIGNAL('redraw()'), self.on_draw) # Create redraw signal
        self.drawingThread = threading.Thread(target=self.drawLoop)
        self.drawingThread.setDaemon(True)
        self.drawingThread.start()
        
    def _cleanup(self):
        self._stopEvent.set()
        self.handlerThread.join()
        self.drawingThread.join()
        
    def handleSigint(self, *args):
        self._cleanup()
        QApplication.quit()
        
    def pollLcm(self):
        while not self._stopEvent.isSet():
            rc = select.select([self._lcm.fileno()], [], [self._lcm.fileno()], 0.05)
            if len(rc[0]) > 0 or len(rc[2]) > 0:
                self._lcm.handle()
            
    def drawLoop(self):
        while not self._stopEvent.isSet():
            self.emit(SIGNAL("redraw()"))
            time.sleep(0.5)
            
    def handleMessage(self, channel, msg):
        for (lcmChannel, lcmType, lcmProperty) in self.data.keys():
            if lcmChannel == channel:
                data = eval(lcmType + ".decode(msg)." + lcmProperty)
                self.data[(lcmChannel, lcmType, lcmProperty)].append(data)
        
    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        
        path = unicode(QFileDialog.getSaveFileName(self, 
                        'Save file', '', 
                        file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def on_about(self):
        msg = """ Plot an LCM message
        """
        QMessageBox.about(self, "About the demo", msg.strip())
    
    def on_draw(self):
        """ Redraws the figure
        """
        for (channel, lcmType, lcmProperty) in self.axes.keys():
            axis = self.axes[(channel, lcmType, lcmProperty)]
            axis.clear()
            axis.grid(self.gridCheckBox.isChecked())
            axis.plot(self.data[(channel, lcmType, lcmProperty)])
            axis.set_title(channel + ": " + lcmProperty)
            
        self.canvas.draw()
    
    def addPlot(self):
        channel = str(self.channelTextbox.text()).strip()
        lcmType = str(self.typeTextbox.text()).strip()
        lcmProperty = str(self.propertyTextbox.text()).strip()
        
        if not self.checkInputs(channel, lcmType, lcmProperty):
            return
        
        self.data[(channel, lcmType, lcmProperty)] = []
        n = len(self.data)
        i = 0
        self.fig.clear() # Clear the old plot first
        for key in self.data.keys():
            i = i + 1
            self.axes[key] = self.fig.add_subplot(n, 1, i)
        
        self.lastPlot = (channel, lcmType, lcmProperty)
        self._lcm.subscribe(channel, self.handleMessage)
        
    def clearPlots(self):
        for key in self.data.keys():
            self.data[key] = []
    
    def checkInputs(self, channel, lcmType, lcmProperty):
        # Error checking cause nobody is perfect...
        if channel == "":
            print "Warning: No channel given"
            return False
        
        try:
            __import__("marof_lcm." + lcmType)
        except ImportError:
            print "Warning: The LCM type is not in scope"
            return False
        else:
            try:
                eval("getattr(" + lcmType + ", lcmProperty)")
            except Exception:
                print "Warning: The LCM property for this type does not exist"
                return False
        
        # Clear the data and don't create a new axis if there is already data for this        
        if self.data.has_key((channel, lcmType, lcmProperty)):
            print "This data already exists:", channel
            self.data[(channel, lcmType, lcmProperty)] = []
            return False
        
        return True
    
    def createMainFrame(self):
        self.mainFrame = QWidget()
        
        self.dpi = 72
        self.fig = Figure((5.0, 2.5), dpi=self.dpi, tight_layout=True)
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas.setParent(self.mainFrame)
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        
        self.mpl_toolbar = NavigationToolbar2QTAgg(self.canvas, self.mainFrame)
        
        # Other GUI controls
        # 
        self.channelTextbox = QLineEdit()
        self.channelTextbox.setMinimumWidth(100)
        self.typeTextbox = QLineEdit()
        self.typeTextbox.setMinimumWidth(100)
        self.propertyTextbox = QLineEdit()
        self.propertyTextbox.setMinimumWidth(100)
        #self.connect(self.textbox, SIGNAL('editingFinished ()'), self.on_draw)
        
        self.addPlotButton = QPushButton("Add Plot")
        self.connect(self.addPlotButton, SIGNAL('clicked()'), self.addPlot)
        
        self.mergePlotButton = QPushButton("Reset Data")
        self.connect(self.mergePlotButton, SIGNAL('clicked()'), self.clearPlots)
        
        self.gridCheckBox = QCheckBox("Show Grid")
        self.gridCheckBox.setChecked(False)
        self.connect(self.gridCheckBox, SIGNAL('stateChanged(int)'), self.on_draw)
        
        slider_label = QLabel('Bar width (%):')
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(1, 100)
        self.slider.setValue(20)
        self.slider.setTracking(True)
        self.slider.setTickPosition(QSlider.TicksBothSides)
        self.connect(self.slider, SIGNAL('valueChanged(int)'), self.on_draw)
        
        #
        # Layout with box sizers
        # 
        hbox = QHBoxLayout()
        
        for w in [self.channelTextbox, self.typeTextbox, self.propertyTextbox, 
                  self.addPlotButton, self.mergePlotButton, self.gridCheckBox, 
                  slider_label, self.slider]:
            hbox.addWidget(w)
            hbox.setAlignment(w, Qt.AlignVCenter)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.mainFrame.setLayout(vbox)
        self.setCentralWidget(self.mainFrame)
        
    def createMenu(self):
        
        # File menu        
        fileMenu = self.menuBar().addMenu("File")
        
        saveMenuItem = self.create_action("&Save plot",
            shortcut="Ctrl+S", slot=self.save_plot, 
            tip="Save the plot")
        
        quitAction = self.create_action("&Quit", slot=self.close, 
            shortcut="Ctrl+Q", tip="Close the application")
        
        self.add_actions(fileMenu, 
            (saveMenuItem, None, quitAction))
        
        # Help menu
        helpMenu = self.menuBar().addMenu("Help")
        aboutAction = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About the demo')
        
        self.add_actions(helpMenu, (aboutAction,))

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def closeEvent(self, event):
        self._cleanup() # stop the drawing thread before exiting
        event.accept()
Example #43
0
class dbsElectrodeControlsDialog(QDialog):
    def __init__(self, callback, parent=None):
        QDialog.__init__(self, parent)
        self.callback = callback
        self.create_widgets()
        #self.layout_widgets()
        self.create_connections()
        self.setModal(False)
        self.setWindowTitle('Electrode Controls')
        self.layout().setSizeConstraint(QLayout.SetFixedSize)
        
        self.saved_params = dict()
        
     
    def create_widgets(self):   
        gridLayout = QGridLayout()
        groupBox = QGroupBox( 'Rendering controls' )
        groupBox.setFlat(True)
        groupBox2 = QGroupBox( 'DBSCAN centroids' )
        groupBox2.setFlat(True)
        groupBox3 = QGroupBox( 'Electrode filter' )
        groupBox3.setFlat(True)
        
        gridLayout.addWidget(groupBox)
        gridLayout.addWidget(groupBox3)
        gridLayout.addWidget(groupBox2)
        
        # rendering controls
        self.visi_label = QLabel( 'show electrodes' )
        self.visi = QCheckBox()
        self.visi.setChecked(False)
        
        self.fall_off_label = QLabel( 'fall-off' )
        self.fall_off = QSlider(Qt.Horizontal)
        self.fall_off.setRange(1, 100) # data set dependent
        
        self.thickness_label = QLabel( 'thickness' )
        self.thickness = QSlider(Qt.Horizontal)
        self.thickness.setRange(1, 100) # data set dependent
        
        self.trans_label = QLabel( 'force translucency' )
        self.forced_translucency = QCheckBox()
        self.forced_translucency.setChecked(False)
        
        # dbscan controls
        #self.view_button_grp = QButtonGroup()
        self.all_electrodes = QRadioButton('show all')
        self.only_clusters = QRadioButton('show clusters')
        self.only_noise = QRadioButton('show noise') 
        self.all_electrodes.setEnabled(False)
        self.all_electrodes.setChecked(True)
        self.only_clusters.setEnabled(False)
        self.only_noise.setEnabled(False)
        #self.view_button_grp.addButton( self.all_electrodes )
        #self.view_button_grp.addButton( self.only_clusters )
        #self.view_button_grp.addButton( self.only_noise ) 
        #gridLayout.addWidget(self.view_button_grp)
        
        self.eps_label = QLabel( 'epsilon' )
        self.eps_spinbox = QDoubleSpinBox()
        self.eps_spinbox.setRange(0.1, 10)
        self.eps_spinbox.setSingleStep(0.1)
        
        self.min_points_label = QLabel( 'min points' )
        self.min_spinbox = QSpinBox()
        self.min_spinbox.setRange(1, 20)
        self.min_spinbox.setSingleStep(1)
        
        self.button = QPushButton('Recalculate')
        self.button.setCheckable(True)
        
        self.browser = QTextBrowser()
    
        vbox = QVBoxLayout()
        vbox2 = QVBoxLayout()
        vbox3 = QVBoxLayout()
        
        vbox.addWidget( self.visi_label )
        vbox.addWidget( self.visi )
        vbox.addWidget( self.fall_off_label )
        vbox.addWidget( self.fall_off )
        vbox.addWidget( self.thickness_label )
        vbox.addWidget( self.thickness )
        vbox.addWidget( self.trans_label )
        vbox.addWidget( self.forced_translucency )
        
        vbox2.addWidget( self.eps_label )
        vbox2.addWidget( self.eps_spinbox )
        vbox2.addWidget( self.min_points_label )
        vbox2.addWidget( self.min_spinbox )
        vbox2.addWidget( self.button )
        vbox2.addWidget( self.browser )
        
        vbox3.addWidget( self.all_electrodes )
        vbox3.addWidget( self.only_clusters )
        vbox3.addWidget( self.only_noise )
        
        groupBox.setLayout(vbox)
        groupBox2.setLayout(vbox2)
        groupBox3.setLayout(vbox3)
        
        self.setLayout(gridLayout)
        self.layout().setSizeConstraint( QLayout.SetFixedSize )
               

    def create_connections(self):
        self.visi.stateChanged.connect(self.__toggleVisibility)
        self.fall_off.valueChanged.connect(self.__setOpacityFalloff)
        self.thickness.valueChanged.connect(self.__setLineThickness)
        self.forced_translucency.stateChanged.connect(self.__toggleForceTranslucency)
        self.button.pressed.connect(self.__calculateDBSCANClusters)
        
        self.all_electrodes.toggled.connect(self.__setElectrodeTypeVisible)
        self.only_clusters.toggled.connect(self.__setElectrodeTypeVisible)
        self.only_noise.toggled.connect(self.__setElectrodeTypeVisible)
    
    
    def __setElectrodeTypeVisible(self):
        av = self.parent().active_vol
        vdata = self.parent()._vdata[av]
        
        if self.all_electrodes.isChecked():
            vdata.setAllElectrodesVisible()
        elif self.only_clusters.isChecked():
            vdata.setElectrodeClustersVisible() 
        elif self.only_noise.isChecked():
            vdata.setElectrodeNoiseVisible()
        
        
    def __calculateDBSCANClusters(self):
        av = self.parent().active_vol
        vdata = self.parent()._vdata[av]
        
        vdata.setDBSCANEps( self.eps_spinbox.value() )
        vdata.setDBSCANMinPts( self.min_spinbox.value() )
        vdata.clusterWithDBSCAN()
        
        count = vdata.electrode_centroid_clustering.dbscan_clusters
        labels = vdata.electrode_centroid_clustering.dbscan_results.labels_
        
        out = 'Estimated number of clusters: %d\n' % count
        #self.browser.setText('Estimated number of clusters: %d' % count)
        
        for patnum, score in enumerate(labels):
            out += 'Patient {0}: {1}\n'.format(patnum, score)
            
        self.browser.setText(out)
        
        vdata.setElectrodeClustersVisible() 
        self.only_clusters.setChecked(True)       
        
        
    def __toggleVisibility(self):
        av = self.parent().active_vol
        vdata = self.parent()._vdata[av]._electrodes
        
        on = False
        if self.visi.checkState():
            on = True
            self.all_electrodes.setEnabled(True)
            self.only_clusters.setEnabled(True)
            self.only_noise.setEnabled(True)
        else:
            self.all_electrodes.setEnabled(False)
            self.only_clusters.setEnabled(False)
            self.only_noise.setEnabled(False)
            
        for electrode in vdata:
            electrode.setVis(on)
            
        self.apply()
        
        
    def __toggleForceTranslucency(self):
        av = self.parent().active_vol
        vdata = self.parent()._vdata[av]._electrodes
        
        on = False
        if self.forced_translucency.checkState():
            on = True
            
        for electrode in vdata:
            electrode.forceTranslucency(on)
            
        self.apply()
        
        
    def __setOpacityFalloff(self):
        av = self.parent().active_vol
        vdata = self.parent()._vdata[av]._electrodes
        #self.fall_off.setValue( vdata[-1].fall_off )
        
        for electrode in vdata:
            electrode.setFallOff(self.fall_off.value() / 10.0)
            
        self.apply()
        
        
    def __setLineThickness(self):
        av = self.parent().active_vol
        vdata = self.parent()._vdata[av]._electrodes
        
        for electrode in vdata:
            electrode.setThickness(self.thickness.value() / 10.0)
       
        self.apply()
        
        
    def saveCurrentParams(self, av, fresh_load = False):
        #av = self.parent().active_vol
        #vdata = self.parent()._vdata[av]._electrodes
        
        if av not in self.saved_params.keys():
            self.saved_params[av] = ElectrodeParameters()
        
        self.saved_params[av].electrodes_show = self.visi.isChecked()
        self.saved_params[av].electrodes_all = self.all_electrodes.isChecked()
        self.saved_params[av].electrodes_clusters = self.only_clusters.isChecked()
        self.saved_params[av].electrodes_noise = self.only_noise.isChecked()
        self.saved_params[av].falloff = self.fall_off.value()
        self.saved_params[av].thickness = self.thickness.value()
        self.saved_params[av].transp = self.forced_translucency.isChecked()
        self.saved_params[av].fresh_load = fresh_load
            
            
    def updateWidgetValues(self, av, default = False):
        #av = self.parent().active_vol
        #vdata = self.parent()._vdata[av]._electrodes
        
        if av not in self.saved_params.keys():
            self.saved_params[av] = ElectrodeParameters()
        
        if default: # todo: need to have default values in one place for assignment
            self.visi.setChecked( False ) 
            self.all_electrodes.setChecked( False ) 
            self.only_clusters.setChecked( False ) 
            self.only_noise.setChecked( False ) 
            self.fall_off.setValue( 1 ) 
            self.thickness.setValue( 10 ) 
            self.forced_translucency.setChecked( False )
        else:
            self.visi.setChecked( self.saved_params[av].electrodes_show ) 
            self.all_electrodes.setChecked( self.saved_params[av].electrodes_all ) 
            self.only_clusters.setChecked( self.saved_params[av].electrodes_clusters ) 
            self.only_noise.setChecked( self.saved_params[av].electrodes_noise ) 
            self.fall_off.setValue( self.saved_params[av].falloff ) 
            self.thickness.setValue( self.saved_params[av].thickness ) 
            self.forced_translucency.setChecked( self.saved_params[av].transp )
        
    def apply(self):
        av = self.parent().active_vol
        self.parent().vol_qvtk_widgets[av].update()
Example #44
0
class MotorizedLinearPoti(COMCUPluginBase):
    def __init__(self, *args):
        COMCUPluginBase.__init__(self, BrickletMotorizedLinearPoti, *args)

        self.mp = self.device

        self.cbe_position = CallbackEmulator(self.mp.get_position,
                                             self.cb_position,
                                             self.increase_error_count)

        self.current_position = None

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        self.slider.setMinimumWidth(200)
        self.slider.setEnabled(False)

        plots = [('Potentiometer Position', Qt.red, lambda: self.current_position, str)]
        self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider],
                                      curve_motion_granularity=40, update_interval=0.025)

        self.motor_slider = QSlider(Qt.Horizontal)
        self.motor_slider.setRange(0, 100)
        self.motor_slider.valueChanged.connect(self.motor_slider_value_changed)
        self.motor_hold_position = QCheckBox("Hold Position")
        self.motor_drive_mode = QComboBox()
        self.motor_drive_mode.addItem('Fast')
        self.motor_drive_mode.addItem('Smooth')
        
        def get_motor_slider_value():
            return self.motor_slider.value()
        
        self.motor_hold_position.stateChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value()))
        self.motor_drive_mode.currentIndexChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value()))

        self.motor_position_label = MotorPositionLabel('Motor Target Position:')

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.motor_position_label)
        hlayout.addWidget(self.motor_slider)
        hlayout.addWidget(self.motor_drive_mode)
        hlayout.addWidget(self.motor_hold_position)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(hlayout)

    def start(self):
        async_call(self.mp.get_position, None, self.cb_position, self.increase_error_count)
        async_call(self.mp.get_motor_position, None, self.cb_motor_position, self.increase_error_count)

        self.cbe_position.set_period(25)
        self.plot_widget.stop = False

    def stop(self):
        self.cbe_position.set_period(0)
        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletMotorizedLinearPoti.DEVICE_IDENTIFIER

    def cb_position(self, position):
        self.current_position = position
        self.slider.setValue(position)

    def cb_motor_position(self, motor):
        self.motor_slider.blockSignals(True)
        self.motor_hold_position.blockSignals(True)
        self.motor_drive_mode.blockSignals(True)

        self.motor_hold_position.setChecked(motor.hold_position)
        self.motor_drive_mode.setCurrentIndex(motor.drive_mode)
        self.motor_position_label.setText(str(motor.position))
        self.motor_slider.setValue(motor.position)

        self.motor_slider.blockSignals(False)
        self.motor_hold_position.blockSignals(False)
        self.motor_drive_mode.blockSignals(False)

    
    def motor_slider_value_changed(self, position):
        self.motor_position_label.setText(str(position))
        self.mp.set_motor_position(self.motor_slider.value(), self.motor_drive_mode.currentIndex(), self.motor_hold_position.isChecked())
Example #45
0
class LinearPoti(PluginBase):
    qtcb_position = pyqtSignal(int)

    def __init__(self, ipcon, uid):
        PluginBase.__init__(self, ipcon, uid)

        self.lp = bricklet_linear_poti.LinearPoti(self.uid)
        self.ipcon.add_device(self.lp)
        self.version = '.'.join(map(str, self.lp.get_version()[1]))

        self.qtcb_position.connect(self.cb_position)
        self.lp.register_callback(self.lp.CALLBACK_POSITION,
                                  self.qtcb_position.emit)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)

        self.position_label = PositionLabel('Position: ')

        self.current_value = 0
        plot_list = [['', Qt.red, self.get_current_value]]
        self.plot_widget = PlotWidget('Position', plot_list)

        layout_h = QHBoxLayout()
        layout_h.addStretch()
        layout_h.addWidget(self.position_label)
        layout_h.addWidget(self.slider)
        layout_h.addStretch()

        layout = QVBoxLayout(self)
        layout.addLayout(layout_h)
        layout.addWidget(self.plot_widget)

    def start(self):
        try:
            self.cb_position(self.lp.get_position())
            self.lp.set_position_callback_period(20)
        except ip_connection.Error:
            return

        self.plot_widget.stop = False

    def stop(self):
        try:
            self.lp.set_position_callback_period(0)
        except ip_connection.Error:
            pass

        self.plot_widget.stop = True

    @staticmethod
    def has_name(name):
        return 'Linear Poti Bricklet' in name

    def get_current_value(self):
        return self.current_value

    def cb_position(self, position):
        self.current_value = position
        self.slider.setValue(position)
        self.position_label.setText(str(position))
Example #46
0
class MainWindow(object):
    '''
    Main window in View.
    '''
    MAIN_WINDOW_TITLE = "PyGestures"
    def __init__(self):
        '''
        Constructor
        '''
        self.mainWindow = QMainWindow();
        self.mainWindow.setWindowTitle(self.MAIN_WINDOW_TITLE)
        self.mainWindowSignals = MainWindowSignals(self);
        self._createWidgets();
        self._connectSignals();
        self.mainWindow.setCentralWidget(self.mainWidget);
        self.mainWindow.show();
        
    def _createWidgets(self):
        '''
        '''
        self.mainWidget = QWidget(self.mainWindow)
        self.videoWidget = VideoWidget()
        self.scaleButton = QPushButton("Scale capture",self.mainWindow)
        self.trainNetworkButton = QPushButton("Train network",self.mainWindow)
        self.captureButton = QPushButton("Capture",self.mainWindow)
        self.classifyButton = QPushButton("Classify",self.mainWindow)
        self.layout = QGridLayout();
        self.layout.addWidget(self.videoWidget,0,0)
        self.layout.addWidget(self.scaleButton,1,0)
        self.mainWidget.setLayout(self.layout)
        self.cbMinSlider = QSlider(Qt.Horizontal, self.mainWindow)
        self.layout.addWidget(self.cbMinSlider,2,0)
        self.cbMaxSlider = QSlider(Qt.Horizontal, self.mainWindow)
        self.layout.addWidget(self.cbMaxSlider,3,0)
        self.crMinSlider = QSlider(Qt.Horizontal, self.mainWindow)
        self.layout.addWidget(self.crMinSlider,4,0)
        self.crMaxSlider = QSlider(Qt.Horizontal, self.mainWindow)
        self.layout.addWidget(self.crMaxSlider,5,0)
        self.layout.addWidget(self.captureButton,6,0)
        self.layout.addWidget(self.trainNetworkButton,7,0)
        self.layout.addWidget(self.classifyButton,8,0)
        #self.cbMinSlider.setFocusPolicy(QtCore.Qt.NoFocus)
        #self.cbMinSlider.setGeometry(30, 40, 100, 30)
        self.cbMinSlider.setValue(80)
        self.cbMinSlider.setRange(0,255)
        self.cbMinSlider.valueChanged[int].connect(self.mainWindowSignals.changedValueCbMin)
        self.cbMaxSlider.setRange(0,255)
        self.cbMaxSlider.setValue(135)
        self.cbMaxSlider.valueChanged[int].connect(self.mainWindowSignals.changedValueCbMax)
        self.crMinSlider.setRange(0,255)
        self.crMinSlider.setValue(130)
        self.crMinSlider.valueChanged[int].connect(self.mainWindowSignals.changedValueCrMin)
        self.crMaxSlider.setRange(0,255)
        self.crMaxSlider.setValue(180)
        self.crMaxSlider.valueChanged[int].connect(self.mainWindowSignals.changedValueCrMax)
    def _connectSignals(self):
        '''
        '''
        self.mainWindowSignals.camera = self.videoWidget._capture
        self.mainWindow.connect(self.scaleButton,SIGNAL("clicked()"),self.mainWindowSignals.prepareCapture)
        self.mainWindow.connect(self.captureButton,SIGNAL("clicked()"),self.mainWindowSignals.captureImage)
        self.mainWindow.connect(self.trainNetworkButton,SIGNAL("clicked()"),self.mainWindowSignals.trainNetwork)
        self.mainWindow.connect(self.classifyButton,SIGNAL("clicked()"),self.mainWindowSignals.captureImage)
Example #47
0
class XZoomSlider(QWidget):
    zoomAmountChanged = Signal(int)

    def __init__(self, parent=None):
        super(XZoomSlider, self).__init__(parent)

        # define the interface
        in_icon = projexui.resources.find('img/zoom_in.png')
        out_icon = projexui.resources.find('img/zoom_out.png')

        self._zoomInButton = QToolButton(self)
        self._zoomInButton.setAutoRaise(True)
        self._zoomInButton.setToolTip('Zoom In')
        self._zoomInButton.setIcon(QIcon(in_icon))

        self._zoomOutButton = QToolButton(self)
        self._zoomOutButton.setAutoRaise(True)
        self._zoomOutButton.setToolTip('Zoom Out')
        self._zoomOutButton.setIcon(QIcon(out_icon))

        self._zoomSlider = QSlider(Qt.Horizontal, self)
        self._zoomSlider.setRange(10, 100)
        self._zoomSlider.setValue(100)

        # define the layout
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addWidget(self._zoomOutButton)
        layout.addWidget(self._zoomSlider)
        layout.addWidget(self._zoomInButton)

        self.setLayout(layout)

        # create connections
        self._zoomSlider.valueChanged.connect(self.emitZoomAmountChanged)
        self._zoomInButton.clicked.connect(self.zoomIn)
        self._zoomOutButton.clicked.connect(self.zoomOut)

    def emitZoomAmountChanged(self):
        """
        Emits the current zoom amount, provided the signals are not being
        blocked.
        """
        if not self.signalsBlocked():
            self.zoomAmountChanged.emit(self.zoomAmount())

    def maximum(self):
        """
        Returns the maximum zoom level for this widget.
        
        :return     <int>
        """
        return self._zoomSlider.maximum()

    def minimum(self):
        """
        Returns the minimum zoom level for this widget.
        
        :return     <int>
        """
        return self._zoomSlider.minimum()

    def setMaximum(self, maximum):
        """
        Sets the maximum zoom level for this widget.
        
        :param      maximum | <int>
        """
        self._zoomSlider.setMaximum(minimum)

    def setMinimum(self, minimum):
        """
        Sets the minimum zoom level for this widget.
        
        :param      minimum | <int>
        """
        self._zoomSlider.setMinimum(minimum)

    def setZoomStep(self, amount):
        """
        Sets how much a single step for the zoom in/out will be.
        
        :param      amount | <int>
        """
        self._zoomSlider.setPageStep(amount)

    @Slot(int)
    def setZoomAmount(self, amount):
        """
        Sets the zoom amount for this widget to the inputed amount.
        
        :param      amount | <int>
        """
        self._zoomSlider.setValue(amount)

    def zoomAmount(self):
        """
        Returns the current zoom amount for this widget.
        
        :return     <int>
        """
        return self._zoomSlider.value()

    @Slot()
    def zoomIn(self):
        """
        Zooms in by a single page step.
        """
        self._zoomSlider.triggerAction(QSlider.SliderPageStepAdd)

    def zoomInButton(self):
        """
        Returns the zoom in button from the left side of this widget.
        
        :return     <QToolButton>
        """
        return self._zoomInButton

    @Slot()
    def zoomOut(self):
        """
        Zooms out by a single page step.
        """
        self._zoomSlider.triggerAction(QSlider.SliderPageStepSub)

    def zoomOutButton(self):
        """
        Returns the zoom out button from the right side of this widget.
        
        :return     <QToolButton>
        """
        return self._zoomOutButton

    def zoomSlider(self):
        """
        Returns the slider widget of this zoom slider.
        
        :return     <QSlider>
        """
        return self._zoomSlider

    def zoomStep(self):
        """
        Returns the amount for a single step when the user clicks the zoom in/
        out amount.
        
        :return     <int>
        """
        return self._zoomSlider.pageStep()

    x_maximum = Property(int, maximum, setMaximum)
    x_minimum = Property(int, minimum, setMinimum)
    z_zoomStep = Property(int, zoomStep, setZoomStep)