class Slider(QWidget): def __init__(self, caption, default_value, minimum_value=1, maximum_value=60, single_step=1, page_step=6, caption_size=None, unit='', time=False, tooltip=''): QWidget.__init__(self) self.value = default_value self.unit = unit self.time = time description = QLabel(caption) description.setWordWrap(True) description.setToolTip(tooltip) if caption_size: description.setMaximumWidth(caption_size) self.slider = QSlider(Qt.Horizontal) self.slider.setMaximum(maximum_value) self.slider.setMinimum(minimum_value) self.slider.setSingleStep(single_step) self.slider.setPageStep(page_step) self.slider.setToolTip(tooltip) #self.slider.setTickInterval(2) #self.slider.setTickPosition(QSlider.TicksBelow) self.slider.valueChanged.connect(self.__on_change) self.value_label = QLabel() hbox = QHBoxLayout() hbox.addWidget(description) hbox.addWidget(self.slider) hbox.addWidget(self.value_label) hbox.setMargin(0) self.setLayout(hbox) self.setContentsMargins(5, 0, 5, 0) self.slider.setValue(self.value) self.__on_change(self.value) def __on_change(self, value): # FIXME: Fill with spaces to reach the maximum length self.value = value unit = self.unit if self.time: minutes = timedelta(minutes=self.value) date = datetime(1, 1, 1) + minutes text = "%02dh %02dm" % (date.hour, date.minute) else: text = "%s %s" % (self.value, self.unit) self.value_label.setText(text) def get_value(self): return int(self.slider.value())
def getSlider(self, parent): sld = QSlider(parent) sld.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) sld.setMinimum(0) sld.setMaximum(99) sld.setPageStep(10) sld.setPageStep(10) sld.setMinimumHeight(50) sld.setTickInterval(25) sld.setTickPosition(QSlider.TicksBothSides) return sld
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)
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)
class Window(QWidget): def __init__(self, parent = None): QWidget.__init__(self, parent) format = QAudioFormat() format.setChannels(1) format.setFrequency(22050) format.setSampleSize(16) format.setCodec("audio/pcm") format.setByteOrder(QAudioFormat.LittleEndian) format.setSampleType(QAudioFormat.SignedInt) self.output = QAudioOutput(format, self) self.frequency = 440 self.volume = 0 self.buffer = QBuffer() self.data = QByteArray() self.deviceLineEdit = QLineEdit() self.deviceLineEdit.setReadOnly(True) self.deviceLineEdit.setText(QAudioDeviceInfo.defaultOutputDevice().deviceName()) self.pitchSlider = QSlider(Qt.Horizontal) self.pitchSlider.setMaximum(100) self.volumeSlider = QSlider(Qt.Horizontal) self.volumeSlider.setMaximum(32767) self.volumeSlider.setPageStep(1024) self.playButton = QPushButton(self.tr("&Play")) self.pitchSlider.valueChanged.connect(self.changeFrequency) self.volumeSlider.valueChanged.connect(self.changeVolume) self.playButton.clicked.connect(self.play) formLayout = QFormLayout() formLayout.addRow(self.tr("Device:"), self.deviceLineEdit) formLayout.addRow(self.tr("P&itch:"), self.pitchSlider) formLayout.addRow(self.tr("&Volume:"), self.volumeSlider) buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.playButton) buttonLayout.addStretch() horizontalLayout = QHBoxLayout(self) horizontalLayout.addLayout(formLayout) horizontalLayout.addLayout(buttonLayout) def changeFrequency(self, value): self.frequency = 440 + (value * 2) def play(self): if self.output.state() == QAudio.ActiveState: self.output.stop() if self.buffer.isOpen(): self.buffer.close() self.createData() self.buffer.setData(self.data) self.buffer.open(QIODevice.ReadOnly) self.buffer.seek(0) self.output.start(self.buffer) def changeVolume(self, value): self.volume = value def createData(self): # Create 2 seconds of data with 22050 samples per second, each sample # being 16 bits (2 bytes). self.data.clear() for i in xrange(2 * 22050): t = i / 22050.0 value = int(self.volume * sin(2 * pi * self.frequency * t)) self.data.append(struct.pack("<h", value))
class QtSlider(QtControl, ProxySlider): """ A Qt implementation of an Enaml ProxySlider. """ #: A reference to the widget created by the proxy. widget = Typed(QSlider) #: Cyclic notification guard flags. _guard = Int(0) #-------------------------------------------------------------------------- # Initialization API #-------------------------------------------------------------------------- def create_widget(self): """ Create the underlying QSlider widget. """ self.widget = QSlider(self.parent_widget()) def init_widget(self): """ Initialize the underlying widget. """ super(QtSlider, self).init_widget() d = self.declaration self.set_minimum(d.minimum) self.set_maximum(d.maximum) self.set_value(d.value) self.set_orientation(d.orientation) self.set_page_step(d.page_step) self.set_single_step(d.single_step) self.set_tick_interval(d.tick_interval) self.set_tick_position(d.tick_position) self.set_tracking(d.tracking) self.widget.valueChanged.connect(self.on_value_changed) #-------------------------------------------------------------------------- # Signal Handlers #-------------------------------------------------------------------------- def on_value_changed(self): """ Send the 'value_changed' action to the Enaml widget when the slider value has changed. """ if not self._guard & VALUE_FLAG: self._guard |= VALUE_FLAG try: self.declaration.value = self.widget.value() finally: self._guard &= ~VALUE_FLAG #-------------------------------------------------------------------------- # ProxySlider API #-------------------------------------------------------------------------- def set_maximum(self, maximum): """ Set the maximum value of the underlying widget. """ self.widget.setMaximum(maximum) def set_minimum(self, minimum): """ Set the minimum value of the underlying widget. """ self.widget.setMinimum(minimum) def set_value(self, value): """ Set the value of the underlying widget. """ if not self._guard & VALUE_FLAG: self._guard |= VALUE_FLAG try: self.widget.setValue(value) finally: self._guard &= ~VALUE_FLAG def set_page_step(self, page_step): """ Set the page step of the underlying widget. """ self.widget.setPageStep(page_step) def set_single_step(self, single_step): """ Set the single step of the underlying widget. """ self.widget.setSingleStep(single_step) def set_tick_interval(self, interval): """ Set the tick interval of the underlying widget. """ self.widget.setTickInterval(interval) def set_tick_position(self, tick_position): """ Set the tick position of the underlying widget. """ self.widget.setTickPosition(TICK_POSITION[tick_position]) def set_orientation(self, orientation): """ Set the orientation of the underlying widget. """ self.widget.setOrientation(ORIENTATION[orientation]) def set_tracking(self, tracking): """ Set the tracking of the underlying widget. """ self.widget.setTracking(tracking)
class MyMainWindow(QMainWindow): ' Main Window ' def __init__(self, AUTO): ' Initialize QWidget inside MyMainWindow ' super(MyMainWindow, self).__init__() QWidget.__init__(self) self.auto = AUTO self.statusBar().showMessage(' {}'.format(__doc__)) self.setStyleSheet('QStatusBar{color:grey;}') self.setWindowTitle(__doc__) self.setWindowIcon(QIcon.fromTheme("face-monkey")) self.setFont(QFont('Ubuntu Light', 10)) self.setMaximumSize(QDesktopWidget().screenGeometry().width(), QDesktopWidget().screenGeometry().height()) self.base = path.abspath(path.join(getcwd(), str(datetime.now().year))) # directory auto completer self.completer = QCompleter(self) self.dirs = QDirModel(self) self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) # process self.process1 = None self.process2 = None self.cmd1 = 'nice -n {n} arecord{v} -f {f} -c {c} -r {b} -t raw' self.cmd2 = 'oggenc - -r -C {c} -R {b} -q {q} {d}{t}{a} -o {o}' self.process3 = QProcess(self) #self.process3.finished.connect(self.on_process3_finished) #self.process3.error.connect(self.on_process3_error) self.cmd3 = ('nice -n 20 ' + 'sox "{o}" -n spectrogram -x {x} -y {y} -z 99 -t "{o}" -o "{o}.png"') self.actual_file = '' # re starting timers, one stops, one starts self.timerFirst = QTimer(self) self.timerFirst.timeout.connect(self.end) self.timerSecond = QTimer(self) self.timerSecond.timeout.connect(self.run) # Proxy support, by reading http_proxy os env variable proxy_url = QUrl(environ.get('http_proxy', '')) QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.HttpProxy if str(proxy_url.scheme()).startswith('http') else QNetworkProxy.Socks5Proxy, proxy_url.host(), proxy_url.port(), proxy_url.userName(), proxy_url.password())) \ if 'http_proxy' in environ else None print((' INFO: Proxy Auto-Config as ' + str(proxy_url))) # basic widgets layouts and set up self.mainwidget = QTabWidget() self.mainwidget.setToolTip(__doc__) self.mainwidget.setMovable(True) self.mainwidget.setTabShape(QTabWidget.Triangular) self.mainwidget.setContextMenuPolicy(Qt.CustomContextMenu) self.mainwidget.setStyleSheet('QTabBar{color:white;font-weight:bold;}') self.mainwidget.setTabBar(TabBar(self)) self.mainwidget.setTabsClosable(False) self.setCentralWidget(self.mainwidget) self.dock1 = QDockWidget() self.dock2 = QDockWidget() self.dock3 = QDockWidget() self.dock4 = QDockWidget() self.dock5 = QDockWidget() for a in (self.dock1, self.dock2, self.dock3, self.dock4, self.dock5): a.setWindowModality(Qt.NonModal) # a.setWindowOpacity(0.9) a.setWindowTitle(__doc__ if a.windowTitle() == '' else a.windowTitle()) a.setStyleSheet('QDockWidget::title{text-align:center;}') self.mainwidget.addTab(a, QIcon.fromTheme("face-smile"), 'Double Click Me') # Paleta de colores para pintar transparente self.palette().setBrush(QPalette.Base, Qt.transparent) self.setPalette(self.palette()) self.setAttribute(Qt.WA_OpaquePaintEvent, False) # toolbar and basic actions self.toolbar = QToolBar(self) self.toolbar.setIconSize(QSize(24, 24)) # spacer widget for left self.left_spacer = QWidget(self) self.left_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # spacer widget for right self.right_spacer = QWidget(self) self.right_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) qaqq = QAction(QIcon.fromTheme("application-exit"), 'Quit', self) qaqq.setShortcut('Ctrl+Q') qaqq.triggered.connect(exit) qamin = QAction(QIcon.fromTheme("go-down"), 'Minimize', self) qamin.triggered.connect(lambda: self.showMinimized()) qamax = QAction(QIcon.fromTheme("go-up"), 'Maximize', self) qanor = QAction(QIcon.fromTheme("view-fullscreen"), 'AutoCenter AutoResize', self) qanor.triggered.connect(self.center) qatim = QAction(QIcon.fromTheme("mail-signed-verified"), 'View Date and Time', self) qatim.triggered.connect(self.timedate) qabug = QAction(QIcon.fromTheme("help-about"), 'Report a Problem', self) qabug.triggered.connect(lambda: qabug.setDisabled(True) if not call( 'xdg-open mailto:' + '*****@*****.**'.decode('rot13'), shell=True) else ' ERROR ') qamax.triggered.connect(lambda: self.showMaximized()) qaqt = QAction(QIcon.fromTheme("help-about"), 'About Qt', self) qaqt.triggered.connect(lambda: QMessageBox.aboutQt(self)) qakde = QAction(QIcon.fromTheme("help-about"), 'About KDE', self) if KDE: qakde.triggered.connect(KHelpMenu(self, "", False).aboutKDE) qaslf = QAction(QIcon.fromTheme("help-about"), 'About Self', self) if KDE: qaslf.triggered.connect( KAboutApplicationDialog(aboutData, self).exec_) else: qaslf.triggered.connect(lambda: QMessageBox.about(self.mainwidget, __doc__, ''.join((__doc__, linesep, 'version ', __version__, ', (', __license__, '), by ', __author__, ', ( ', __email__, ' )', linesep )))) qafnt = QAction(QIcon.fromTheme("tools-check-spelling"), 'Set GUI Font', self) if KDE: font = QFont() qafnt.triggered.connect(lambda: self.setStyleSheet(''.join(( '*{font-family:', str(font.toString()), '}')) if KFontDialog.getFont(font)[0] == QDialog.Accepted else '')) else: qafnt.triggered.connect(lambda: self.setStyleSheet(''.join(('*{font-family:', str(QFontDialog.getFont()[0].toString()), '}')))) qasrc = QAction(QIcon.fromTheme("applications-development"), 'View Source Code', self) qasrc.triggered.connect(lambda: call('xdg-open {}'.format(__file__), shell=True)) qakb = QAction(QIcon.fromTheme("input-keyboard"), 'Keyboard Shortcuts', self) qakb.triggered.connect(lambda: QMessageBox.information(self.mainwidget, 'Keyboard Shortcuts', ' Ctrl+Q = Quit ')) qapic = QAction(QIcon.fromTheme("camera-photo"), 'Take a Screenshot', self) qapic.triggered.connect(lambda: QPixmap.grabWindow( QApplication.desktop().winId()).save(QFileDialog.getSaveFileName( self.mainwidget, " Save Screenshot As ...", path.expanduser("~"), ';;(*.png) PNG', 'png'))) qatb = QAction(QIcon.fromTheme("go-top"), 'Toggle ToolBar', self) qatb.triggered.connect(lambda: self.toolbar.hide() if self.toolbar.isVisible() is True else self.toolbar.show()) qati = QAction(QIcon.fromTheme("zoom-in"), 'Switch ToolBar Icon Size', self) qati.triggered.connect(lambda: self.toolbar.setIconSize(self.toolbar.iconSize() * 4) if self.toolbar.iconSize().width() * 4 == 24 else self.toolbar.setIconSize(self.toolbar.iconSize() / 4)) qasb = QAction(QIcon.fromTheme("preferences-other"), 'Toggle Tabs Bar', self) qasb.triggered.connect(lambda: self.mainwidget.tabBar().hide() if self.mainwidget.tabBar().isVisible() is True else self.mainwidget.tabBar().show()) qadoc = QAction(QIcon.fromTheme("help-browser"), 'On-line Docs', self) qadoc.triggered.connect(lambda: open_new_tab(str(__url__).strip())) qapy = QAction(QIcon.fromTheme("help-about"), 'About Python', self) qapy.triggered.connect(lambda: open_new_tab('http://python.org/about')) qali = QAction(QIcon.fromTheme("help-browser"), 'Read Licence', self) qali.triggered.connect(lambda: open_new_tab(__full_licence__)) qacol = QAction(QIcon.fromTheme("preferences-system"), 'Set GUI Colors', self) if KDE: color = QColor() qacol.triggered.connect(lambda: self.setStyleSheet(''.join(('* { background-color: ', str(color.name()), '}'))) if KColorDialog.getColor(color, self) else '') else: qacol.triggered.connect(lambda: self.setStyleSheet(''.join(( ' * { background-color: ', str(QColorDialog.getColor().name()), ' } ')))) qatit = QAction(QIcon.fromTheme("preferences-system"), 'Set the App Window Title', self) qatit.triggered.connect(self.seTitle) self.toolbar.addWidget(self.left_spacer) self.toolbar.addSeparator() self.toolbar.addActions((qaqq, qamin, qanor, qamax, qasrc, qakb, qacol, qatim, qatb, qafnt, qati, qasb, qatit, qapic, qadoc, qali, qaslf, qaqt, qakde, qapy, qabug)) self.addToolBar(Qt.TopToolBarArea, self.toolbar) self.toolbar.addSeparator() self.toolbar.addWidget(self.right_spacer) # define the menu menu = self.menuBar() # File menu items menu.addMenu('&File').addActions((qaqq, )) menu.addMenu('&Window').addActions((qamax, qanor, qamin)) # Settings menu menu.addMenu('&Settings').addActions((qasrc, qacol, qafnt, qatim, qatb, qati, qasb, qapic)) # Help menu items menu.addMenu('&Help').addActions((qadoc, qakb, qabug, qali, qaqt, qakde, qapy, qaslf)) # Tray Icon tray = QSystemTrayIcon(QIcon.fromTheme("face-devilish"), self) tray.setToolTip(__doc__) traymenu = QMenu() traymenu.addActions((qamax, qanor, qamin, qaqq)) tray.setContextMenu(traymenu) tray.show() def contextMenuRequested(point): ' quick and dirty custom context menu ' menu = QMenu() menu.addActions((qaqq, qamin, qanor, qamax, qasrc, qakb, qacol, qafnt, qati, qasb, qatb, qatim, qatit, qapic, qadoc, qali, qaslf, qaqt, qakde, qapy, qabug)) menu.exec_(self.mapToGlobal(point)) self.mainwidget.customContextMenuRequested.connect(contextMenuRequested) def must_be_checked(widget_list): ' widget tuple passed as argument should be checked as ON ' for each_widget in widget_list: try: each_widget.setChecked(True) except: pass def must_have_tooltip(widget_list): ' widget tuple passed as argument should have tooltips ' for each_widget in widget_list: try: each_widget.setToolTip(each_widget.text()) except: each_widget.setToolTip(each_widget.currentText()) finally: each_widget.setCursor(QCursor(Qt.PointingHandCursor)) def must_autofillbackground(widget_list): ' widget tuple passed as argument should have filled background ' for each_widget in widget_list: try: each_widget.setAutoFillBackground(True) except: pass def must_glow(widget_list): ' apply an glow effect to the widget ' for glow, each_widget in enumerate(widget_list): try: if each_widget.graphicsEffect() is None: glow = QGraphicsDropShadowEffect(self) glow.setOffset(0) glow.setBlurRadius(99) glow.setColor(QColor(99, 255, 255)) each_widget.setGraphicsEffect(glow) # glow.setEnabled(False) try: each_widget.clicked.connect(lambda: each_widget.graphicsEffect().setEnabled(True) if each_widget.graphicsEffect().isEnabled() is False else each_widget.graphicsEffect().setEnabled(False)) except: each_widget.sliderPressed.connect(lambda: each_widget.graphicsEffect().setEnabled(True) if each_widget.graphicsEffect().isEnabled() is False else each_widget.graphicsEffect().setEnabled(False)) except: pass ####################################################################### # dock 1 QLabel('<h1 style="color:white;"> Record !</h1>', self.dock1).resize( self.dock3.size().width() / 4, 25) self.group1 = QGroupBox() self.group1.setTitle(__doc__) self.spec = QPushButton(self) self.spec.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.spec.setMinimumSize(self.spec.size().width(), 250) self.spec.setFlat(True) self.spec.clicked.connect(self.spectro) self.clock = QLCDNumber() self.clock.setSegmentStyle(QLCDNumber.Flat) self.clock.setMinimumSize(self.clock.size().width(), 50) self.clock.setNumDigits(25) self.timer1 = QTimer(self) self.timer1.timeout.connect(lambda: self.clock.display( datetime.now().strftime("%d-%m-%Y %H:%M:%S %p"))) self.timer1.start(1000) self.clock.setToolTip(datetime.now().strftime("%c %x")) self.clock.setCursor(QCursor(Qt.CrossCursor)) self.diskBar = QProgressBar() self.diskBar.setMinimum(0) self.diskBar.setMaximum(statvfs(HOME).f_blocks * statvfs(HOME).f_frsize / 1024 / 1024 / 1024) self.diskBar.setValue(statvfs(HOME).f_bfree * statvfs(HOME).f_frsize / 1024 / 1024 / 1024) self.diskBar.setToolTip(str(statvfs(HOME).f_bfree * statvfs(HOME).f_frsize / 1024 / 1024 / 1024) + ' Gigabytes free') self.feedback = QPlainTextEdit(''.join(('<center><h3>', __doc__, ', version', __version__, __license__, ' <br> by ', __author__, ' <i>(Dev)</i>, Radio Comunitaria FM Reconquista <i>(Q.A.)</i><br>', 'FMReconquista.org.ar & GitHub.com/JuanCarlosPaco/Cinta-Testigo'))) self.rec = QPushButton(QIcon.fromTheme("media-record"), 'Record') self.rec.setMinimumSize(self.rec.size().width(), 50) self.rec.clicked.connect(self.go) # self.run self.stop = QPushButton(QIcon.fromTheme("media-playback-stop"), 'Stop') self.stop.clicked.connect(self.end) self.kill = QPushButton(QIcon.fromTheme("process-stop"), 'Kill') self.kill.clicked.connect(self.killer) vboxg1 = QVBoxLayout(self.group1) for each_widget in ( QLabel('<b style="color:white;"> Spectro'), self.spec, QLabel('<b style="color:white;"> Time '), self.clock, QLabel('<b style="color:white;"> Disk '), self.diskBar, QLabel('<b style="color:white;"> STDOUT + STDIN '), self.feedback, QLabel('<b style="color:white;"> Record '), self.rec, self.stop, self.kill): vboxg1.addWidget(each_widget) self.group2 = QGroupBox() self.group2.setTitle(__doc__) self.slider = QSlider(self) self.slid_l = QLabel(self.slider) self.slider.setCursor(QCursor(Qt.OpenHandCursor)) self.slider.sliderPressed.connect(lambda: self.slider.setCursor(QCursor(Qt.ClosedHandCursor))) self.slider.sliderReleased.connect(lambda: self.slider.setCursor(QCursor(Qt.OpenHandCursor))) self.slider.valueChanged.connect(lambda: self.slider.setToolTip(str(self.slider.value()))) self.slider.valueChanged.connect(lambda: self.slid_l.setText( '<h2 style="color:white;">{}'.format(self.slider.value()))) self.slider.setMinimum(10) self.slider.setMaximum(99) self.slider.setValue(30) self.slider.setOrientation(Qt.Vertical) self.slider.setTickPosition(QSlider.TicksBothSides) self.slider.setTickInterval(2) self.slider.setSingleStep(10) self.slider.setPageStep(10) vboxg2 = QVBoxLayout(self.group2) for each_widget in ( QLabel('<b style="color:white;">MINUTES of recording'), self.slider, QLabel('<b style="color:white;"> Default: 30 Min')): vboxg2.addWidget(each_widget) group3 = QGroupBox() group3.setTitle(__doc__) try: self.label2 = QLabel(getoutput('sox --version', shell=True)) self.label4 = QLabel(getoutput('arecord --version', shell=1)[:25]) self.label6 = QLabel(str(getoutput('oggenc --version', shell=True))) except: print(''' ERROR: No SOX, OGGenc avaliable ! ( sudo apt-get install vorbis-tools sox alsa-utils ) ''') exit() self.button5 = QPushButton(QIcon.fromTheme("audio-x-generic"), 'OGG --> ZIP') self.button5.clicked.connect(lambda: make_archive( str(QFileDialog.getSaveFileName(self, "Save OGG to ZIP file As...", getcwd(), ';;(*.zip)', 'zip')).replace('.zip', ''), "zip", path.abspath(path.join(getcwd(), str(datetime.now().year))))) self.button1 = QPushButton(QIcon.fromTheme("folder-open"), 'Files') self.button1.clicked.connect(lambda: call('xdg-open ' + getcwd(), shell=True)) self.button0 = QPushButton( QIcon.fromTheme("preferences-desktop-screensaver"), 'LCD OFF') self.button0.clicked.connect(lambda: call('sleep 3 ; xset dpms force off', shell=True)) vboxg3 = QVBoxLayout(group3) for each_widget in ( QLabel('<b style="color:white;"> OGG Output Codec '), self.label6, QLabel('<b style="color:white;"> Raw Record Backend '), self.label4, QLabel('<b style="color:white;"> Helper Libs '), self.label2, QLabel('<b style="color:white;"> OGG ZIP '), self.button5, QLabel('<b style="color:white;"> Files '), self.button1, QLabel('<b style="color:white;"> LCD '), self.button0): vboxg3.addWidget(each_widget) container = QWidget() hbox = QHBoxLayout(container) for each_widget in (self.group2, self.group1, group3): hbox.addWidget(each_widget) self.dock1.setWidget(container) # dock 2 QLabel('<h1 style="color:white;"> Hardware !</h1>', self.dock2).resize( self.dock2.size().width() / 4, 25) try: audioDriverStr = {Solid.AudioInterface.Alsa: "ALSA", Solid.AudioInterface.OpenSoundSystem: "Open Sound", Solid.AudioInterface.UnknownAudioDriver: "Unknown?"} audioInterfaceTypeStr = { Solid.AudioInterface.AudioControl: "Control", Solid.AudioInterface.UnknownAudioInterfaceType: "Unknown?", Solid.AudioInterface.AudioInput: "In", Solid.AudioInterface.AudioOutput: "Out"} soundcardTypeStr = { Solid.AudioInterface.InternalSoundcard: "Internal", Solid.AudioInterface.UsbSoundcard: "USB3", Solid.AudioInterface.FirewireSoundcard: "FireWire", Solid.AudioInterface.Headset: "Headsets", Solid.AudioInterface.Modem: "Modem"} display = QTreeWidget() display.setAlternatingRowColors(True) display.setHeaderLabels(["Items", "ID", "Drivers", "I / O", "Type"]) display.setColumnWidth(0, 350) display.setColumnWidth(1, 350) display.setColumnWidth(3, 75) # retrieve a list of Solid.Device for this machine deviceList = Solid.Device.allDevices() # filter the list of all devices and display matching results # note that we never create a Solid.AudioInterface object, but # receive one from the 'asDeviceInterface' call for device in deviceList: if device.isDeviceInterface( Solid.DeviceInterface.AudioInterface): audio = device.asDeviceInterface( Solid.DeviceInterface.AudioInterface) devtype = audio.deviceType() devstr = [] for key in audioInterfaceTypeStr: flag = key & devtype if flag: devstr.append(audioInterfaceTypeStr[key]) QTreeWidgetItem(display, [device.product(), audio.name(), audioDriverStr[audio.driver()], "/".join(devstr), soundcardTypeStr[audio.soundcardType()]]) self.dock2.setWidget(display) except: self.dock2.setWidget(QLabel(""" <center style='color:white;'> <h1>:(<br>ERROR: Please, install PyKDE !</h1><br> <br><i> (Sorry, can not use non-Qt Libs). Thanks </i><center>""")) ## dock 3 QLabel('<h1 style="color:white;"> Previews !</h1>', self.dock3).resize( self.dock3.size().width() / 4, 25) self.fileView = QColumnView() self.fileView.updatePreviewWidget.connect(self.play) self.fileView.setToolTip(' Browse and Preview Files ') self.media = None self.model = QDirModel() self.fileView.setModel(self.model) self.dock3.setWidget(self.fileView) # dock4 QLabel('<h1 style="color:white;"> Setup !</h1>', self.dock4).resize( self.dock4.size().width() / 4, 25) self.group4 = QGroupBox() self.group4.setTitle(__doc__) self.combo0 = QComboBox() self.combo0.addItems(['S16_LE', 'S32_LE', 'S16_BE', 'U16_LE', 'U16_BE', 'S24_LE', 'S24_BE', 'U24_LE', 'U24_BE', 'S32_BE', 'U32_LE', 'U32_BE']) self.combo1 = QComboBox() self.combo1.addItems(['1', '-1', '0', '2', '3', '4', '5', '6', '7', '8', '9', '10']) self.combo2 = QComboBox() self.combo2.addItems(['128', '256', '512', '1024', '64', '32', '16']) self.combo3 = QComboBox(self) self.combo3.addItems(['MONO', 'STEREO', 'Surround']) self.combo4 = QComboBox() self.combo4.addItems(['44100', '96000', '48000', '32000', '22050', '16000', '11025', '8000']) self.combo5 = QComboBox(self) self.combo5.addItems(['20', '19', '18', '17', '16', '15', '14', '13', '12', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1', '0']) self.nepochoose = QCheckBox('Auto-Tag Files using Nepomuk Semantic') self.chckbx0 = QCheckBox('Disable Software based Volume Control') self.chckbx1 = QCheckBox('Output Sound Stereo-to-Mono Downmix') self.chckbx2 = QCheckBox('Add Date and Time MetaData to Sound files') self.chckbx3 = QCheckBox('Add Yourself as the Author Artist of Sound') vboxg4 = QVBoxLayout(self.group4) for each_widget in ( QLabel('<b style="color:white;"> Sound OGG Quality'), self.combo1, QLabel('<b style="color:white;"> Sound Record Format'), self.combo0, QLabel('<b style="color:white;"> Sound KBps '), self.combo2, QLabel('<b style="color:white;"> Sound Channels '), self.combo3, QLabel('<b style="color:white;"> Sound Sample Rate '), self.combo4, QLabel('<b style="color:white;"> Sound Volume'), self.chckbx0, QLabel('<b style="color:white;"> Sound Mix'), self.chckbx1, QLabel('<b style="color:white;"> Sound Meta'), self.chckbx2, QLabel('<b style="color:white;"> Sound Authorship'), self.chckbx3, QLabel('<b style="color:white;"> CPUs Priority'), self.combo5, QLabel('<b style="color:white;">Nepomuk Semantic User Experience'), self.nepochoose): vboxg4.addWidget(each_widget) self.dock4.setWidget(self.group4) # dock 5 QLabel('<h1 style="color:white;"> Voice Changer ! </h1>', self.dock5 ).resize(self.dock5.size().width() / 3, 25) self.group5 = QGroupBox() self.group5.setTitle(__doc__) self.dial = QDial() self.dial.setCursor(QCursor(Qt.OpenHandCursor)) self.di_l = QLabel(self.dial) self.di_l.resize(self.dial.size() / 8) self.dial.sliderPressed.connect(lambda: self.dial.setCursor(QCursor(Qt.ClosedHandCursor))) self.dial.sliderReleased.connect(lambda: self.dial.setCursor(QCursor(Qt.OpenHandCursor))) self.dial.valueChanged.connect(lambda: self.dial.setToolTip(str(self.dial.value()))) self.dial.valueChanged.connect(lambda: self.di_l.setText( '<h1 style="color:white;">{}'.format(self.dial.value()))) self.dial.setValue(0) self.dial.setMinimum(-999) self.dial.setMaximum(999) self.dial.setSingleStep(100) self.dial.setPageStep(100) self.dial.setWrapping(False) self.dial.setNotchesVisible(True) self.defo = QPushButton(QIcon.fromTheme("media-playback-start"), 'Run') self.defo.setMinimumSize(self.defo.size().width(), 50) self.defo.clicked.connect(lambda: self.process3.start( 'play -q -V0 "|rec -q -V0 -n -d -R riaa pitch {} "' .format(self.dial.value()) if int(self.dial.value()) != 0 else 'play -q -V0 "|rec -q -V0 --multi-threaded -n -d -R bend {} "' .format(' 3,2500,3 3,-2500,3 ' * 999))) self.qq = QPushButton(QIcon.fromTheme("media-playback-stop"), 'Stop') self.qq.clicked.connect(self.process3.kill) self.die = QPushButton(QIcon.fromTheme("process-stop"), 'Kill') self.die.clicked.connect(lambda: call('killall rec', shell=True)) vboxg5 = QVBoxLayout(self.group5) for each_widget in (self.dial, self.defo, self.qq, self.die): vboxg5.addWidget(each_widget) self.dock5.setWidget(self.group5) # configure some widget settings must_be_checked((self.nepochoose, self.chckbx1, self.chckbx2, self.chckbx3)) must_have_tooltip((self.label2, self.label4, self.label6, self.combo0, self.nepochoose, self.combo1, self.combo2, self.combo3, self.combo4, self.combo5, self.chckbx0, self.chckbx1, self.chckbx2, self.chckbx3, self.rec, self.stop, self.defo, self.qq, self.die, self.kill, self.button0, self.button1, self.button5)) must_autofillbackground((self.clock, self.label2, self.label4, self.label6, self.nepochoose, self.chckbx0, self.chckbx1, self.chckbx2, self.chckbx3)) must_glow((self.rec, self.dial, self.combo1)) self.nepomuk_get('testigo') if self.auto is True: self.go() def play(self, index): ' play with delay ' if not self.media: self.media = Phonon.MediaObject(self) audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self) Phonon.createPath(self.media, audioOutput) self.media.setCurrentSource(Phonon.MediaSource( self.model.filePath(index))) self.media.play() def end(self): ' kill it with fire ' print((' INFO: Stoping Processes at {}'.format(str(datetime.now())))) self.process1.terminate() self.process2.terminate() self.feedback.setText(''' <h5>Errors for RECORDER QProcess 1:</h5>{}<hr> <h5>Errors for ENCODER QProcess 2:</h5>{}<hr> <h5>Output for RECORDER QProcess 1:</h5>{}<hr> <h5>Output for ENCODER QProcess 2:</h5>{}<hr> '''.format(self.process1.readAllStandardError(), self.process2.readAllStandardError(), self.process1.readAllStandardOutput(), self.process2.readAllStandardOutput(), )) def killer(self): ' kill -9 ' QMessageBox.information(self.mainwidget, __doc__, ' KILL -9 was sent to the multi-process backend ! ') self.process1.kill() self.process2.kill() def go(self): ' run timeout re-starting timers ' self.timerFirst.start(int(self.slider.value()) * 60 * 1000 + 2000) self.timerSecond.start(int(self.slider.value()) * 60 * 1000 + 2010) self.run() def run(self): ' run forest run ' print((' INFO: Working at {}'.format(str(datetime.now())))) chnl = 1 if self.combo3.currentText() == 'MONO' else 2 print((' INFO: Using {} Channels . . . '.format(chnl))) btrt = int(self.combo4.currentText()) print((' INFO: Using {} Hz per Second . . . '.format(btrt))) threshold = int(self.dial.value()) print((' INFO: Using Thresold of {} . . . '.format(threshold))) print((' INFO: Using Recording time of {}'.format(self.slider.value()))) frmt = str(self.combo0.currentText()).strip() print((' INFO: Using Recording quality of {} ...'.format(frmt))) qlt = str(self.combo1.currentText()).strip() print((' INFO: Using Recording quality of {} ...'.format(qlt))) prio = str(self.combo5.currentText()).strip() print((' INFO: Using CPU Priority of {} ...'.format(prio))) downmix = '--downmix ' if self.chckbx1.isChecked() is True else '' print((' INFO: Using Downmix is {} ...'.format(downmix))) aut = '-a ' + getuser() if self.chckbx3.isChecked() is True else '' print((' INFO: The Author Artist of this sound is: {}'.format(aut))) T = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") tim = '--date {} '.format(T) if self.chckbx2.isChecked() is True else '' print((' INFO: The Date and Time of this sound is: {}'.format(tim))) vol = ' --disable-softvol' if self.chckbx0.isChecked() is True else '' print((' INFO: Software based Volume Control is: {}'.format(vol))) # make base directory try: mkdir(self.base) print((' INFO: Base Directory path created {}'.format(self.base))) except OSError: print((' INFO: Base Directory already exist {}'.format(self.base))) except: print((' ERROR: Can not create Directory ?, {}'.format(self.base))) # make directory tree try: for dr in range(1, 13): mkdir(path.abspath(path.join(self.base, str(dr)))) print((' INFO:Directory created {}/{}'.format(self.base, dr))) except OSError: print((' INFO: Directory already exist {}/1,12'.format(self.base))) except: print((' ERROR: Cant create Directory?, {}/1,12'.format(self.base))) # make new filename flnm = path.abspath(path.join(self.base, str(datetime.now().month), datetime.now().strftime("%Y-%m-%d_%H:%M:%S.ogg"))) self.actual_file = flnm print((' INFO: Recording on the file {}'.format(flnm))) # make custom commands cmd1 = self.cmd1.format(n=prio, f=frmt, c=chnl, b=btrt, v=vol) cmd2 = self.cmd2.format(c=chnl, b=btrt, q=qlt, d=downmix, o=flnm, a=aut, t=tim) print((cmd1, cmd2)) # multiprocess recording loop pipe self.process1 = QProcess(self) self.process2 = QProcess(self) self.process1.setStandardOutputProcess(self.process2) self.process1.start(cmd1) if not self.process1.waitForStarted(): print((" ERROR: RECORDER QProcess 1 Failed: \n {} ".format(cmd1))) self.process2.start(cmd2) if not self.process2.waitForStarted(): print((" ERROR: ENCODER QProcess 2 Failed: \n {} ".format(cmd2))) self.nepomuk_set(flnm, 'testigo', 'testigo', 'AutoTag by Cinta-Testigo') def spectro(self): ' spectrometer ' wid = self.spec.size().width() hei = self.spec.size().height() command = self.cmd3.format(o=self.actual_file, x=wid, y=hei) print(' INFO: Spectrometer is deleting OLD .ogg.png Files on target ') call('rm --verbose --force {}/*/*.ogg.png'.format(self.base), shell=1) print(' INFO: Spectrometer finished Deleting Files, Starting Render ') call(command, shell=True) print((''' INFO: Spectrometer finished Rendering Sound using: {}{} OutPut: {}'''.format(command, linesep, self.actual_file))) self.spec.setIcon(QIcon('{o}.png'.format(o=self.actual_file))) self.spec.setIconSize(QSize(wid, hei)) self.spec.resize(wid, hei) ########################################################################### def paintEvent(self, event): 'Paint semi-transparent background, animated pattern, background text' QWidget.paintEvent(self, event) # make a painter p = QPainter(self) p.setRenderHint(QPainter.TextAntialiasing) p.setRenderHint(QPainter.HighQualityAntialiasing) # fill a rectangle with transparent painting p.fillRect(event.rect(), Qt.transparent) # animated random dots background pattern for i in range(4096): x = randint(9, self.size().width() - 9) y = randint(9, self.size().height() - 9) p.setPen(QPen(QColor(randint(200, 255), randint(200, 255), 255), 1)) p.drawPoint(x, y) # set pen to use white color p.setPen(QPen(QColor(randint(9, 255), randint(9, 255), 255), 1)) # Rotate painter 45 Degree p.rotate(35) # Set painter Font for text p.setFont(QFont('Ubuntu', 300)) # draw the background text, with antialiasing p.drawText(99, 199, "Radio") # Rotate -45 the QPen back ! p.rotate(-35) # set the pen to no pen p.setPen(Qt.NoPen) # Background Color p.setBrush(QColor(0, 0, 0)) # Background Opacity p.setOpacity(0.75) # Background Rounded Borders p.drawRoundedRect(self.rect(), 50, 50) # finalize the painter p.end() def seTitle(self): ' set the title of the main window ' dialog = QDialog(self) textEditInput = QLineEdit(' Type Title Here ') ok = QPushButton(' O K ') ok.clicked.connect(lambda: self.setWindowTitle(textEditInput.text())) ly = QVBoxLayout() [ly.addWidget(wdgt) for wdgt in (QLabel('Title:'), textEditInput, ok)] dialog.setLayout(ly) dialog.exec_() def timedate(self): ' get the time and date ' dialog = QDialog(self) clock = QLCDNumber() clock.setNumDigits(24) timer = QTimer() timer.timeout.connect(lambda: clock.display( datetime.now().strftime("%d-%m-%Y %H:%M:%S %p"))) timer.start(1000) clock.setToolTip(datetime.now().strftime("%c %x")) ok = QPushButton(' O K ') ok.clicked.connect(dialog.close) ly = QVBoxLayout() [ly.addWidget(wdgt) for wdgt in (QCalendarWidget(), clock, ok)] dialog.setLayout(ly) dialog.exec_() def closeEvent(self, event): ' Ask to Quit ' if QMessageBox.question(self, ' Close ', ' Quit ? ', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes: event.accept() else: event.ignore() def center(self): ' Center and resize the window ' self.showNormal() self.resize(QDesktopWidget().screenGeometry().width() // 1.25, QDesktopWidget().screenGeometry().height() // 1.25) qr = self.frameGeometry() qr.moveCenter(QDesktopWidget().availableGeometry().center()) self.move(qr.topLeft()) def nepomuk_set(self, file_tag=None, __tag='', _label='', _description=''): ' Quick and Easy Nepomuk Taggify for Files ' print((''' INFO: Semantic Desktop Experience is Tagging Files : {}, {}, {}, {})'''.format(file_tag, __tag, _label, _description))) if Nepomuk.ResourceManager.instance().init() is 0: fle = Nepomuk.Resource(KUrl(QFileInfo(file_tag).absoluteFilePath())) _tag = Nepomuk.Tag(__tag) _tag.setLabel(_label) fle.addTag(_tag) fle.setDescription(_description) print(([str(a.label()) for a in fle.tags()], fle.description())) return ([str(a.label()) for a in fle.tags()], fle.description()) else: print(" ERROR: FAIL: Nepomuk is not running ! ") def nepomuk_get(self, query_to_search): ' Quick and Easy Nepomuk Query for Files ' print((''' INFO: Semantic Desktop Experience is Quering Files : {} '''.format(query_to_search))) results = [] nepo = Nepomuk.Query.QueryServiceClient() nepo.desktopQuery("hasTag:{}".format(query_to_search)) def _query(data): ''' ('filename.ext', 'file description', ['list', 'of', 'tags']) ''' results.append(([str(a.resource().genericLabel()) for a in data][0], [str(a.resource().description()) for a in data][0], [str(a.label()) for a in iter([a.resource().tags() for a in data][0] )])) nepo.newEntries.connect(_query) def _end(): ''' [ ('filename.ext', 'file description', ['list', 'of', 'tags']), ('filename.ext', 'file description', ['list', 'of', 'tags']), ('filename.ext', 'file description', ['list', 'of', 'tags']) ] ''' nepo.newEntries.disconnect print(results) return results nepo.finishedListing.connect(_end)
class Slider(QWidget): def __init__( self, caption, default_value, minimum_value=1, maximum_value=60, single_step=1, page_step=6, caption_size=None, unit="", time=False, tooltip="", ): QWidget.__init__(self) self.value = default_value self.unit = unit self.time = time description = QLabel(caption) description.setWordWrap(True) description.setToolTip(tooltip) if caption_size: description.setMaximumWidth(caption_size) self.slider = QSlider(Qt.Horizontal) self.slider.setMaximum(maximum_value) self.slider.setMinimum(minimum_value) self.slider.setSingleStep(single_step) self.slider.setPageStep(page_step) self.slider.setToolTip(tooltip) # self.slider.setTickInterval(2) # self.slider.setTickPosition(QSlider.TicksBelow) self.slider.valueChanged.connect(self.__on_change) self.value_label = QLabel() hbox = QHBoxLayout() hbox.addWidget(description) hbox.addWidget(self.slider) hbox.addWidget(self.value_label) hbox.setMargin(0) self.setLayout(hbox) self.setContentsMargins(5, 0, 5, 0) self.slider.setValue(self.value) self.__on_change(self.value) def __on_change(self, value): # FIXME: Fill with spaces to reach the maximum length self.value = value unit = self.unit if self.time: minutes = timedelta(minutes=self.value) date = datetime(1, 1, 1) + minutes text = "%02dh %02dm" % (date.hour, date.minute) else: text = "%s %s" % (self.value, self.unit) self.value_label.setText(text) def get_value(self): return int(self.slider.value())
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)
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)