From 7f0d3c2ab4d1ec6abcc7d9a7768f5992371ada98 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 6 Sep 2017 18:02:09 +0200 Subject: [PATCH 01/22] [new] missing parents added, some preperations --- QtPyLoT.py | 74 +++++++++++++++++++++++++++++++------- pylot/core/util/widgets.py | 48 ++++++++++--------------- 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index c02599e0..9cee1a45 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -109,6 +109,7 @@ class MainWindow(QMainWindow): print('Using default input file {}'.format(infile)) if os.path.isfile(infile) == False: infile = QFileDialog().getOpenFileName(caption='Choose PyLoT-input file') + if not os.path.exists(infile[0]): QMessageBox.warning(self, "PyLoT Warning", "No PyLoT-input file declared!") @@ -209,6 +210,8 @@ class MainWindow(QMainWindow): except: self.startTime = UTCDateTime() + self.init_styles() + pylot_icon = QIcon() pylot_icon.addPixmap(QPixmap(':/icons/pylot.png')) @@ -566,21 +569,22 @@ class MainWindow(QMainWindow): self.eventBox.activated.connect(self.refreshEvents) # add main tab widget - self.tabs = QTabWidget() + self.tabs = QTabWidget(self) self._main_layout.addWidget(self.tabs) self.tabs.currentChanged.connect(self.refreshTabs) # add scroll area used in case number of traces gets too high - self.wf_scroll_area = QtGui.QScrollArea() + self.wf_scroll_area = QtGui.QScrollArea(self) # create central matplotlib figure canvas widget self.pg = pg + #self.set_style('custom') self.init_wfWidget() # init main widgets for main tabs - wf_tab = QtGui.QWidget() - array_tab = QtGui.QWidget() - events_tab = QtGui.QWidget() + wf_tab = QtGui.QWidget(self) + array_tab = QtGui.QWidget(self) + events_tab = QtGui.QWidget(self) # init main widgets layouts self.wf_layout = QtGui.QVBoxLayout() @@ -623,8 +627,8 @@ class MainWindow(QMainWindow): self.dataPlot = PylotCanvas(parent=self, connect_events=False, multicursor=True) self.dataPlot.updateWidget(xlab, None, plottitle) else: - self.pg = True - self.dataPlot = WaveformWidgetPG(parent=self, xlabel=xlab, ylabel=None, + self.pg = pg + self.dataPlot = WaveformWidgetPG(parent=self, title=plottitle) self.dataPlot.setCursor(Qt.CrossCursor) self.wf_scroll_area.setWidget(self.dataPlot) @@ -662,6 +666,53 @@ class MainWindow(QMainWindow): if event.key() == QtCore.Qt.Key.Key_Shift: self._shift = False + def init_styles(self): + self._styles = {} + styles = ['default', 'dark', 'custom'] + for style in styles: + self._styles[style] = {} + + self._styles['default']['stylesheet'] = ("QMainWindow {background-color: rgba(200, 200, 200, 255)}") + # ;" + # "alternate-background-color: rgba(255, 0, 255, 255);" + # "color: rgba(0, 0, 0, 255);" + # "gridline-color: rgba(0, 0, 0, 255);" + # "selection-background-color: rgba(50, 50, 150, 255)};" + # "QMainWindow {background-color: red}") + self._styles['default']['background'] = 'w' + self._styles['default']['foreground'] = 'k' + + self._styles['dark']['stylesheet'] = ("QWidget {background-color: rgba(50, 50, 60, 255);" + "alternate-background-color: rgba(100, 100, 150, 255);" + "border-color: rgba(200, 200, 200, 255);" + "color: rgba(255, 255, 255, 255);" + "gridline-color: rgba(255, 255, 255, 255);" + "selection-background-color: rgba(50, 50, 150, 255)}") + self._styles['dark']['background'] = QtGui.QColor(50, 50, 65, 255) + self._styles['dark']['foreground'] = 'w' + + infile = open('./pylot/core/util/stylesheet.qss', 'r') + stylesheet = infile.read() + infile.close() + self._styles['custom']['stylesheet'] = stylesheet + self._styles['custom']['background'] = QtGui.QColor(50, 50, 65, 255) + self._styles['custom']['foreground'] = 'w' + + + def set_style(self, stylename): + if not stylename in self._styles: + qmb = QMessageBox.warning(self, 'Could not find style', + 'Could not find style with name {}.'.format(stylename)) + return + self._style = stylename + style = self._styles[stylename] + self.setStyleSheet(style['stylesheet']) + + if self.pg: + pg.setConfigOption('background', style['background']) + pg.setConfigOption('foreground', style['foreground']) + pg.setConfigOptions(antialias=True) + @property def metadata(self): return self._metadata @@ -1521,7 +1572,7 @@ class MainWindow(QMainWindow): self.getPlotWidget().updateWidget() plots = self.wfp_thread.data for times, data in plots: - self.dataPlot.plotWidget.getPlotItem().plot(times, data, pen='k') + self.dataPlot.plotWidget.getPlotItem().plot(times, data)#, pen='k') self.dataPlot.reinitMoveProxy() self.dataPlot.plotWidget.showAxis('left') self.dataPlot.plotWidget.showAxis('bottom') @@ -2498,7 +2549,7 @@ class MainWindow(QMainWindow): self.events_layout.removeWidget(self.event_table) # init new qtable - self.event_table = QtGui.QTableWidget() + self.event_table = QtGui.QTableWidget(self) self.event_table.setColumnCount(12) self.event_table.setRowCount(len(eventlist)) self.event_table.setHorizontalHeaderLabels(['', @@ -2775,7 +2826,7 @@ class MainWindow(QMainWindow): if not self.okToContinue(): return if not fnm: - dlg = QFileDialog() + dlg = QFileDialog(parent=self) fnm = dlg.getOpenFileName(self, 'Open project file...', filter='Pylot project (*.plp)') if not fnm: return @@ -2802,7 +2853,7 @@ class MainWindow(QMainWindow): ''' Save back project to new pickle file. ''' - dlg = QFileDialog() + dlg = QFileDialog(self) fnm = dlg.getSaveFileName(self, 'Create a new project file...', filter='Pylot project (*.plp)') filename = fnm[0] if not len(fnm[0]): @@ -3084,7 +3135,6 @@ def create_window(): # window.show() return app, app_created - def main(args=None): project_filename = None pylot_infile = None diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index e038bb3c..a733a98c 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -16,11 +16,6 @@ import time import numpy as np -try: - import pyqtgraph as pg -except: - pg = None - from matplotlib.figure import Figure from pylot.core.util.utils import find_horizontals, identifyPhase, loopIdentifyPhase, trim_station_components, \ identifyPhaseID, check4rotated @@ -64,12 +59,6 @@ elif sys.version_info.major == 2: else: raise ImportError('Could not determine python version.') -if pg: - pg.setConfigOption('background', 'w') - pg.setConfigOption('foreground', 'k') - pg.setConfigOptions(antialias=True) - # pg.setConfigOption('leftButtonPan', False) - def getDataType(parent): type = QInputDialog().getItem(parent, "Select phases type", "Type:", @@ -435,29 +424,30 @@ class PlotWidget(FigureCanvas): class WaveformWidgetPG(QtGui.QWidget): - def __init__(self, parent=None, xlabel='x', ylabel='y', title='Title'): - QtGui.QWidget.__init__(self, parent) # , 1) - self.setParent(parent) - self._parent = parent + def __init__(self, parent, title='Title'): + QtGui.QWidget.__init__(self, parent=parent) + self.pg = self.parent().pg + # added because adding widget to scrollArea will set scrollArea to parent + self.orig_parent = parent # attribute plotdict is a dictionary connecting position and a name self.plotdict = dict() # create plot self.main_layout = QtGui.QVBoxLayout() self.label = QtGui.QLabel() self.setLayout(self.main_layout) - self.plotWidget = pg.PlotWidget(title=title, autoDownsample=True) + self.plotWidget = self.pg.PlotWidget(self.parent(), title=title, autoDownsample=True) self.main_layout.addWidget(self.plotWidget) self.main_layout.addWidget(self.label) - self.plotWidget.showGrid(x=False, y=True, alpha=0.2) + self.plotWidget.showGrid(x=False, y=True, alpha=0.3) self.plotWidget.hideAxis('bottom') self.plotWidget.hideAxis('left') self.wfstart, self.wfend = 0, 0 self.reinitMoveProxy() - self._proxy = pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) + self._proxy = self.pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) def reinitMoveProxy(self): - self.vLine = pg.InfiniteLine(angle=90, movable=False) - self.hLine = pg.InfiniteLine(angle=0, movable=False) + self.vLine = self.pg.InfiniteLine(angle=90, movable=False) + self.hLine = self.pg.InfiniteLine(angle=0, movable=False) self.plotWidget.addItem(self.vLine, ignoreBounds=True) self.plotWidget.addItem(self.hLine, ignoreBounds=True) @@ -467,10 +457,10 @@ class WaveformWidgetPG(QtGui.QWidget): mousePoint = self.plotWidget.getPlotItem().vb.mapSceneToView(pos) x, y, = (mousePoint.x(), mousePoint.y()) # if x > 0:# and index < len(data1): - wfID = self._parent.getWFID(y) - station = self._parent.getStationName(wfID) + wfID = self.orig_parent.getWFID(y) + station = self.orig_parent.getStationName(wfID) abstime = self.wfstart + x - if self._parent.get_current_event(): + if self.orig_parent.get_current_event(): self.label.setText("station = {}, T = {}, t = {} [s]".format(station, abstime, x)) self.vLine.setPos(mousePoint.x()) self.hLine.setPos(mousePoint.y()) @@ -484,12 +474,6 @@ class WaveformWidgetPG(QtGui.QWidget): def clearPlotDict(self): self.plotdict = dict() - def getParent(self): - return self._parent - - def setParent(self, parent): - self._parent = parent - def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None, noiselevel=None, scaleddata=False, mapping=True, component='*', nth_sample=1, iniPick=None, verbosity=0): @@ -3747,6 +3731,12 @@ class GraphicsTab(PropTab): self.main_layout.addWidget(self.spinbox_nth_sample, 1, 1) def add_pg_cb(self): + try: + import pyqtgraph as pg + pg = True + except: + pg = False + text = {True: 'Use pyqtgraphic library for plotting', False: 'Cannot use library: pyqtgraphic not found on system'} label = QLabel('PyQt graphic') From 7ecf9764016ef35b8231af86635dd92484984d82 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 6 Sep 2017 18:34:59 +0200 Subject: [PATCH 02/22] [add] dark stylesheet --- QtPyLoT.py | 36 +++---- pylot/core/util/widgets.py | 2 +- styles/dark.qss | 188 +++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 styles/dark.qss diff --git a/QtPyLoT.py b/QtPyLoT.py index 9cee1a45..6a75b495 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -578,7 +578,7 @@ class MainWindow(QMainWindow): # create central matplotlib figure canvas widget self.pg = pg - #self.set_style('custom') + #self.set_style('dark') self.init_wfWidget() # init main widgets for main tabs @@ -668,36 +668,21 @@ class MainWindow(QMainWindow): def init_styles(self): self._styles = {} - styles = ['default', 'dark', 'custom'] + styles = ['default', 'dark'] for style in styles: self._styles[style] = {} - self._styles['default']['stylesheet'] = ("QMainWindow {background-color: rgba(200, 200, 200, 255)}") - # ;" - # "alternate-background-color: rgba(255, 0, 255, 255);" - # "color: rgba(0, 0, 0, 255);" - # "gridline-color: rgba(0, 0, 0, 255);" - # "selection-background-color: rgba(50, 50, 150, 255)};" - # "QMainWindow {background-color: red}") self._styles['default']['background'] = 'w' self._styles['default']['foreground'] = 'k' + self._styles['default']['stylesheet'] = self.styleSheet() - self._styles['dark']['stylesheet'] = ("QWidget {background-color: rgba(50, 50, 60, 255);" - "alternate-background-color: rgba(100, 100, 150, 255);" - "border-color: rgba(200, 200, 200, 255);" - "color: rgba(255, 255, 255, 255);" - "gridline-color: rgba(255, 255, 255, 255);" - "selection-background-color: rgba(50, 50, 150, 255)}") self._styles['dark']['background'] = QtGui.QColor(50, 50, 65, 255) self._styles['dark']['foreground'] = 'w' - - infile = open('./pylot/core/util/stylesheet.qss', 'r') + # TODO: improve this + infile = open('./styles/dark.qss', 'r') stylesheet = infile.read() infile.close() - self._styles['custom']['stylesheet'] = stylesheet - self._styles['custom']['background'] = QtGui.QColor(50, 50, 65, 255) - self._styles['custom']['foreground'] = 'w' - + self._styles['dark']['stylesheet'] = stylesheet def set_style(self, stylename): if not stylename in self._styles: @@ -708,6 +693,15 @@ class MainWindow(QMainWindow): style = self._styles[stylename] self.setStyleSheet(style['stylesheet']) + bg_colors = [60, 60, 70] + bg_colors = [color/255. for color in bg_colors] + + cycler = matplotlib.cycler(color='wbgrcmy') + matplotlib.rcParams['axes.prop_cycle'] = cycler + matplotlib.rcParams['axes.facecolor'] = '({}, {}, {})'.format(*bg_colors) + matplotlib.rcParams['figure.facecolor'] = '({}, {}, {})'.format(*bg_colors) + + if self.pg: pg.setConfigOption('background', style['background']) pg.setConfigOption('foreground', style['foreground']) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index a733a98c..222e1f5a 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -926,7 +926,7 @@ class PylotCanvas(FigureCanvas): trace.normalize(np.max(np.abs(trace.data)) * 2) times = [time for index, time in enumerate(time_ax) if not index % nth_sample] data = [datum + n for index, datum in enumerate(trace.data) if not index % nth_sample] - ax.plot(times, data, 'k', linewidth=0.7) + ax.plot(times, data, linewidth=0.7) if noiselevel is not None: for level in noiselevel: ax.plot([time_ax[0], time_ax[-1]], diff --git a/styles/dark.qss b/styles/dark.qss new file mode 100644 index 00000000..dd9c0086 --- /dev/null +++ b/styles/dark.qss @@ -0,0 +1,188 @@ +QMainWindow{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +color: rgba(255, 255, 255, 255); +} + +QWidget{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(255, 255, 255, 255); +} + +QComboBox{ +background-color: rgba(80, 80, 90, 255); +color: rgba(255, 255, 255, 255); +} + +QComboBox *{ +background-color: rgba(80, 80, 90, 255); +color: rgba(255, 255, 255, 255); +} + +QMenuBar{ +background-color: rgba(60, 60, 70, 255); +padding:1px; +} + +QMenuBar::item{ +background-color: rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +padding:3px; +} + +QMenu{ +background-color: rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +padding:0; +} + +QMenu::item:selected{ +color: rgba(255, 255, 255, 255); +background-color: rgba(200, 210, 230, 255); +} + +QToolBar{ +border-style:solid; +border-color:rgba(70, 70, 80, 255); +border-width:1px; +} + +QFileDialog QLabel{ +color: rgba(0, 0, 0, 255); +} + +QFileDialog QPushButton{ +background-color: rgba(210, 210, 210, 255); +color: rgba(0, 0, 0, 255); +} + +QMessageBox{ +background-color: rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +} + +QTableWidget{ +background-color: rgba(70, 70, 80, 255); +color:rgba(255, 255, 255, 255); +border-color:rgba(255, 255, 255, 255); +selection-background-color: rgba(200, 210, 230, 255); +} + +QHeaderView::section{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +border:none; +border-top-style:solid; +border-width:1px; +border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +color:rgba(255, 255, 255, 255); +padding:5px; +} + +QHeaderView{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); + +border:none; +border-top-style:solid; +border-width:1px; +border-top-color:rgba(70, 70, 80, 255); +color:rgba(255, 255, 255, 255); +} + +QListWidget{ +background-color:rgba(200, 200, 200, 255); +color:rgba(255, 255, 255, 255); +} + +QStatusBar{ +background-color:rgba(60, 60, 70, 255); +color:rgba(255, 255, 255, 255); +} + +QPushButton{ +background-color:rgba(70, 70, 80, 255); +color:rgba(255, 255, 255, 255); +} + +QPushButton:pressed{ +background-color: rgba(70, 70, 80, 255); +} + +QTabBar{ +background-color:transparent +} + +QTabBar::tab{ +background-color:rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +border-style:solid; +border-color:rgba(80, 80, 90, 255); +border-bottom-color: transparent; +border-width:1px; +padding:5px; +} + +QTabBar::tab:selected{ +background-color:rgba(80, 80, 90, 255); +color: rgba(255, 255, 255, 255); +border-style:solid; +border-color:rgba(80, 80, 90, 255); +border-bottom-color: transparent; +border-width:1px; +padding:5px; +} + +QTabWidget{ +background-color:transparent; +} + +QTabWidget::pane{ +background-color:rgba(255, 255, 255, 255); +border-style:solid; +border-color:rgba(80, 80, 90, 255); +border-width:1px; +} + +QTabWidget::tab{ +background-color:rgba(60, 60, 70, 255); +} + +QTabWidget > QWidget{ +background-color: rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +} + +QScrollArea{ +background: transparent; +} + +QScrollArea>QWidget>QWidget{ +background: transparent; +} + +QLabel{ +color: rgba(255, 255, 255, 255); +background-color: transparent; +} + +QLineEdit{ +border-radius:0; +} + +QListWidget{ +background-color:rgba(60, 60, 70, 255) +} + +QProgressBar{ +border-radius:0; +text-align:center; +color:rgba(255, 255, 255, 255); +background-color:rgba(60,60,80,255); +border: 2px solid #e3a21a; +border-radius:7px; + font: 75 12pt "Open Sans"; + +} + +QProgressBar::chunk{ +background-color:rgba(60, 60, 70, 255); +width:10px; +} \ No newline at end of file From 7e39593b05b9982b1fd1d7818d58faf07b74e9f0 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 7 Sep 2017 10:52:22 +0200 Subject: [PATCH 03/22] [change] dark stylesheet update --- styles/dark.qss | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/styles/dark.qss b/styles/dark.qss index dd9c0086..743fb076 100644 --- a/styles/dark.qss +++ b/styles/dark.qss @@ -1,10 +1,10 @@ QMainWindow{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); } QWidget{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); } @@ -19,18 +19,18 @@ color: rgba(255, 255, 255, 255); } QMenuBar{ -background-color: rgba(60, 60, 70, 255); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); padding:1px; } QMenuBar::item{ -background-color: rgba(60, 60, 70, 255); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); padding:3px; } QMenu{ -background-color: rgba(60, 60, 70, 255); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); padding:0; } @@ -41,11 +41,16 @@ background-color: rgba(200, 210, 230, 255); } QToolBar{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); border-style:solid; border-color:rgba(70, 70, 80, 255); border-width:1px; } +QToolBar *{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +} + QFileDialog QLabel{ color: rgba(0, 0, 0, 255); } @@ -111,10 +116,10 @@ background-color:transparent } QTabBar::tab{ -background-color:rgba(60, 60, 70, 255); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); border-style:solid; -border-color:rgba(80, 80, 90, 255); +border-color:rgba(60, 60, 70, 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -163,7 +168,23 @@ color: rgba(255, 255, 255, 255); background-color: transparent; } +QTextEdit{ +color: rgba(255, 255, 255, 255); +background-color: rgba(80, 80, 90, 255); +} + +QSpinBox{ +color: rgba(255, 255, 255, 255); +background-color: rgba(80, 80, 90, 255); +} + +QDoubleSpinBox{ +color: rgba(255, 255, 255, 255); +background-color: rgba(80, 80, 90, 255); +} + QLineEdit{ +background-color: rgba(80, 80, 90, 255); border-radius:0; } From bab34a23c41628dccf66fb93c7737e88e77da4f6 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 7 Sep 2017 10:59:09 +0200 Subject: [PATCH 04/22] [add] settings for styles --- pylot/styles/__init__.py | 1 + pylot/styles/dark.qss | 209 +++++++++++++++++++++++++++++++++++++++ pylot/styles/settings.py | 44 +++++++++ 3 files changed, 254 insertions(+) create mode 100644 pylot/styles/__init__.py create mode 100644 pylot/styles/dark.qss create mode 100644 pylot/styles/settings.py diff --git a/pylot/styles/__init__.py b/pylot/styles/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/pylot/styles/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss new file mode 100644 index 00000000..743fb076 --- /dev/null +++ b/pylot/styles/dark.qss @@ -0,0 +1,209 @@ +QMainWindow{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(255, 255, 255, 255); +} + +QWidget{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(255, 255, 255, 255); +} + +QComboBox{ +background-color: rgba(80, 80, 90, 255); +color: rgba(255, 255, 255, 255); +} + +QComboBox *{ +background-color: rgba(80, 80, 90, 255); +color: rgba(255, 255, 255, 255); +} + +QMenuBar{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +padding:1px; +} + +QMenuBar::item{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(255, 255, 255, 255); +padding:3px; +} + +QMenu{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(255, 255, 255, 255); +padding:0; +} + +QMenu::item:selected{ +color: rgba(255, 255, 255, 255); +background-color: rgba(200, 210, 230, 255); +} + +QToolBar{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +border-style:solid; +border-color:rgba(70, 70, 80, 255); +border-width:1px; +} + +QToolBar *{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +} + +QFileDialog QLabel{ +color: rgba(0, 0, 0, 255); +} + +QFileDialog QPushButton{ +background-color: rgba(210, 210, 210, 255); +color: rgba(0, 0, 0, 255); +} + +QMessageBox{ +background-color: rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +} + +QTableWidget{ +background-color: rgba(70, 70, 80, 255); +color:rgba(255, 255, 255, 255); +border-color:rgba(255, 255, 255, 255); +selection-background-color: rgba(200, 210, 230, 255); +} + +QHeaderView::section{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +border:none; +border-top-style:solid; +border-width:1px; +border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +color:rgba(255, 255, 255, 255); +padding:5px; +} + +QHeaderView{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); + +border:none; +border-top-style:solid; +border-width:1px; +border-top-color:rgba(70, 70, 80, 255); +color:rgba(255, 255, 255, 255); +} + +QListWidget{ +background-color:rgba(200, 200, 200, 255); +color:rgba(255, 255, 255, 255); +} + +QStatusBar{ +background-color:rgba(60, 60, 70, 255); +color:rgba(255, 255, 255, 255); +} + +QPushButton{ +background-color:rgba(70, 70, 80, 255); +color:rgba(255, 255, 255, 255); +} + +QPushButton:pressed{ +background-color: rgba(70, 70, 80, 255); +} + +QTabBar{ +background-color:transparent +} + +QTabBar::tab{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(255, 255, 255, 255); +border-style:solid; +border-color:rgba(60, 60, 70, 255); +border-bottom-color: transparent; +border-width:1px; +padding:5px; +} + +QTabBar::tab:selected{ +background-color:rgba(80, 80, 90, 255); +color: rgba(255, 255, 255, 255); +border-style:solid; +border-color:rgba(80, 80, 90, 255); +border-bottom-color: transparent; +border-width:1px; +padding:5px; +} + +QTabWidget{ +background-color:transparent; +} + +QTabWidget::pane{ +background-color:rgba(255, 255, 255, 255); +border-style:solid; +border-color:rgba(80, 80, 90, 255); +border-width:1px; +} + +QTabWidget::tab{ +background-color:rgba(60, 60, 70, 255); +} + +QTabWidget > QWidget{ +background-color: rgba(60, 60, 70, 255); +color: rgba(255, 255, 255, 255); +} + +QScrollArea{ +background: transparent; +} + +QScrollArea>QWidget>QWidget{ +background: transparent; +} + +QLabel{ +color: rgba(255, 255, 255, 255); +background-color: transparent; +} + +QTextEdit{ +color: rgba(255, 255, 255, 255); +background-color: rgba(80, 80, 90, 255); +} + +QSpinBox{ +color: rgba(255, 255, 255, 255); +background-color: rgba(80, 80, 90, 255); +} + +QDoubleSpinBox{ +color: rgba(255, 255, 255, 255); +background-color: rgba(80, 80, 90, 255); +} + +QLineEdit{ +background-color: rgba(80, 80, 90, 255); +border-radius:0; +} + +QListWidget{ +background-color:rgba(60, 60, 70, 255) +} + +QProgressBar{ +border-radius:0; +text-align:center; +color:rgba(255, 255, 255, 255); +background-color:rgba(60,60,80,255); +border: 2px solid #e3a21a; +border-radius:7px; + font: 75 12pt "Open Sans"; + +} + +QProgressBar::chunk{ +background-color:rgba(60, 60, 70, 255); +width:10px; +} \ No newline at end of file diff --git a/pylot/styles/settings.py b/pylot/styles/settings.py new file mode 100644 index 00000000..c05164ff --- /dev/null +++ b/pylot/styles/settings.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +# Set base phase colors for manual and automatic picks +# together with a modifier (r, g, or b) used to alternate +# the base color +phasecolors = { + 'manual': { + 'P':{ + 'rgba': (0, 0, 255, 255), + 'modifier': 'g'}, + 'S':{ + 'rgba': (255, 0, 0, 255), + 'modifier': 'b'} + }, + 'auto':{ + 'P':{ + 'rgba': (140, 0, 255, 255), + 'modifier': 'g'}, + 'S':{ + 'rgba': (255, 140, 0, 255), + 'modifier': 'b'} + } +} + +# Set plot colors and stylesheet for each style +stylecolors = { + 'default':{ + 'wf':{ + 'rgba': (0, 0, 0, 255)}, + 'background': { + 'rgba': (255, 255, 255, 255)}, + 'stylesheet': { + 'filename': None} + }, + 'dark':{ + 'wf':{ + 'rgba': (255, 255, 255, 255)}, + 'background':{ + 'rgba': (50, 50, 60, 255)}, + 'stylesheet': { + 'filename': 'styles/dark.qss'} + } +} + From 9c63621ba4bd8300cb56ba2fdf0f56646724caf2 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 7 Sep 2017 16:07:43 +0200 Subject: [PATCH 05/22] [update] style_settings --- QtPyLoT.py | 127 +++++++++++++------- pylot/core/util/utils.py | 45 +++---- pylot/core/util/widgets.py | 117 +++++++++--------- pylot/styles/dark.qss | 49 +++++--- pylot/styles/settings.py | 44 ------- pylot/styles/style_settings.py | 70 +++++++++++ styles/dark.qss | 209 --------------------------------- 7 files changed, 264 insertions(+), 397 deletions(-) delete mode 100644 pylot/styles/settings.py create mode 100644 pylot/styles/style_settings.py delete mode 100644 styles/dark.qss diff --git a/QtPyLoT.py b/QtPyLoT.py index 6a75b495..cf72c1cd 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -74,7 +74,8 @@ from pylot.core.util.connection import checkurl from pylot.core.util.dataprocessing import read_metadata, restitute_data from pylot.core.util.utils import fnConstructor, getLogin, \ full_range, readFilterInformation, trim_station_components, check4gaps, make_pen, pick_color_plt, \ - pick_linestyle_plt, remove_underscores, check4doubled, identifyPhaseID, excludeQualityClasses, has_spe, check4rotated + pick_linestyle_plt, remove_underscores, check4doubled, identifyPhaseID, excludeQualityClasses, has_spe, \ + check4rotated, transform_colors_mpl, transform_colors_mpl_str from pylot.core.util.event import Event from pylot.core.io.location import create_creation_info, create_event from pylot.core.util.widgets import FilterOptionsDialog, NewEventDlg, \ @@ -86,6 +87,8 @@ from pylot.core.util.structure import DATASTRUCTURE from pylot.core.util.thread import Thread, Worker from pylot.core.util.version import get_git_version as _getVersionString +from pylot.styles import style_settings + if sys.version_info.major == 3: import icons_rc_3 as icons_rc elif sys.version_info.major == 2: @@ -140,12 +143,6 @@ class MainWindow(QMainWindow): # default factor for dataplot e.g. enabling/disabling scrollarea self.height_factor = 12 - # default colors for ref/test event - self._colors = { - 'ref': QtGui.QColor(200, 210, 230, 255), - 'test': QtGui.QColor(200, 230, 200, 255) - } - # UI has to be set up before(!) children widgets are about to show up self.createAction = createAction # read settings @@ -553,6 +550,11 @@ class MainWindow(QMainWindow): self.addActions(toolbars["autoPyLoT"], pickActions) self.addActions(toolbars["LocationTools"], locationToolActions) + # init pyqtgraph + self.pg = pg + + # init style + self.set_style('dark') # add event combo box and ref/test buttons self.eventBox = self.createEventBox() @@ -577,8 +579,6 @@ class MainWindow(QMainWindow): self.wf_scroll_area = QtGui.QScrollArea(self) # create central matplotlib figure canvas widget - self.pg = pg - #self.set_style('dark') self.init_wfWidget() # init main widgets for main tabs @@ -647,8 +647,8 @@ class MainWindow(QMainWindow): 'event as test picks for autopicker testing.') self.ref_event_button.setCheckable(True) self.test_event_button.setCheckable(True) - self.set_button_color(self.ref_event_button, self._colors['ref']) - self.set_button_color(self.test_event_button, self._colors['test']) + self.set_button_border_color(self.ref_event_button, self._style['ref']['rgba']) + self.set_button_border_color(self.test_event_button, self._style['test']['rgba']) self.ref_event_button.clicked.connect(self.toggleRef) self.test_event_button.clicked.connect(self.toggleTest) self.ref_event_button.setEnabled(False) @@ -669,43 +669,74 @@ class MainWindow(QMainWindow): def init_styles(self): self._styles = {} styles = ['default', 'dark'] + stylecolors = style_settings.stylecolors for style in styles: - self._styles[style] = {} + if style in stylecolors.keys(): + self._styles[style] = stylecolors[style] - self._styles['default']['background'] = 'w' - self._styles['default']['foreground'] = 'k' - self._styles['default']['stylesheet'] = self.styleSheet() + self._phasecolors = style_settings.phasecolors - self._styles['dark']['background'] = QtGui.QColor(50, 50, 65, 255) - self._styles['dark']['foreground'] = 'w' - # TODO: improve this - infile = open('./styles/dark.qss', 'r') - stylesheet = infile.read() - infile.close() - self._styles['dark']['stylesheet'] = stylesheet + for style, stylecolors in self._styles.items(): + stylesheet = stylecolors['stylesheet']['filename'] + if stylesheet: + stylesheet_file = open(stylesheet, 'r') + stylesheet = stylesheet_file.read() + stylesheet_file.close() + else: + stylesheet = self.styleSheet() - def set_style(self, stylename): + bg_color = stylecolors['background']['rgba'] + line_color = stylecolors['linecolor']['rgba'] + multcursor_color = stylecolors['multicursor']['rgba'] + + # transform to 0-1 values for mpl and update dict + stylecolors['background']['rgba_mpl'] = transform_colors_mpl(bg_color) + stylecolors['linecolor']['rgba_mpl'] = transform_colors_mpl(line_color) + multcursor_color = stylecolors['multicursor']['rgba_mpl'] = transform_colors_mpl(multcursor_color) + + stylecolors['stylesheet'] = stylesheet + + def set_style(self, stylename='default'): if not stylename in self._styles: qmb = QMessageBox.warning(self, 'Could not find style', - 'Could not find style with name {}.'.format(stylename)) + 'Could not find style with name {}. Using default.'.format(stylename)) + self.set_style() return - self._style = stylename + style = self._styles[stylename] + self._style = style self.setStyleSheet(style['stylesheet']) - bg_colors = [60, 60, 70] - bg_colors = [color/255. for color in bg_colors] + # colors for ref/test event + self._ref_test_colors = { + 'ref': QtGui.QColor(*style['ref']['rgba']), + 'test': QtGui.QColor(*style['test']['rgba']), + } - cycler = matplotlib.cycler(color='wbgrcmy') - matplotlib.rcParams['axes.prop_cycle'] = cycler - matplotlib.rcParams['axes.facecolor'] = '({}, {}, {})'.format(*bg_colors) - matplotlib.rcParams['figure.facecolor'] = '({}, {}, {})'.format(*bg_colors) + # plot colors + bg_color = style['background']['rgba'] + bg_color_mpl_na = transform_colors_mpl_str(bg_color, no_alpha=True) + line_color = style['linecolor']['rgba'] + line_color_mpl_na = transform_colors_mpl_str(line_color, no_alpha=True) + for param in matplotlib.rcParams: + if 'color' in param and matplotlib.rcParams[param] in ['k', 'black']: + matplotlib.rcParams[param] = line_color_mpl_na + + matplotlib.rc('axes', + edgecolor=line_color_mpl_na, + facecolor=bg_color_mpl_na, + labelcolor=line_color_mpl_na) + matplotlib.rc('xtick', + color=line_color_mpl_na) + matplotlib.rc('ytick', + color=line_color_mpl_na) + matplotlib.rc('figure', + facecolor=bg_color_mpl_na) if self.pg: - pg.setConfigOption('background', style['background']) - pg.setConfigOption('foreground', style['foreground']) - pg.setConfigOptions(antialias=True) + pg.setConfigOption('background', bg_color) + pg.setConfigOption('foreground', line_color) @property def metadata(self): @@ -846,20 +877,27 @@ class MainWindow(QMainWindow): def add_recentfile(self, event): self.recentfiles.insert(0, event) - def set_button_color(self, button, color=None): + def set_button_border_color(self, button, color=None): ''' Set background color of a button. button: type = QtGui.QAbstractButton color: type = QtGui.QColor or type = str (RGBA) ''' if type(color) == QtGui.QColor: + button.setStyleSheet({'QPushButton{background-color:transparent}'}) palette = button.palette() role = button.backgroundRole() palette.setColor(role, color) button.setPalette(palette) button.setAutoFillBackground(True) - elif type(color) == str or not color: - button.setStyleSheet("background-color: {}".format(color)) + elif type(color) == str: + button.setStyleSheet('QPushButton{border-color: %s}' + 'QPushButton:checked{background-color: rgba%s}'% (color, color)) + elif type(color) == tuple: + button.setStyleSheet('QPushButton{border-color: rgba%s}' + 'QPushButton:checked{background-color: rgba%s}' % (str(color), str(color))) + elif not color: + button.setStyleSheet(self.orig_parent._style['stylesheet']) def getWFFnames(self): try: @@ -1135,9 +1173,9 @@ class MainWindow(QMainWindow): item_ref = QtGui.QStandardItem() # str(event_ref)) item_test = QtGui.QStandardItem() # str(event_test)) if event_ref: - item_ref.setBackground(self._colors['ref']) + item_ref.setBackground(self._ref_test_colors['ref']) if event_test: - item_test.setBackground(self._colors['test']) + item_test.setBackground(self._ref_test_colors['test']) item_notes = QtGui.QStandardItem(event.notes) openIcon = self.style().standardIcon(QStyle.SP_DirOpenIcon) @@ -1959,7 +1997,7 @@ class MainWindow(QMainWindow): def init_canvas_dict(self): self.canvas_dict = {} for key in self.fig_keys: - self.canvas_dict[key] = PylotCanvas(self.fig_dict[key]) + self.canvas_dict[key] = PylotCanvas(self.fig_dict[key], parent=self) def init_fig_dict_wadatijack(self, eventIDs): self.fig_dict_wadatijack = {} @@ -1978,7 +2016,8 @@ class MainWindow(QMainWindow): for eventID in self.fig_dict_wadatijack.keys(): self.canvas_dict_wadatijack[eventID] = {} for key in self.fig_keys_wadatijack: - self.canvas_dict_wadatijack[eventID][key] = PylotCanvas(self.fig_dict_wadatijack[eventID][key]) + self.canvas_dict_wadatijack[eventID][key] = PylotCanvas(self.fig_dict_wadatijack[eventID][key], + parent=self) def tune_autopicker(self): ''' @@ -2597,8 +2636,8 @@ class MainWindow(QMainWindow): item_notes = QtGui.QTableWidgetItem() # manipulate items - item_ref.setBackground(self._colors['ref']) - item_test.setBackground(self._colors['test']) + item_ref.setBackground(self._ref_test_colors['ref']) + item_test.setBackground(self._ref_test_colors['test']) item_path.setText(event.path) if hasattr(event, 'origins'): if event.origins: @@ -2909,7 +2948,7 @@ class MainWindow(QMainWindow): def setParameter(self, show=True): if not self.paraBox: - self.paraBox = PylotParaBox(self._inputs) + self.paraBox = PylotParaBox(self._inputs, parent=self, windowflag=1) self.paraBox.accepted.connect(self._setDirty) self.paraBox.accepted.connect(self.filterOptionsFromParameter) if show: diff --git a/pylot/core/util/utils.py b/pylot/core/util/utils.py index 28dad3bb..d0d7e8f5 100644 --- a/pylot/core/util/utils.py +++ b/pylot/core/util/utils.py @@ -14,6 +14,7 @@ from obspy.signal.rotate import rotate2zne from obspy.io.xseed.utils import SEEDParserException from pylot.core.io.inputs import PylotParameter +from pylot.styles import style_settings from scipy.interpolate import splrep, splev from PySide import QtCore, QtGui @@ -577,36 +578,22 @@ def modify_rgba(rgba, modifier, intensity): def base_phase_colors(picktype, phase): - phases = { - 'manual': - { - 'P': - { - 'rgba': (0, 0, 255, 255), - 'modifier': 'g' - }, - 'S': - { - 'rgba': (255, 0, 0, 255), - 'modifier': 'b' - } - }, - 'auto': - { - 'P': - { - 'rgba': (140, 0, 255, 255), - 'modifier': 'g' - }, - 'S': - { - 'rgba': (255, 140, 0, 255), - 'modifier': 'b' - } - } - } - return phases[picktype][phase] + phasecolors = style_settings.phasecolors + return phasecolors[picktype][phase] +def transform_colors_mpl_str(colors, no_alpha=False): + colors = list(colors) + colors_mpl = tuple([color / 255. for color in colors]) + if no_alpha: + colors_mpl = '({}, {}, {})'.format(*colors_mpl) + else: + colors_mpl = '({}, {}, {}, {})'.format(*colors_mpl) + return colors_mpl + +def transform_colors_mpl(colors): + colors = list(colors) + colors_mpl = tuple([color / 255. for color in colors]) + return colors_mpl def remove_underscores(data): """ diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 222e1f5a..e54fc655 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -442,12 +442,13 @@ class WaveformWidgetPG(QtGui.QWidget): self.plotWidget.hideAxis('bottom') self.plotWidget.hideAxis('left') self.wfstart, self.wfend = 0, 0 + self.pen = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) self.reinitMoveProxy() self._proxy = self.pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) def reinitMoveProxy(self): - self.vLine = self.pg.InfiniteLine(angle=90, movable=False) - self.hLine = self.pg.InfiniteLine(angle=0, movable=False) + self.vLine = self.pg.InfiniteLine(angle=90, movable=False, pen=self.pen) + self.hLine = self.pg.InfiniteLine(angle=0, movable=False, pen=self.pen) self.plotWidget.addItem(self.vLine, ignoreBounds=True) self.plotWidget.addItem(self.hLine, ignoreBounds=True) @@ -594,7 +595,6 @@ class WaveformWidgetPG(QtGui.QWidget): class PylotCanvas(FigureCanvas): def __init__(self, figure=None, parent=None, connect_events=True, multicursor=False, panZoomX=True, panZoomY=True): - self._parent = parent if not figure: figure = Figure() # create axes @@ -602,17 +602,18 @@ class PylotCanvas(FigureCanvas): self.axes = figure.axes self.figure = figure - self.figure.set_facecolor((1., 1., 1.)) + self.figure.set_facecolor(parent._style['background']['rgba_mpl']) # attribute plotdict is a dictionary connecting position and a name self.plotdict = dict() # initialize super class super(PylotCanvas, self).__init__(self.figure) + self.setParent(parent) if multicursor: # add a cursor for station selection self.multiCursor = MultiCursor(self.figure.canvas, self.axes, horizOn=True, useblit=True, - color='m', lw=1) + color=parent._style['multicursor']['rgba_mpl'], lw=1) # initialize panning attributes self.press = None @@ -868,12 +869,6 @@ class PylotCanvas(FigureCanvas): def clearPlotDict(self): self.plotdict = dict() - def getParent(self): - return self._parent - - def setParent(self, parent): - self._parent = parent - def plotWFData(self, wfdata, title=None, zoomx=None, zoomy=None, noiselevel=None, scaleddata=False, mapping=True, component='*', nth_sample=1, iniPick=None, verbosity=0): @@ -906,6 +901,9 @@ class PylotCanvas(FigureCanvas): nsc.sort() nsc.reverse() + style = self.parent()._style + linecolor = style['linecolor']['rgba_mpl'] + for n, (network, station, channel) in enumerate(nsc): st = st_select.select(network=network, station=station, channel=channel) trace = st[0] @@ -926,11 +924,13 @@ class PylotCanvas(FigureCanvas): trace.normalize(np.max(np.abs(trace.data)) * 2) times = [time for index, time in enumerate(time_ax) if not index % nth_sample] data = [datum + n for index, datum in enumerate(trace.data) if not index % nth_sample] - ax.plot(times, data, linewidth=0.7) + ax.plot(times, data, color=linecolor, linewidth=0.7) if noiselevel is not None: for level in noiselevel: ax.plot([time_ax[0], time_ax[-1]], - [level, level], '--k') + [level, level], + color = linecolor, + linestyle = 'dashed') self.setPlotDict(n, (station, channel, network)) if iniPick: ax.vlines(iniPick, ax.get_ylim()[0], ax.get_ylim()[1], @@ -1093,7 +1093,8 @@ class PickDlg(QDialog): def __init__(self, parent=None, data=None, station=None, network=None, picks=None, autopicks=None, rotate=False, parameter=None, embedded=False, metadata=None, event=None, filteroptions=None, model='iasp91'): - super(PickDlg, self).__init__(parent) + super(PickDlg, self).__init__(parent, 1) + self.orig_parent = parent # initialize attributes self.parameter = parameter @@ -1113,6 +1114,7 @@ class PickDlg(QDialog): pylot_user = getpass.getuser() self._user = settings.value('user/Login', pylot_user) self._dirty = False + self._style = parent._style if picks: self.picks = copy.deepcopy(picks) self._init_picks = picks @@ -1508,36 +1510,46 @@ class PickDlg(QDialog): self.leave_picking_mode() def init_p_pick(self): - self.set_button_color(self.p_button, 'yellow') + self.set_button_border_color(self.p_button, 'yellow') self.activatePicking() self.currentPhase = str(self.p_button.text()) def init_s_pick(self): - self.set_button_color(self.s_button, 'yellow') + self.set_button_border_color(self.s_button, 'yellow') self.activatePicking() self.currentPhase = str(self.s_button.text()) def getPhaseID(self, phase): return identifyPhaseID(phase) - def set_button_color(self, button, color=None): + def set_button_border_color(self, button, color=None): + ''' + Set background color of a button. + button: type = QtGui.QAbstractButton + color: type = QtGui.QColor or type = str (RGBA) + ''' if type(color) == QtGui.QColor: + button.setStyleSheet({'QPushButton{background-color:transparent}'}) palette = button.palette() role = button.backgroundRole() palette.setColor(role, color) button.setPalette(palette) button.setAutoFillBackground(True) - elif type(color) == str or not color: - button.setStyleSheet("background-color: {}".format(color)) + elif type(color) == str: + button.setStyleSheet('QPushButton{border-color: %s}' % color) + elif type(color) == tuple: + button.setStyleSheet('QPushButton{border-color: rgba%s}' % str(color)) + elif not color: + button.setStyleSheet(self.orig_parent._style['stylesheet']) def reset_p_button(self): - self.set_button_color(self.p_button) + self.set_button_border_color(self.p_button) self.p_button.setEnabled(True) self.p_button.setChecked(False) self.p_button.setText('P') def reset_s_button(self): - self.set_button_color(self.s_button) + self.set_button_border_color(self.s_button) self.s_button.setEnabled(True) self.s_button.setChecked(False) self.s_button.setText('S') @@ -1676,10 +1688,10 @@ class PickDlg(QDialog): self.cidpress = self.multicompfig.connectPressEvent(self.setPick) if self.getPhaseID(self.currentPhase) == 'P': - self.set_button_color(self.p_button, 'green') + self.set_button_border_color(self.p_button, 'green') self.setIniPickP(gui_event, wfdata, trace_number) elif self.getPhaseID(self.currentPhase) == 'S': - self.set_button_color(self.s_button, 'green') + self.set_button_border_color(self.s_button, 'green') self.setIniPickS(gui_event, wfdata) self.zoomAction.setEnabled(False) @@ -2421,7 +2433,6 @@ class TuneAutopicker(QWidget): def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) - self.parent = parent self.setParent(parent) self.setWindowTitle('PyLoT - Tune Autopicker') self.parameter = parent._inputs @@ -2439,7 +2450,7 @@ class TuneAutopicker(QWidget): self.set_stretch() self.resize(1280, 720) if hasattr(parent, 'metadata'): - self.metadata = self.parent.metadata + self.metadata = self.parent().metadata else: self.metadata = None # self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) @@ -2456,7 +2467,7 @@ class TuneAutopicker(QWidget): self.setLayout(self.main_layout) def init_eventlist(self): - self.eventBox = self.parent.createEventBox() + self.eventBox = self.parent().createEventBox() self.eventBox.setMaxVisibleItems(20) self.fill_eventbox() self.trace_layout.addWidget(self.eventBox) @@ -2474,13 +2485,13 @@ class TuneAutopicker(QWidget): self.stationBox.activated.connect(self.fill_tabs) def fill_stationbox(self): - fnames = self.parent.getWFFnames_from_eventbox(eventbox=self.eventBox) + fnames = self.parent().getWFFnames_from_eventbox(eventbox=self.eventBox) self.data.setWFData(fnames) wfdat = self.data.getWFData() # all available streams # trim station components to same start value trim_station_components(wfdat, trim_start=True, trim_end=False) # rotate misaligned stations to ZNE - wfdat = check4rotated(wfdat, self.parent.metadata) + wfdat = check4rotated(wfdat, self.parent().metadata) self.stationBox.clear() stations = [] for trace in self.data.getWFData(): @@ -2494,7 +2505,7 @@ class TuneAutopicker(QWidget): for network, station in stations: item = QtGui.QStandardItem(network + '.' + station) if station in self.get_current_event().pylot_picks: - item.setBackground(self.parent._colors['ref']) + item.setBackground(self.parent()._colors['ref']) model.appendRow(item) def init_figure_tabs(self): @@ -2509,7 +2520,7 @@ class TuneAutopicker(QWidget): self.stb_names = ['aicARHfig', 'refSpick', 'el_S1pick', 'el_S2pick'] def add_parameters(self): - self.paraBox = PylotParaBox(self.parameter) + self.paraBox = PylotParaBox(self.parameter, parent=self, windowflag=0) self.paraBox.set_tune_mode(True) self.update_eventID() self.parameter_layout.addWidget(self.paraBox) @@ -2535,7 +2546,7 @@ class TuneAutopicker(QWidget): def get_current_event(self): path = self.eventBox.currentText() - return self.parent.project.getEventFromPath(path) + return self.parent().project.getEventFromPath(path) def get_current_event_name(self): return self.eventBox.currentText().split('/')[-1] @@ -2570,10 +2581,10 @@ class TuneAutopicker(QWidget): return station = self.get_current_station() data = self.data.getWFData() - metadata = self.parent.metadata + metadata = self.parent().metadata event = self.get_current_event() - filteroptions = self.parent.filteroptions - pickDlg = PickDlg(self, data=data.select(station=station), + filteroptions = self.parent().filteroptions + pickDlg = PickDlg(self.parent(), data=data.select(station=station), station=station, parameter=self.parameter, picks=self.get_current_event_picks(station), autopicks=self.get_current_event_autopicks(station), @@ -2582,8 +2593,8 @@ class TuneAutopicker(QWidget): pickDlg.update_picks.connect(self.picks_from_pickdlg) pickDlg.update_picks.connect(self.fill_eventbox) pickDlg.update_picks.connect(self.fill_stationbox) - pickDlg.update_picks.connect(lambda: self.parent.setDirty(True)) - pickDlg.update_picks.connect(self.parent.enableSaveEventAction) + pickDlg.update_picks.connect(lambda: self.parent().setDirty(True)) + pickDlg.update_picks.connect(self.parent().enableSaveEventAction) self.pickDlg = QtGui.QWidget() hl = QtGui.QHBoxLayout() self.pickDlg.setLayout(hl) @@ -2591,15 +2602,15 @@ class TuneAutopicker(QWidget): def picks_from_pickdlg(self, picks=None): station = self.get_current_station() - replot = self.parent.addPicks(station, picks) + replot = self.parent().addPicks(station, picks) self.get_current_event().setPick(station, picks) - if self.get_current_event() == self.parent.get_current_event(): + if self.get_current_event() == self.parent().get_current_event(): if replot: - self.parent.plotWaveformDataThread() - self.parent.drawPicks() + self.parent().plotWaveformDataThread() + self.parent().drawPicks() else: - self.parent.drawPicks(station) - self.parent.draw() + self.parent().drawPicks(station) + self.parent().draw() def plot_manual_picks_to_figs(self): picks = self.get_current_event_picks(self.get_current_station()) @@ -2624,13 +2635,13 @@ class TuneAutopicker(QWidget): ('el_S1pick', 0), ('el_S2pick', 0)] for p_ax in p_axes: - axes = self.parent.fig_dict[p_ax[0]].axes + axes = self.parent().fig_dict[p_ax[0]].axes if not axes: continue ax = axes[p_ax[1]] self.plot_manual_Ppick_to_ax(ax, (picks['P']['mpp'] - starttime)) for s_ax in s_axes: - axes = self.parent.fig_dict[s_ax[0]].axes + axes = self.parent().fig_dict[s_ax[0]].axes if not axes: continue ax = axes[s_ax[1]] @@ -2660,7 +2671,7 @@ class TuneAutopicker(QWidget): def fill_tabs(self, event=None, picked=False): self.clear_all() - canvas_dict = self.parent.canvas_dict + canvas_dict = self.parent().canvas_dict self.gen_pick_dlg() self.overview = self.gen_tab_widget('Overview', canvas_dict['mainFig']) id0 = self.figure_tabs.insertTab(0, self.pickDlg, 'Traces Plot') @@ -2706,12 +2717,12 @@ class TuneAutopicker(QWidget): self.init_tab_names() def fill_eventbox(self): - project = self.parent.project + project = self.parent().project if not project: return # update own list - self.parent.fill_eventbox(eventBox=self.eventBox, select_events='ref') - index_start = self.parent.eventBox.currentIndex() + self.parent().fill_eventbox(eventBox=self.eventBox, select_events='ref') + index_start = self.parent().eventBox.currentIndex() index = index_start if index == -1: index += 1 @@ -2730,7 +2741,7 @@ class TuneAutopicker(QWidget): if not index == index_start: self.eventBox.activated.emit(index) # update parent - self.parent.fill_eventbox() + self.parent().fill_eventbox() def update_eventID(self): self.paraBox.boxes['eventID'].setText( @@ -2793,8 +2804,8 @@ class TuneAutopicker(QWidget): def params_from_gui(self): parameters = self.paraBox.params_from_gui() - if self.parent: - self.parent._inputs = parameters + if self.parent(): + self.parent()._inputs = parameters return parameters def set_stretch(self): @@ -2834,7 +2845,7 @@ class PylotParaBox(QtGui.QWidget): accepted = QtCore.Signal(str) rejected = QtCore.Signal(str) - def __init__(self, parameter, parent=None): + def __init__(self, parameter, parent=None, windowflag=1): ''' Generate Widget containing parameters for PyLoT. @@ -2842,7 +2853,7 @@ class PylotParaBox(QtGui.QWidget): :type: PylotParameter (object) ''' - QtGui.QWidget.__init__(self, parent) + QtGui.QWidget.__init__(self, parent, windowflag) self.parameter = parameter self.tabs = QtGui.QTabWidget() self.layout = QtGui.QVBoxLayout() diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index 743fb076..33ec7f74 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -8,9 +8,22 @@ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop color: rgba(255, 255, 255, 255); } +QWidget:checked{ +background-color: transparent; +border-color: rgba(100, 100, 120, 255); +border-width: 2px; +border-style:inset; +} + +FigureCanvasQtAgg{ +background-color: rgba(50, 50, 60, 255); +color: rgba(255, 255, 255, 255); +} + QComboBox{ background-color: rgba(80, 80, 90, 255); color: rgba(255, 255, 255, 255); +min-height: 1.5em; } QComboBox *{ @@ -35,9 +48,9 @@ color: rgba(255, 255, 255, 255); padding:0; } -QMenu::item:selected{ +*::item:selected{ color: rgba(255, 255, 255, 255); -background-color: rgba(200, 210, 230, 255); +background-color: rgba(0, 150, 190, 255); } QToolBar{ @@ -51,15 +64,6 @@ QToolBar *{ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); } -QFileDialog QLabel{ -color: rgba(0, 0, 0, 255); -} - -QFileDialog QPushButton{ -background-color: rgba(210, 210, 210, 255); -color: rgba(0, 0, 0, 255); -} - QMessageBox{ background-color: rgba(60, 60, 70, 255); color: rgba(255, 255, 255, 255); @@ -103,16 +107,26 @@ color:rgba(255, 255, 255, 255); } QPushButton{ -background-color:rgba(70, 70, 80, 255); +background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color:rgba(255, 255, 255, 255); +border-color: (60, 60, 70, 255); +border-style: outset; +border-width: 2px; +border-color: rgba(50, 50, 60, 255); +min-width: 6em; +padding: 5px; } QPushButton:pressed{ background-color: rgba(70, 70, 80, 255); } +*:disabled{ +color:rgba(100, 100, 120, 255); +} + QTabBar{ -background-color:transparent +background-color:transparent; } QTabBar::tab{ @@ -197,13 +211,12 @@ border-radius:0; text-align:center; color:rgba(255, 255, 255, 255); background-color:rgba(60,60,80,255); -border: 2px solid #e3a21a; -border-radius:7px; - font: 75 12pt "Open Sans"; - +border: 2px solid; +border-color:rgba(0, 150, 190, 255); +border-radius:5px; } QProgressBar::chunk{ -background-color:rgba(60, 60, 70, 255); +background-color:rgba(0, 150, 190, 255); width:10px; } \ No newline at end of file diff --git a/pylot/styles/settings.py b/pylot/styles/settings.py deleted file mode 100644 index c05164ff..00000000 --- a/pylot/styles/settings.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- - -# Set base phase colors for manual and automatic picks -# together with a modifier (r, g, or b) used to alternate -# the base color -phasecolors = { - 'manual': { - 'P':{ - 'rgba': (0, 0, 255, 255), - 'modifier': 'g'}, - 'S':{ - 'rgba': (255, 0, 0, 255), - 'modifier': 'b'} - }, - 'auto':{ - 'P':{ - 'rgba': (140, 0, 255, 255), - 'modifier': 'g'}, - 'S':{ - 'rgba': (255, 140, 0, 255), - 'modifier': 'b'} - } -} - -# Set plot colors and stylesheet for each style -stylecolors = { - 'default':{ - 'wf':{ - 'rgba': (0, 0, 0, 255)}, - 'background': { - 'rgba': (255, 255, 255, 255)}, - 'stylesheet': { - 'filename': None} - }, - 'dark':{ - 'wf':{ - 'rgba': (255, 255, 255, 255)}, - 'background':{ - 'rgba': (50, 50, 60, 255)}, - 'stylesheet': { - 'filename': 'styles/dark.qss'} - } -} - diff --git a/pylot/styles/style_settings.py b/pylot/styles/style_settings.py new file mode 100644 index 00000000..1a02bb85 --- /dev/null +++ b/pylot/styles/style_settings.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Set base phase colors for manual and automatic picks +# together with a modifier (r, g, or b) used to alternate +# the base color +phasecolors = { + 'manual': { + 'P':{ + 'rgba': (0, 0, 255, 255), + 'modifier': 'g'}, + 'S':{ + 'rgba': (255, 0, 0, 255), + 'modifier': 'b'} + }, + 'auto':{ + 'P':{ + 'rgba': (140, 0, 255, 255), + 'modifier': 'g'}, + 'S':{ + 'rgba': (255, 140, 0, 255), + 'modifier': 'b'} + } +} + +# Set plot colors and stylesheet for each style +stylecolors = { + 'default':{ + 'linecolor':{ + 'rgba': (0, 0, 0, 255)}, + 'background': { + 'rgba': (255, 255, 255, 255)}, + 'multicursor': { + 'rgba': (255, 190, 0, 255)}, + 'ref': { + 'rgba': (200, 210, 230, 255)}, + 'test': { + 'rgba': (200, 230, 200, 255)}, + 'stylesheet': { + 'filename': None} + }, + 'dark': { + 'linecolor': { + 'rgba': (255, 255, 255, 255)}, + 'background': { + 'rgba': (50, 50, 60, 255)}, + 'multicursor': { + 'rgba': (0, 150, 190, 255)}, + 'ref': { + 'rgba': (80, 110, 170, 255)}, + 'test': { + 'rgba': (130, 190, 100, 255)}, + 'stylesheet': { + 'filename': 'pylot/styles/dark.qss'} + }, + 'bright': { + 'linecolor': { + 'rgba': (0, 0, 0, 255)}, + 'background': { + 'rgba': (255, 255, 255, 255)}, + 'multicursor': { + 'rgba': (100, 100, 190, 255)}, + 'ref': { + 'rgba': (200, 210, 230, 255)}, + 'test': { + 'rgba': (200, 230, 200, 255)}, + 'stylesheet': { + 'filename': 'pylot/styles/bright.qss'} + } +} + diff --git a/styles/dark.qss b/styles/dark.qss deleted file mode 100644 index 743fb076..00000000 --- a/styles/dark.qss +++ /dev/null @@ -1,209 +0,0 @@ -QMainWindow{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -color: rgba(255, 255, 255, 255); -} - -QWidget{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -color: rgba(255, 255, 255, 255); -} - -QComboBox{ -background-color: rgba(80, 80, 90, 255); -color: rgba(255, 255, 255, 255); -} - -QComboBox *{ -background-color: rgba(80, 80, 90, 255); -color: rgba(255, 255, 255, 255); -} - -QMenuBar{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -padding:1px; -} - -QMenuBar::item{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -color: rgba(255, 255, 255, 255); -padding:3px; -} - -QMenu{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -color: rgba(255, 255, 255, 255); -padding:0; -} - -QMenu::item:selected{ -color: rgba(255, 255, 255, 255); -background-color: rgba(200, 210, 230, 255); -} - -QToolBar{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -border-style:solid; -border-color:rgba(70, 70, 80, 255); -border-width:1px; -} - -QToolBar *{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -} - -QFileDialog QLabel{ -color: rgba(0, 0, 0, 255); -} - -QFileDialog QPushButton{ -background-color: rgba(210, 210, 210, 255); -color: rgba(0, 0, 0, 255); -} - -QMessageBox{ -background-color: rgba(60, 60, 70, 255); -color: rgba(255, 255, 255, 255); -} - -QTableWidget{ -background-color: rgba(70, 70, 80, 255); -color:rgba(255, 255, 255, 255); -border-color:rgba(255, 255, 255, 255); -selection-background-color: rgba(200, 210, 230, 255); -} - -QHeaderView::section{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); -border:none; -border-top-style:solid; -border-width:1px; -border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); -color:rgba(255, 255, 255, 255); -padding:5px; -} - -QHeaderView{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); - -border:none; -border-top-style:solid; -border-width:1px; -border-top-color:rgba(70, 70, 80, 255); -color:rgba(255, 255, 255, 255); -} - -QListWidget{ -background-color:rgba(200, 200, 200, 255); -color:rgba(255, 255, 255, 255); -} - -QStatusBar{ -background-color:rgba(60, 60, 70, 255); -color:rgba(255, 255, 255, 255); -} - -QPushButton{ -background-color:rgba(70, 70, 80, 255); -color:rgba(255, 255, 255, 255); -} - -QPushButton:pressed{ -background-color: rgba(70, 70, 80, 255); -} - -QTabBar{ -background-color:transparent -} - -QTabBar::tab{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); -color: rgba(255, 255, 255, 255); -border-style:solid; -border-color:rgba(60, 60, 70, 255); -border-bottom-color: transparent; -border-width:1px; -padding:5px; -} - -QTabBar::tab:selected{ -background-color:rgba(80, 80, 90, 255); -color: rgba(255, 255, 255, 255); -border-style:solid; -border-color:rgba(80, 80, 90, 255); -border-bottom-color: transparent; -border-width:1px; -padding:5px; -} - -QTabWidget{ -background-color:transparent; -} - -QTabWidget::pane{ -background-color:rgba(255, 255, 255, 255); -border-style:solid; -border-color:rgba(80, 80, 90, 255); -border-width:1px; -} - -QTabWidget::tab{ -background-color:rgba(60, 60, 70, 255); -} - -QTabWidget > QWidget{ -background-color: rgba(60, 60, 70, 255); -color: rgba(255, 255, 255, 255); -} - -QScrollArea{ -background: transparent; -} - -QScrollArea>QWidget>QWidget{ -background: transparent; -} - -QLabel{ -color: rgba(255, 255, 255, 255); -background-color: transparent; -} - -QTextEdit{ -color: rgba(255, 255, 255, 255); -background-color: rgba(80, 80, 90, 255); -} - -QSpinBox{ -color: rgba(255, 255, 255, 255); -background-color: rgba(80, 80, 90, 255); -} - -QDoubleSpinBox{ -color: rgba(255, 255, 255, 255); -background-color: rgba(80, 80, 90, 255); -} - -QLineEdit{ -background-color: rgba(80, 80, 90, 255); -border-radius:0; -} - -QListWidget{ -background-color:rgba(60, 60, 70, 255) -} - -QProgressBar{ -border-radius:0; -text-align:center; -color:rgba(255, 255, 255, 255); -background-color:rgba(60,60,80,255); -border: 2px solid #e3a21a; -border-radius:7px; - font: 75 12pt "Open Sans"; - -} - -QProgressBar::chunk{ -background-color:rgba(60, 60, 70, 255); -width:10px; -} \ No newline at end of file From cacfb374681cf9146861c6d65bee5cbd588c8b02 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 7 Sep 2017 16:51:56 +0200 Subject: [PATCH 06/22] [minor] some updates, added bright style sheet --- QtPyLoT.py | 7 +++++-- pylot/core/util/widgets.py | 7 ++++--- pylot/styles/dark.qss | 5 ----- pylot/styles/style_settings.py | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index cf72c1cd..dc447ce8 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -555,6 +555,8 @@ class MainWindow(QMainWindow): # init style self.set_style('dark') + #self.set_style('bright') + #self.set_style('default') # add event combo box and ref/test buttons self.eventBox = self.createEventBox() @@ -668,7 +670,7 @@ class MainWindow(QMainWindow): def init_styles(self): self._styles = {} - styles = ['default', 'dark'] + styles = ['default', 'dark', 'bright'] stylecolors = style_settings.stylecolors for style in styles: if style in stylecolors.keys(): @@ -1604,7 +1606,8 @@ class MainWindow(QMainWindow): self.getPlotWidget().updateWidget() plots = self.wfp_thread.data for times, data in plots: - self.dataPlot.plotWidget.getPlotItem().plot(times, data)#, pen='k') + self.dataPlot.plotWidget.getPlotItem().plot(times, data, + pen=self.dataPlot.pen_linecolor) self.dataPlot.reinitMoveProxy() self.dataPlot.plotWidget.showAxis('left') self.dataPlot.plotWidget.showAxis('bottom') diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index e54fc655..72e81377 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -442,13 +442,14 @@ class WaveformWidgetPG(QtGui.QWidget): self.plotWidget.hideAxis('bottom') self.plotWidget.hideAxis('left') self.wfstart, self.wfend = 0, 0 - self.pen = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) + self.pen_multicursor = self.pg.mkPen(self.parent()._style['multicursor']['rgba']) + self.pen_linecolor = self.pg.mkPen(self.parent()._style['linecolor']['rgba']) self.reinitMoveProxy() self._proxy = self.pg.SignalProxy(self.plotWidget.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved) def reinitMoveProxy(self): - self.vLine = self.pg.InfiniteLine(angle=90, movable=False, pen=self.pen) - self.hLine = self.pg.InfiniteLine(angle=0, movable=False, pen=self.pen) + self.vLine = self.pg.InfiniteLine(angle=90, movable=False, pen=self.pen_multicursor) + self.hLine = self.pg.InfiniteLine(angle=0, movable=False, pen=self.pen_multicursor) self.plotWidget.addItem(self.vLine, ignoreBounds=True) self.plotWidget.addItem(self.hLine, ignoreBounds=True) diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index 33ec7f74..91bfff15 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -15,11 +15,6 @@ border-width: 2px; border-style:inset; } -FigureCanvasQtAgg{ -background-color: rgba(50, 50, 60, 255); -color: rgba(255, 255, 255, 255); -} - QComboBox{ background-color: rgba(80, 80, 90, 255); color: rgba(255, 255, 255, 255); diff --git a/pylot/styles/style_settings.py b/pylot/styles/style_settings.py index 1a02bb85..35c23399 100644 --- a/pylot/styles/style_settings.py +++ b/pylot/styles/style_settings.py @@ -40,7 +40,7 @@ stylecolors = { }, 'dark': { 'linecolor': { - 'rgba': (255, 255, 255, 255)}, + 'rgba': (230, 230, 230, 255)}, 'background': { 'rgba': (50, 50, 60, 255)}, 'multicursor': { From 8717df836a0d316c778777220d1ff59c086439f7 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 09:27:47 +0200 Subject: [PATCH 07/22] [add] bright stylesheet --- pylot/styles/bright.qss | 216 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 pylot/styles/bright.qss diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss new file mode 100644 index 00000000..96ae977a --- /dev/null +++ b/pylot/styles/bright.qss @@ -0,0 +1,216 @@ +QMainWindow{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +color: rgba(0, 0, 0, 255); +} + +QWidget{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +color: rgba(0, 0, 0, 255); +} + +QWidget:checked{ +background-color: transparent; +border-color: rgba(220, 220, 220, 255); +border-width: 2px; +border-style:inset; +} + +QComboBox{ +background-color: rgba(255, 255, 255, 255); +color: rgba(0, 0, 0, 255); +min-height: 1.5em; +} + +QComboBox *{ +background-color: rgba(255, 255, 255, 255); +color: rgba(0, 0, 0, 255); +} + +QMenuBar{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +padding:1px; +} + +QMenuBar::item{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +color: rgba(0, 0, 0, 255); +padding:3px; +} + +QMenu{ +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +color: rgba(0, 0, 0, 255); +padding:0; +} + +*::item:selected{ +color: rgba(0, 0, 0, 255); +background-color: rgba(0, 150, 190, 255); +} + +QToolBar{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +border-style:solid; +border-color:rgba(220, 220, 220, 255); +border-width:1px; +} + +QToolBar *{ +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +} + +QMessageBox{ +background-color: rgba(240, 240, 240 255); +color: rgba(0, 0, 0, 255); +} + +QTableWidget{ +background-color: rgba(240, 240, 240 255); +color:rgba(0, 0, 0, 255); +border-color:rgba(0, 0, 0, 255); +selection-background-color: rgba(200, 210, 230, 255); +} + +QHeaderView::section{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(240, 240, 240 255), stop:1 rgba(220, 220, 220, 255)); +border:none; +border-top-style:solid; +border-width:1px; +border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(240, 240, 240 255), stop:1 rgba(220, 220, 220, 255)); +color:rgba(0, 0, 0, 255); +padding:5px; +} + +QHeaderView{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(240, 240, 240 255), stop:1 rgba(220, 220, 220, 255)); + +border:none; +border-top-style:solid; +border-width:1px; +border-top-color:rgba(220, 220, 220, 255); +color:rgba(0, 0, 0, 255); +} + +QListWidget{ +background-color:rgba(200, 200, 200, 255); +color:rgba(0, 0, 0, 255); +} + +QStatusBar{ +background-color:rgba(240, 240, 240 255); +color:rgba(0, 0, 0, 255); +} + +QPushButton{ +background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +color:rgba(0, 0, 0, 255); +border-style: outset; +border-width: 2px; +border-color: rgba(220, 220, 220, 255); +min-width: 6em; +padding: 5px; +} + +QPushButton:pressed{ +background-color: rgba(220, 220, 220, 255); +} + +*:disabled{ +color:rgba(100, 100, 120, 255); +} + +QTabBar{ +background-color:transparent; +} + +QTabBar::tab{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +color: rgba(0, 0, 0, 255); +border-style:solid; +border-color:rgba(220, 220, 220 255); +border-bottom-color: transparent; +border-width:1px; +padding:5px; +} + +QTabBar::tab:selected{ +background-color:rgba(255, 255, 255, 255); +color: rgba(0, 0, 0, 255); +border-style:solid; +border-color:rgba(220, 220, 220, 255); +border-bottom-color: transparent; +border-width:1px; +padding:5px; +} + +QTabWidget{ +background-color:transparent; +} + +QTabWidget::pane{ +background-color:rgba(0, 0, 0, 255); +border-style:solid; +border-color:rgba(255, 255, 255, 255); +border-width:1px; +} + +QTabWidget::tab{ +background-color:rgba(240, 240, 240 255); +} + +QTabWidget > QWidget{ +background-color: rgba(240, 240, 240 255); +color: rgba(0, 0, 0, 255); +} + +QScrollArea{ +background: transparent; +} + +QScrollArea>QWidget>QWidget{ +background: transparent; +} + +QLabel{ +color: rgba(0, 0, 0, 255); +background-color: transparent; +} + +QTextEdit{ +color: rgba(0, 0, 0, 255); +background-color: rgba(255, 255, 255, 255); +} + +QSpinBox{ +color: rgba(0, 0, 0, 255); +background-color: rgba(255, 255, 255, 255); +} + +QDoubleSpinBox{ +color: rgba(0, 0, 0, 255); +background-color: rgba(255, 255, 255, 255); +} + +QLineEdit{ +background-color: rgba(255, 255, 255, 255); +border-radius:0; +} + +QListWidget{ +background-color:rgba(240, 240, 240 255) +} + +QProgressBar{ +border-radius:0; +text-align:center; +color:rgba(0, 0, 0, 255); +background-color:rgba(60,60,80,255); +border: 2px solid; +border-color:rgba(0, 150, 190, 255); +border-radius:5px; +} + +QProgressBar::chunk{ +background-color:rgba(0, 150, 190, 255); +width:10px; +} \ No newline at end of file From a97258513eb9814e7359d69578dd11e544651ae8 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 10:28:54 +0200 Subject: [PATCH 08/22] [bugfix] missing variable name change --- pylot/core/util/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 7e0a906c..6648e6f8 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2507,7 +2507,7 @@ class TuneAutopicker(QWidget): for network, station in stations: item = QtGui.QStandardItem(network + '.' + station) if station in self.get_current_event().pylot_picks: - item.setBackground(self.parent()._colors['ref']) + item.setBackground(self.parent()._ref_test_colors['ref']) model.appendRow(item) def init_figure_tabs(self): From 51fe48553db7981ac99142487a1be122f66d14bf Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 12:21:56 +0200 Subject: [PATCH 09/22] [update] bright stylesheet --- QtPyLoT.py | 7 ++-- pylot/styles/bright.qss | 79 ++++++++++++++++++++++++----------------- pylot/styles/dark.qss | 22 +++++++++--- 3 files changed, 69 insertions(+), 39 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 61e560f5..63ef7c8e 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -554,8 +554,8 @@ class MainWindow(QMainWindow): self.pg = pg # init style - self.set_style('dark') - #self.set_style('bright') + #self.set_style('dark') + self.set_style('bright') #self.set_style('default') # add event combo box and ref/test buttons @@ -3172,7 +3172,8 @@ def create_window(): return app, app_created def main(args=None): - project_filename = None + #project_filename = None + args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' pylot_infile = None if args: if args.project_filename: diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index 96ae977a..708b9a26 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -1,16 +1,16 @@ QMainWindow{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); color: rgba(0, 0, 0, 255); } QWidget{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(235, 235, 235, 255), stop:1 rgba(230, 230, 230, 255)); color: rgba(0, 0, 0, 255); } QWidget:checked{ background-color: transparent; -border-color: rgba(220, 220, 220, 255); +border-color: rgba(230, 230, 230, 255); border-width: 2px; border-style:inset; } @@ -19,100 +19,115 @@ QComboBox{ background-color: rgba(255, 255, 255, 255); color: rgba(0, 0, 0, 255); min-height: 1.5em; + +selection-background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 55, 140, 150), stop:1 rgba(0, 70, 180, 150)); } QComboBox *{ background-color: rgba(255, 255, 255, 255); color: rgba(0, 0, 0, 255); + +selection-background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 55, 140, 150), stop:1 rgba(0, 70, 180, 150)); +selection-color: rgba(255, 255, 255, 255); } QMenuBar{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(240, 240, 240, 255), stop:1 rgba(230, 230, 230, 255)); padding:1px; } QMenuBar::item{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(240, 240, 240, 255), stop:1 rgba(230, 230, 230, 255)); color: rgba(0, 0, 0, 255); padding:3px; } QMenu{ -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(230, 230, 230 255)); color: rgba(0, 0, 0, 255); padding:0; } *::item:selected{ color: rgba(0, 0, 0, 255); -background-color: rgba(0, 150, 190, 255); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 55, 140, 150), stop:1 rgba(0, 70, 180, 150)); } QToolBar{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); border-style:solid; -border-color:rgba(220, 220, 220, 255); +border-color:rgba(200, 200, 200, 150); border-width:1px; } QToolBar *{ -background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); } QMessageBox{ -background-color: rgba(240, 240, 240 255); +background-color: rgba(255, 255, 255, 255); color: rgba(0, 0, 0, 255); } QTableWidget{ -background-color: rgba(240, 240, 240 255); +background-color: rgba(255, 255, 255, 255); color:rgba(0, 0, 0, 255); border-color:rgba(0, 0, 0, 255); selection-background-color: rgba(200, 210, 230, 255); } +QTableCornerButton::section{ +border: none; +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); +} + QHeaderView::section{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(240, 240, 240 255), stop:1 rgba(220, 220, 220, 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); border:none; border-top-style:solid; border-width:1px; -border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(240, 240, 240 255), stop:1 rgba(220, 220, 220, 255)); +border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); color:rgba(0, 0, 0, 255); padding:5px; } +QHeaderView::section:checked{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 55, 140, 150), stop:1 rgba(0, 70, 180, 150)); +border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 55, 140, 150), stop:1 rgba(0, 70, 180, 150)); +} + QHeaderView{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(240, 240, 240 255), stop:1 rgba(220, 220, 220, 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); border:none; border-top-style:solid; border-width:1px; -border-top-color:rgba(220, 220, 220, 255); +border-top-color:rgba(230, 230, 230, 255); color:rgba(0, 0, 0, 255); } QListWidget{ -background-color:rgba(200, 200, 200, 255); +background-color:rgba(230, 230, 230, 255); color:rgba(0, 0, 0, 255); } QStatusBar{ -background-color:rgba(240, 240, 240 255); +background-color:rgba(255, 255, 255, 255); color:rgba(0, 0, 0, 255); } QPushButton{ -background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); color:rgba(0, 0, 0, 255); border-style: outset; border-width: 2px; -border-color: rgba(220, 220, 220, 255); +border-color: rgba(230, 230, 230, 255); min-width: 6em; padding: 5px; } QPushButton:pressed{ -background-color: rgba(220, 220, 220, 255); +background-color: rgba(230, 230, 230, 255); } *:disabled{ @@ -124,10 +139,10 @@ background-color:transparent; } QTabBar::tab{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(240, 240, 240 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); color: rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(220, 220, 220 255); +border-color:rgba(230, 230, 230 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -137,7 +152,7 @@ QTabBar::tab:selected{ background-color:rgba(255, 255, 255, 255); color: rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(220, 220, 220, 255); +border-color:rgba(200, 200, 200, 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -150,16 +165,16 @@ background-color:transparent; QTabWidget::pane{ background-color:rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(255, 255, 255, 255); +border-color:rgba(200, 200, 200, 255); border-width:1px; } QTabWidget::tab{ -background-color:rgba(240, 240, 240 255); +background-color:rgba(255, 255, 255, 255); } QTabWidget > QWidget{ -background-color: rgba(240, 240, 240 255); +background-color: rgba(255, 255, 255, 255); color: rgba(0, 0, 0, 255); } @@ -197,20 +212,20 @@ border-radius:0; } QListWidget{ -background-color:rgba(240, 240, 240 255) +background-color:rgba(255, 255, 255, 255) } QProgressBar{ border-radius:0; text-align:center; color:rgba(0, 0, 0, 255); -background-color:rgba(60,60,80,255); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); border: 2px solid; -border-color:rgba(0, 150, 190, 255); +border-color:rgba(0, 55, 140, 150); border-radius:5px; } QProgressBar::chunk{ -background-color:rgba(0, 150, 190, 255); +background-color:rgba(60, 60, 70, 150); width:10px; -} \ No newline at end of file +} diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index 91bfff15..f4a8e447 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -18,12 +18,17 @@ border-style:inset; QComboBox{ background-color: rgba(80, 80, 90, 255); color: rgba(255, 255, 255, 255); -min-height: 1.5em; +min-height: 1.8em; + +selection-background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 144, 180, 255), stop:1 rgba(0, 150, 190, 255)); } QComboBox *{ background-color: rgba(80, 80, 90, 255); color: rgba(255, 255, 255, 255); + +selection-background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 144, 180, 255), stop:1 rgba(0, 150, 190, 255)); +selection-color: rgba(255, 255, 255, 255); } QMenuBar{ @@ -45,7 +50,7 @@ padding:0; *::item:selected{ color: rgba(255, 255, 255, 255); -background-color: rgba(0, 150, 190, 255); +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 144, 180, 255), stop:1 rgba(0, 150, 190, 255)); } QToolBar{ @@ -71,6 +76,11 @@ border-color:rgba(255, 255, 255, 255); selection-background-color: rgba(200, 210, 230, 255); } +QTableCornerButton::section{ +border: none; +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); +} + QHeaderView::section{ background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); border:none; @@ -81,6 +91,11 @@ color:rgba(255, 255, 255, 255); padding:5px; } +QHeaderView::section:checked{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 120, 150, 255), stop:1 rgba(0, 150, 190, 255)); +border-top-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 120, 150, 255), stop:1 rgba(0, 150, 190, 255)); +} + QHeaderView{ background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(60, 60, 70, 255), stop:1 rgba(70, 70, 80, 255)); @@ -104,7 +119,6 @@ color:rgba(255, 255, 255, 255); QPushButton{ background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color:rgba(255, 255, 255, 255); -border-color: (60, 60, 70, 255); border-style: outset; border-width: 2px; border-color: rgba(50, 50, 60, 255); @@ -214,4 +228,4 @@ border-radius:5px; QProgressBar::chunk{ background-color:rgba(0, 150, 190, 255); width:10px; -} \ No newline at end of file +} From d15828a058ccdfae8d87aa1d488a5cef9c509cef Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 12:25:30 +0200 Subject: [PATCH 10/22] [add] pick trace button color --- QtPyLoT.py | 4 ++-- pylot/core/util/widgets.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 63ef7c8e..5a41557b 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -554,8 +554,8 @@ class MainWindow(QMainWindow): self.pg = pg # init style - #self.set_style('dark') - self.set_style('bright') + self.set_style('dark') + #self.set_style('bright') #self.set_style('default') # add event combo box and ref/test buttons diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 6648e6f8..534141ac 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2531,6 +2531,7 @@ class TuneAutopicker(QWidget): def add_buttons(self): self.pick_button = QtGui.QPushButton('Pick Trace') + self.pick_button.setStyleSheet('QPushButton{border-color: rgba(110, 200, 0, 255)}') self.pick_button.clicked.connect(self.call_picker) self.close_button = QtGui.QPushButton('Close') self.close_button.clicked.connect(self.hide) From 7ef784f2d2453f07ae4f8bcbca0b1191051dcd92 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 15:50:08 +0200 Subject: [PATCH 11/22] [minor] color changes --- QtPyLoT.py | 4 ++-- pylot/styles/bright.qss | 11 ++++++++--- pylot/styles/dark.qss | 27 ++++++++++++++++----------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 5a41557b..b1f872a2 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -3172,8 +3172,8 @@ def create_window(): return app, app_created def main(args=None): - #project_filename = None - args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' + project_filename = None + #args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' pylot_infile = None if args: if args.project_filename: diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index 708b9a26..25fdb5c2 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -8,7 +8,7 @@ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgb color: rgba(0, 0, 0, 255); } -QWidget:checked{ +QToolBar QWidget:checked{ background-color: transparent; border-color: rgba(230, 230, 230, 255); border-width: 2px; @@ -152,7 +152,7 @@ QTabBar::tab:selected{ background-color:rgba(255, 255, 255, 255); color: rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(200, 200, 200, 255); +border-color:rgba(255, 255, 255, 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -165,7 +165,7 @@ background-color:transparent; QTabWidget::pane{ background-color:rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(200, 200, 200, 255); +border-color:rgba(255, 255, 255, 255); border-width:1px; } @@ -211,6 +211,11 @@ background-color: rgba(255, 255, 255, 255); border-radius:0; } +QCheckBox{ +background-color:transparent; +border:none; +} + QListWidget{ background-color:rgba(255, 255, 255, 255) } diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index f4a8e447..3caef6ba 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -8,7 +8,7 @@ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop color: rgba(255, 255, 255, 255); } -QWidget:checked{ +QToolBar QWidget:checked{ background-color: transparent; border-color: rgba(100, 100, 120, 255); border-width: 2px; @@ -56,7 +56,7 @@ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgb QToolBar{ background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); border-style:solid; -border-color:rgba(70, 70, 80, 255); +border-color:rgba(80, 80, 90, 255); border-width:1px; } @@ -70,7 +70,7 @@ color: rgba(255, 255, 255, 255); } QTableWidget{ -background-color: rgba(70, 70, 80, 255); +background-color: rgba(80, 80, 90, 255); color:rgba(255, 255, 255, 255); border-color:rgba(255, 255, 255, 255); selection-background-color: rgba(200, 210, 230, 255); @@ -127,7 +127,7 @@ padding: 5px; } QPushButton:pressed{ -background-color: rgba(70, 70, 80, 255); +background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(80, 80, 90, 255), stop:1 rgba(70, 70, 80, 255)); } *:disabled{ @@ -142,17 +142,17 @@ QTabBar::tab{ background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); border-style:solid; -border-color:rgba(60, 60, 70, 255); +border-color:rgba(70, 70, 80, 255); border-bottom-color: transparent; border-width:1px; padding:5px; } QTabBar::tab:selected{ -background-color:rgba(80, 80, 90, 255); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(80, 80, 90, 255), stop:1 rgba(70, 70, 80, 255)); color: rgba(255, 255, 255, 255); border-style:solid; -border-color:rgba(80, 80, 90, 255); +border-color:rgba(70, 70, 80, 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -163,18 +163,18 @@ background-color:transparent; } QTabWidget::pane{ -background-color:rgba(255, 255, 255, 255); +background-color:rgba(70, 70, 80, 255); border-style:solid; -border-color:rgba(80, 80, 90, 255); +border-color:rgba(70, 70, 80, 255); border-width:1px; } QTabWidget::tab{ -background-color:rgba(60, 60, 70, 255); +background-color:rgba(70, 70, 80, 255); } QTabWidget > QWidget{ -background-color: rgba(60, 60, 70, 255); +background-color: rgba(70, 70, 80, 255); color: rgba(255, 255, 255, 255); } @@ -206,6 +206,11 @@ color: rgba(255, 255, 255, 255); background-color: rgba(80, 80, 90, 255); } +QCheckBox{ +background-color:transparent; +border:none; +} + QLineEdit{ background-color: rgba(80, 80, 90, 255); border-radius:0; From 104a8dda64bac1b30192827d037a9ac729e4828c Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 17:01:36 +0200 Subject: [PATCH 12/22] [update] add linecolor settings to autoPyLoT figs --- QtPyLoT.py | 24 ++++++++++++----- pylot/core/pick/autopick.py | 54 +++++++++++++++++++++++++++---------- pylot/core/pick/picker.py | 17 ++++++------ pylot/core/pick/utils.py | 33 ++++++++++++----------- pylot/core/util/widgets.py | 3 ++- 5 files changed, 86 insertions(+), 45 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index b1f872a2..27b9689e 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -1991,27 +1991,36 @@ class MainWindow(QMainWindow): 'el_S1pick', 'el_S2pick', 'refSpick', - 'aicARHfig' + 'aicARHfig', + 'plot_style' ] for key in self.fig_keys: - fig = Figure() + if key == 'plot_style': + fig = self._style + else: + fig = Figure() self.fig_dict[key] = fig def init_canvas_dict(self): self.canvas_dict = {} for key in self.fig_keys: - self.canvas_dict[key] = PylotCanvas(self.fig_dict[key], parent=self) + if not key == 'plot_style': + self.canvas_dict[key] = PylotCanvas(self.fig_dict[key], parent=self) def init_fig_dict_wadatijack(self, eventIDs): self.fig_dict_wadatijack = {} self.fig_keys_wadatijack = [ 'jackknife', - 'wadati' + 'wadati', + 'plot_style' ] for eventID in eventIDs: self.fig_dict_wadatijack[eventID] = {} for key in self.fig_keys_wadatijack: - fig = Figure() + if key == 'plot_style': + fig = self._style + else: + fig = Figure() self.fig_dict_wadatijack[eventID][key] = fig def init_canvas_dict_wadatijack(self): @@ -2019,8 +2028,9 @@ class MainWindow(QMainWindow): for eventID in self.fig_dict_wadatijack.keys(): self.canvas_dict_wadatijack[eventID] = {} for key in self.fig_keys_wadatijack: - self.canvas_dict_wadatijack[eventID][key] = PylotCanvas(self.fig_dict_wadatijack[eventID][key], - parent=self) + if not key == 'plot_style': + self.canvas_dict_wadatijack[eventID][key] = PylotCanvas(self.fig_dict_wadatijack[eventID][key], + parent=self) def tune_autopicker(self): ''' diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index a4607d63..3a925666 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -322,9 +322,11 @@ def autopickstation(wfstream, pickparam, verbose=False, key = 'aicFig' if fig_dict: fig = fig_dict[key] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None - aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, aictsmoothP, fig=fig) + linecolor = 'k' + aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, aictsmoothP, fig=fig, linecolor=linecolor) # add pstart and pstop to aic plot if fig: for ax in fig.axes: @@ -347,12 +349,14 @@ def autopickstation(wfstream, pickparam, verbose=False, key = 'slength' if fig_dict: fig = fig_dict[key] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, minsiglength / 2, nfacsl, minpercent, iplot, - fig) + fig, linecolor) else: # filter and taper horizontal traces trH1_filt = edat.copy() @@ -369,12 +373,14 @@ def autopickstation(wfstream, pickparam, verbose=False, zne += trH2_filt if fig_dict: fig = fig_dict['slength'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' Pflag = checksignallength(zne, aicpick.getpick(), tsnrz, minsiglength, nfacsl, minpercent, iplot, - fig) + fig, linecolor) if Pflag == 1: # check for spuriously picked S onset @@ -387,10 +393,12 @@ def autopickstation(wfstream, pickparam, verbose=False, if iplot > 1: if fig_dict: fig = fig_dict['checkZ4s'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' Pflag = checkZ4S(zne, aicpick.getpick(), zfac, - tsnrz[2], iplot, fig) + tsnrz[2], iplot, fig, linecolor) if Pflag == 0: Pmarker = 'SinsteadP' Pweight = 9 @@ -442,10 +450,12 @@ def autopickstation(wfstream, pickparam, verbose=False, algoP=algoP) if fig_dict: fig = fig_dict['refPpick'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, - aicpick.getpick(), fig) + aicpick.getpick(), fig, linecolor) mpickP = refPpick.getpick() ############################################################# if mpickP is not None: @@ -454,10 +464,13 @@ def autopickstation(wfstream, pickparam, verbose=False, if iplot: if fig_dict: fig = fig_dict['el_Ppick'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, - mpickP, iplot, fig=fig) + mpickP, iplot, fig=fig, + linecolor=linecolor) else: epickP, lpickP, Perror = earllatepicker(z_copy, nfacP, tsnrz, mpickP, iplot) @@ -487,9 +500,10 @@ def autopickstation(wfstream, pickparam, verbose=False, if iplot: if fig_dict: fig = fig_dict['fm_picker'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None - FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot, fig) + FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot, fig, linecolor) else: FM = fmpicker(zdat, z_copy, fmpickwin, mpickP, iplot) else: @@ -624,10 +638,12 @@ def autopickstation(wfstream, pickparam, verbose=False, # of class AutoPicking if fig_dict: fig = fig_dict['aicARHfig'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, - aictsmoothS, fig=fig) + aictsmoothS, fig=fig, linecolor=linecolor) ############################################################### # go on with processing if AIC onset passes quality control slope = aicarhpick.getSlope() @@ -686,10 +702,12 @@ def autopickstation(wfstream, pickparam, verbose=False, # get refined onset time from CF2 using class Picker if fig_dict: fig = fig_dict['refSpick'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot, ausS, - tsmoothS, aicarhpick.getpick(), fig) + tsmoothS, aicarhpick.getpick(), fig, linecolor) mpickS = refSpick.getpick() ############################################################# if mpickS is not None: @@ -699,12 +717,15 @@ def autopickstation(wfstream, pickparam, verbose=False, if iplot: if fig_dict: fig = fig_dict['el_S1pick'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = 'k' epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, tsnrh, mpickS, iplot, - fig=fig) + fig=fig, + linecolor=linecolor) else: epickS1, lpickS1, Serror1 = earllatepicker(h_copy, nfacS, tsnrh, @@ -714,12 +735,15 @@ def autopickstation(wfstream, pickparam, verbose=False, if iplot: if fig_dict: fig = fig_dict['el_S2pick'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] else: fig = None + linecolor = '' epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, tsnrh, mpickS, iplot, - fig=fig) + fig=fig, + linecolor=linecolor) else: epickS2, lpickS2, Serror2 = earllatepicker(h_copy, nfacS, tsnrh, @@ -828,8 +852,10 @@ def autopickstation(wfstream, pickparam, verbose=False, if fig_dict == None or fig_dict == 'None': fig = plt.figure() plt_flag = 1 + linecolor = 'k' else: fig = fig_dict['mainFig'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] ax1 = fig.add_subplot(311) tdata = np.arange(0, zdat[0].stats.npts / tr_filt.stats.sampling_rate, tr_filt.stats.delta) @@ -837,7 +863,7 @@ def autopickstation(wfstream, pickparam, verbose=False, wfldiff = len(tr_filt.data) - len(tdata) if wfldiff < 0: tdata = tdata[0:len(tdata) - abs(wfldiff)] - ax1.plot(tdata, tr_filt.data / max(tr_filt.data), 'k', label='Data') + ax1.plot(tdata, tr_filt.data / max(tr_filt.data), color=linecolor, linewidth=0.7, label='Data') if Pweight < 4: ax1.plot(cf1.getTimeArray(), cf1.getCF() / max(cf1.getCF()), 'b', label='CF1') @@ -896,7 +922,7 @@ def autopickstation(wfstream, pickparam, verbose=False, wfldiff = len(trH1_filt.data) - len(th1data) if wfldiff < 0: th1data = th1data[0:len(th1data) - abs(wfldiff)] - ax2.plot(th1data, trH1_filt.data / max(trH1_filt.data), 'k', label='Data') + ax2.plot(th1data, trH1_filt.data / max(trH1_filt.data), color=linecolor, linewidth=0.7, label='Data') if Pweight < 4: ax2.plot(arhcf1.getTimeArray(), arhcf1.getCF() / max(arhcf1.getCF()), 'b', label='CF1') @@ -945,7 +971,7 @@ def autopickstation(wfstream, pickparam, verbose=False, wfldiff = len(trH2_filt.data) - len(th2data) if wfldiff < 0: th2data = th2data[0:len(th2data) - abs(wfldiff)] - ax3.plot(th2data, trH2_filt.data / max(trH2_filt.data), 'k', label='Data') + ax3.plot(th2data, trH2_filt.data / max(trH2_filt.data), color=linecolor, linewidth=0.7, label='Data') if Pweight < 4: p22, = ax3.plot(arhcf1.getTimeArray(), arhcf1.getCF() / max(arhcf1.getCF()), 'b', label='CF1') diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 6be3d7d2..5d44d9f0 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -35,7 +35,7 @@ class AutoPicker(object): warnings.simplefilter('ignore') - def __init__(self, cf, TSNR, PickWindow, iplot=0, aus=None, Tsmooth=None, Pick1=None, fig=None): + def __init__(self, cf, TSNR, PickWindow, iplot=0, aus=None, Tsmooth=None, Pick1=None, fig=None, linecolor='k'): ''' :param: cf, characteristic function, on which the picking algorithm is applied :type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object @@ -62,7 +62,8 @@ class AutoPicker(object): ''' assert isinstance(cf, CharacteristicFunction), "%s is not a CharacteristicFunction object" % str(cf) - + self._linecolor = linecolor + self._pickcolor_p = 'b' self.cf = cf.getCF() self.Tcf = cf.getTimeArray() self.Data = cf.getXCF() @@ -264,13 +265,13 @@ class AICPicker(AutoPicker): print("Choose longer slope determination window!") if self.iplot > 1: if self.fig == None or self.fig == 'None': - fig = plt.figure() # self.iplot) ### WHY? MP MP + fig = plt.figure() plt_flag = 1 else: fig = self.fig ax = fig.add_subplot(111) x = self.Data[0].data - ax.plot(self.Tcf, x / max(x), 'k', label='(HOS-/AR-) Data') + ax.plot(self.Tcf, x / max(x), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data') ax.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF') ax.legend(loc=1) ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) @@ -307,7 +308,7 @@ class AICPicker(AutoPicker): x = self.Data[0].data if len(self.Tcf) > len(self.Data[0].data): # why? LK self.Tcf = self.Tcf[0:len(self.Tcf)-1] - ax1.plot(self.Tcf, x / max(x), 'k', label='(HOS-/AR-) Data') + ax1.plot(self.Tcf, x / max(x), color=self._linecolor, linewidth=0.7, label='(HOS-/AR-) Data') ax1.plot(self.Tcf, aicsmooth / max(aicsmooth), 'r', label='Smoothed AIC-CF') if self.Pick is not None: ax1.plot([self.Pick, self.Pick], [-0.1, 0.5], 'b', linewidth=2, label='AIC-Pick') @@ -317,7 +318,7 @@ class AICPicker(AutoPicker): if self.Pick is not None: ax2 = fig.add_subplot(2, 1, 2, sharex=ax1) - ax2.plot(self.Tcf, x, 'k', label='Data') + ax2.plot(self.Tcf, x, color=self._linecolor, linewidth=0.7, label='Data') ax1.axvspan(self.Tcf[inoise[0]], self.Tcf[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') ax1.axvspan(self.Tcf[isignal[0]], self.Tcf[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') @@ -473,10 +474,10 @@ class PragPicker(AutoPicker): else: fig = self.fig ax = fig.add_subplot(111) - ax.plot(Tcfpick, cfipick, 'k', label='CF') + ax.plot(Tcfpick, cfipick, color=self._linecolor, linewidth=0.7, label='CF') ax.plot(Tcfpick, cfsmoothipick, 'r', label='Smoothed CF') if pickflag > 0: - ax.plot([self.Pick, self.Pick], [min(cfipick), max(cfipick)], 'b', linewidth=2, label='Pick') + ax.plot([self.Pick, self.Pick], [min(cfipick), max(cfipick)], self._pickcolor_p, linewidth=2, label='Pick') ax.set_xlabel('Time [s] since %s' % self.Data[0].stats.starttime) ax.set_yticks([]) ax.set_title(self.Data[0].stats.station) diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index 142beda8..579f3239 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -15,7 +15,7 @@ import numpy as np from obspy.core import Stream, UTCDateTime -def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None): +def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None, linecolor='k'): ''' Function to derive earliest and latest possible pick after Diehl & Kissling (2009) as reasonable uncertainties. Latest possible pick is based on noise level, @@ -131,16 +131,16 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None): fig = plt.figure() # iplot) plt_flag = 1 ax = fig.add_subplot(111) - ax.plot(t, x, 'k', label='Data') + ax.plot(t, x, color=linecolor, linewidth=0.7, label='Data') ax.axvspan(t[inoise[0]], t[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') ax.axvspan(t[isignal[0]], t[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') - ax.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], '--k', label='Noise Level') + ax.plot([t[0], t[int(len(t)) - 1]], [nlevel, nlevel], color=linecolor, linewidth=0.7, linestyle='dashed', label='Noise Level') ax.plot(t[pis[zc]], np.zeros(len(zc)), '*g', markersize=14, label='Zero Crossings') - ax.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], '--k') + ax.plot([t[0], t[int(len(t)) - 1]], [-nlevel, -nlevel], color=linecolor, linewidth=0.7, linestyle='dashed') ax.plot([Pick1, Pick1], [max(x), -max(x)], 'b', linewidth=2, label='mpp') - ax.plot([LPick, LPick], [max(x) / 2, -max(x) / 2], '--k', label='lpp') - ax.plot([EPick, EPick], [max(x) / 2, -max(x) / 2], '--k', label='epp') + ax.plot([LPick, LPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed', label='lpp') + ax.plot([EPick, EPick], [max(x) / 2, -max(x) / 2], color=linecolor, linewidth=0.7, linestyle='dashed', label='epp') ax.plot([Pick1 + PickError, Pick1 + PickError], [max(x) / 2, -max(x) / 2], 'r--', label='spe') ax.plot([Pick1 - PickError, Pick1 - PickError], @@ -160,7 +160,7 @@ def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None): return EPick, LPick, PickError -def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None): +def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None, linecolor='k'): ''' Function to derive first motion (polarity) of given phase onset Pick. Calculation is based on zero crossings determined within time window pickwin @@ -324,7 +324,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None): fig = plt.figure() # iplot) plt_flag = 1 ax1 = fig.add_subplot(211) - ax1.plot(t, xraw, 'k') + ax1.plot(t, xraw, color=linecolor, linewidth=0.7) ax1.plot([Pick, Pick], [max(xraw), -max(xraw)], 'b', linewidth=2, label='Pick') if P1 is not None: ax1.plot(t[islope1], xraw[islope1], label='Slope Window') @@ -338,7 +338,7 @@ def fmpicker(Xraw, Xfilt, pickwin, Pick, iplot=0, fig=None): ax2 = fig.add_subplot(2, 1, 2, sharex=ax1) ax2.set_title('First-Motion Determination, Filtered Data') - ax2.plot(t, xfilt, 'k') + ax2.plot(t, xfilt, color=linecolor, linewidth=0.7) ax2.plot([Pick, Pick], [max(xfilt), -max(xfilt)], 'b', linewidth=2) if P2 is not None: @@ -668,15 +668,18 @@ def wadaticheck(pickdic, dttolerance, iplot=0, fig_dict=None): if iplot > 0: if fig_dict: fig = fig_dict['wadati'] + linecolor = fig_dict['plot_style']['linecolor']['rgba_mpl'] plt_flag = 0 else: fig = plt.figure() + linecolor = 'k' plt_flag = 1 ax = fig.add_subplot(111) ax.plot(Ppicks, SPtimes, 'ro', label='Skipped S-Picks') if wfitflag == 0: - ax.plot(Ppicks, wdfit, 'k', label='Wadati 1') - ax.plot(checkedPpicks, checkedSPtimes, 'ko', label='Reliable S-Picks') + ax.plot(Ppicks, wdfit, color=linecolor, linewidth=0.7, label='Wadati 1') + ax.plot(checkedPpicks, checkedSPtimes, color=linecolor, + linewidth=0, marker='o', label='Reliable S-Picks') ax.plot(checkedPpicks, wdfit2, 'g', label='Wadati 2') ax.set_title('Wadati-Diagram, %d S-P Times, Vp/Vs(raw)=%5.2f,' \ 'Vp/Vs(checked)=%5.2f' % (len(SPtimes), vpvsr, cvpvsr)) @@ -699,7 +702,7 @@ def RMS(X): return np.sqrt(np.sum(np.power(X, 2)) / len(X)) -def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fig=None): +def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fig=None, linecolor='k'): ''' Function to detect spuriously picked noise peaks. Uses RMS trace of all 3 components (if available) to determine, @@ -785,7 +788,7 @@ def checksignallength(X, pick, TSNR, minsiglength, nfac, minpercent, iplot=0, fi fig = plt.figure() # iplot) plt_flag = 1 ax = fig.add_subplot(111) - ax.plot(t, rms, 'k', label='RMS Data') + ax.plot(t, rms, color=linecolor, linewidth=0.7, label='RMS Data') ax.axvspan(t[inoise[0]], t[inoise[-1]], color='y', alpha=0.2, lw=0, label='Noise Window') ax.axvspan(t[isignal[0]], t[isignal[-1]], color='b', alpha=0.2, lw=0, label='Signal Window') ax.plot([t[isignal[0]], t[isignal[len(isignal) - 1]]], @@ -975,7 +978,7 @@ def jackknife(X, phi, h): return PHI_jack, PHI_pseudo, PHI_sub -def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None): +def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None, linecolor='k'): ''' Function to compare energy content of vertical trace with energy content of horizontal traces to detect spuriously @@ -1103,7 +1106,7 @@ def checkZ4S(X, pick, zfac, checkwin, iplot, fig=None): plt_flag = 1 ax = fig.add_subplot(3, 1, i + 1, sharex=ax1) ax.plot(t, abs(trace.data), color='b', label='abs') - ax.plot(t, trace.data, color='k') + ax.plot(t, trace.data, color=linecolor, linewidth=0.7) name = str(trace.stats.channel) + ': {}'.format(rms) ax.plot([pick, pick + checkwin], [rms, rms], 'r', label='RMS {}'.format(name)) ax.plot([pick, pick], ax.get_ylim(), 'm', label='Pick') diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 534141ac..dd9cd04c 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2766,7 +2766,8 @@ class TuneAutopicker(QWidget): 'locflag': 0, 'savexml': False} for key in self.fig_dict.keys(): - self.fig_dict[key].clear() + if not key == 'plot_style': + self.fig_dict[key].clear() self.ap_thread = Thread(self, autoPyLoT, arg=args, progressText='Picking trace...', pb_widget=self.pb_widget, From f1fdd3b17bb71feb3b99d0d4ae8730e2c3e50cb6 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 17:19:18 +0200 Subject: [PATCH 13/22] [update] bright stylesheet --- pylot/styles/bright.qss | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index 25fdb5c2..ad25a3da 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -149,15 +149,20 @@ padding:5px; } QTabBar::tab:selected{ -background-color:rgba(255, 255, 255, 255); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(210, 210, 210, 255), stop:1 rgba(230, 230, 230, 255)); color: rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(255, 255, 255, 255); +border-color:rgba(230, 230, 230, 255); border-bottom-color: transparent; border-width:1px; padding:5px; } +QTabBar::tab:disabled{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); +color: rgba(100, 100, 120, 255); +} + QTabWidget{ background-color:transparent; } @@ -165,7 +170,7 @@ background-color:transparent; QTabWidget::pane{ background-color:rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(255, 255, 255, 255); +border-color:rgba(230, 230, 230, 255); border-width:1px; } @@ -174,7 +179,7 @@ background-color:rgba(255, 255, 255, 255); } QTabWidget > QWidget{ -background-color: rgba(255, 255, 255, 255); +background-color: rgba(230, 230, 230, 255); color: rgba(0, 0, 0, 255); } From 78ba5484c63dd67a5fe7ca2fa9660b7e14ede248 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 17:19:34 +0200 Subject: [PATCH 14/22] [bugfix] old usage of _parent --- QtPyLoT.py | 4 ++-- pylot/core/util/widgets.py | 2 +- pylot/styles/dark.qss | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 27b9689e..eea72ecb 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -554,8 +554,8 @@ class MainWindow(QMainWindow): self.pg = pg # init style - self.set_style('dark') - #self.set_style('bright') + #self.set_style('dark') + self.set_style('bright') #self.set_style('default') # add event combo box and ref/test buttons diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index dd9cd04c..f1ed0428 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -729,7 +729,7 @@ class PylotCanvas(FigureCanvas): def saveFigure(self): if self.figure: fd = QtGui.QFileDialog() - fname, filter = fd.getSaveFileName(self._parent, filter='Images (*.png)') + fname, filter = fd.getSaveFileName(self.parent(), filter='Images (*.png)') if not fname: return if not fname.endswith('.png'): diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index 3caef6ba..2d830ff7 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -158,6 +158,11 @@ border-width:1px; padding:5px; } +QTabBar::tab:disabled{ +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); +color: rgba(100, 100, 120, 255); +} + QTabWidget{ background-color:transparent; } From e5b0210c27e6085b890e485ab2bf4b0631404438 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 8 Sep 2017 17:25:29 +0200 Subject: [PATCH 15/22] [update] bright stylesheet --- pylot/styles/bright.qss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index ad25a3da..ee1bb29a 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -139,7 +139,7 @@ background-color:transparent; } QTabBar::tab{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(210, 210, 210, 255)); color: rgba(0, 0, 0, 255); border-style:solid; border-color:rgba(230, 230, 230 255); @@ -149,7 +149,7 @@ padding:5px; } QTabBar::tab:selected{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(210, 210, 210, 255), stop:1 rgba(230, 230, 230, 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); color: rgba(0, 0, 0, 255); border-style:solid; border-color:rgba(230, 230, 230, 255); @@ -159,7 +159,7 @@ padding:5px; } QTabBar::tab:disabled{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(210, 210, 210, 255)); color: rgba(100, 100, 120, 255); } From 6e43e671726b5fb9ab2c38e4aabe0e6a1e4b0b05 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 10:24:22 +0200 Subject: [PATCH 16/22] [minor] stylesheet modifications --- QtPyLoT.py | 4 ++-- pylot/styles/bright.qss | 18 ++++++++++++++---- pylot/styles/dark.qss | 10 ++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index eea72ecb..27b9689e 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -554,8 +554,8 @@ class MainWindow(QMainWindow): self.pg = pg # init style - #self.set_style('dark') - self.set_style('bright') + self.set_style('dark') + #self.set_style('bright') #self.set_style('default') # add event combo box and ref/test buttons diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index ee1bb29a..5e2a0e3f 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -117,13 +117,14 @@ color:rgba(0, 0, 0, 255); } QPushButton{ -background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(255, 255, 255, 255)); +background-color:qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:0.5, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(245, 245, 245, 255)); color:rgba(0, 0, 0, 255); border-style: outset; -border-width: 2px; -border-color: rgba(230, 230, 230, 255); +border-width: 1px; +border-color: rgba(100, 100, 120, 255); min-width: 6em; padding: 5px; +border-radius: 2px; } QPushButton:pressed{ @@ -142,7 +143,7 @@ QTabBar::tab{ background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(230, 230, 230, 255), stop:1 rgba(210, 210, 210, 255)); color: rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(230, 230, 230 255); +border-color:rgba(210, 210, 210 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -213,7 +214,16 @@ background-color: rgba(255, 255, 255, 255); QLineEdit{ background-color: rgba(255, 255, 255, 255); +border: 1px inset; border-radius:0; +border-color: rgba(100, 100, 120, 255); +} + +QLineEdit:disabled{ +background-color: rgba(255, 255, 255, 255); +border: 1px inset; +border-radius:0; +border-color: rgba(200, 200, 200, 255); } QCheckBox{ diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index 2d830ff7..4d54cb7e 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -124,6 +124,7 @@ border-width: 2px; border-color: rgba(50, 50, 60, 255); min-width: 6em; padding: 5px; +border-radius: 2px; } QPushButton:pressed{ @@ -218,7 +219,16 @@ border:none; QLineEdit{ background-color: rgba(80, 80, 90, 255); +border: 1px inset; border-radius:0; +border-color: rgba(100, 100, 120, 255); +} + +QLineEdit:disabled{ +background-color: rgba(80, 80, 90, 255); +border: 1px inset; +border-radius:0; +border-color: rgba(200, 200, 200, 255); } QListWidget{ From f0e4ba5ab2200eadac64bcaf6ce74f981e35670d Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 13:27:32 +0200 Subject: [PATCH 17/22] [add] style settings option --- QtPyLoT.py | 17 ++++++++++++----- pylot/core/util/widgets.py | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 2d6e9f7e..005f182a 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -554,9 +554,9 @@ class MainWindow(QMainWindow): self.pg = pg # init style - self.set_style('dark') - #self.set_style('bright') - #self.set_style('default') + settings = QSettings() + style = settings.value('style') + self.set_style(style) # add event combo box and ref/test buttons self.eventBox = self.createEventBox() @@ -698,11 +698,13 @@ class MainWindow(QMainWindow): stylecolors['stylesheet'] = stylesheet - def set_style(self, stylename='default'): + def set_style(self, stylename=None): + if not stylename: + stylename = 'default' if not stylename in self._styles: qmb = QMessageBox.warning(self, 'Could not find style', 'Could not find style with name {}. Using default.'.format(stylename)) - self.set_style() + self.set_style('default') return style = self._styles[stylename] @@ -740,6 +742,10 @@ class MainWindow(QMainWindow): pg.setConfigOption('background', bg_color) pg.setConfigOption('foreground', line_color) + settings = QSettings() + settings.setValue('style', stylename) + settings.sync() + @property def metadata(self): return self._metadata @@ -3182,6 +3188,7 @@ def create_window(): # window.show() return app, app_created + def main(args=None): project_filename = None #args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index f1ed0428..5b273182 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -3422,6 +3422,7 @@ class SubmitLocal(QWidget): class PropertiesDlg(QDialog): def __init__(self, parent=None, infile=None, inputs=None): super(PropertiesDlg, self).__init__(parent) + self._pylot_mainwindow = self.parent() self.infile = infile self.inputs = inputs @@ -3722,14 +3723,26 @@ class PhasesTab(PropTab): class GraphicsTab(PropTab): def __init__(self, parent=None): super(GraphicsTab, self).__init__(parent) + self.pylot_mainwindow = parent._pylot_mainwindow self.init_layout() self.add_pg_cb() self.add_nth_sample() + self.add_style_settings() self.setLayout(self.main_layout) def init_layout(self): self.main_layout = QGridLayout() + def add_style_settings(self): + styles = self.pylot_mainwindow._styles + label = QtGui.QLabel('Application style (might require Application restart):') + self.style_cb = QComboBox() + for stylename, style in styles.items(): + self.style_cb.addItem(stylename, style) + self.main_layout.addWidget(label, 2, 0) + self.main_layout.addWidget(self.style_cb, 2, 1) + self.style_cb.activated.connect(self.set_current_style) + def add_nth_sample(self): settings = QSettings() nth_sample = settings.value("nth_sample") @@ -3763,6 +3776,10 @@ class GraphicsTab(PropTab): self.main_layout.addWidget(label, 0, 0) self.main_layout.addWidget(self.checkbox_pg, 0, 1) + def set_current_style(self): + selected_style = self.style_cb.currentText() + self.pylot_mainwindow.set_style(selected_style) + def getValues(self): values = {'nth_sample': self.spinbox_nth_sample.value(), 'pyqtgraphic': self.checkbox_pg.isChecked()} From bed5c8ffcf4348324e951cbb15d139ebeee2ba5f Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 14:23:42 +0200 Subject: [PATCH 18/22] [minor] stylesheet changes --- pylot/styles/bright.qss | 35 ++++++++++++++++------------------- pylot/styles/dark.qss | 34 +++++++++++++++------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/pylot/styles/bright.qss b/pylot/styles/bright.qss index 5e2a0e3f..3b8e4c4f 100644 --- a/pylot/styles/bright.qss +++ b/pylot/styles/bright.qss @@ -40,6 +40,8 @@ QMenuBar::item{ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:2, stop:0 rgba(240, 240, 240, 255), stop:1 rgba(230, 230, 230, 255)); color: rgba(0, 0, 0, 255); padding:3px; +padding-left:5px; +padding-right:5px; } QMenu{ @@ -123,7 +125,9 @@ border-style: outset; border-width: 1px; border-color: rgba(100, 100, 120, 255); min-width: 6em; -padding: 5px; +padding: 4px; +padding-left:5px; +padding-right:5px; border-radius: 2px; } @@ -150,10 +154,10 @@ padding:5px; } QTabBar::tab:selected{ -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(245, 245, 245, 255)); color: rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(230, 230, 230, 255); +border-color:rgba(245, 245, 245, 255); border-bottom-color: transparent; border-width:1px; padding:5px; @@ -171,7 +175,7 @@ background-color:transparent; QTabWidget::pane{ background-color:rgba(0, 0, 0, 255); border-style:solid; -border-color:rgba(230, 230, 230, 255); +border-color:rgba(245, 245, 245, 255); border-width:1px; } @@ -180,7 +184,7 @@ background-color:rgba(255, 255, 255, 255); } QTabWidget > QWidget{ -background-color: rgba(230, 230, 230, 255); +background-color: rgba(245, 245, 245, 255); color: rgba(0, 0, 0, 255); } @@ -212,6 +216,11 @@ color: rgba(0, 0, 0, 255); background-color: rgba(255, 255, 255, 255); } +QCheckBox{ +background-color:transparent; +border:none; +} + QLineEdit{ background-color: rgba(255, 255, 255, 255); border: 1px inset; @@ -226,26 +235,14 @@ border-radius:0; border-color: rgba(200, 200, 200, 255); } -QCheckBox{ -background-color:transparent; -border:none; -} - QListWidget{ background-color:rgba(255, 255, 255, 255) } QProgressBar{ -border-radius:0; -text-align:center; -color:rgba(0, 0, 0, 255); -background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(230, 230, 230, 255)); -border: 2px solid; -border-color:rgba(0, 55, 140, 150); -border-radius:5px; +background-color:rgba(230, 230, 230, 255); } QProgressBar::chunk{ -background-color:rgba(60, 60, 70, 150); -width:10px; +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 70, 180, 150), stop:1 transparent); } diff --git a/pylot/styles/dark.qss b/pylot/styles/dark.qss index 4d54cb7e..31492dbb 100644 --- a/pylot/styles/dark.qss +++ b/pylot/styles/dark.qss @@ -16,15 +16,15 @@ border-style:inset; } QComboBox{ -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); color: rgba(255, 255, 255, 255); -min-height: 1.8em; +min-height: 1.5em; selection-background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 144, 180, 255), stop:1 rgba(0, 150, 190, 255)); } QComboBox *{ -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); color: rgba(255, 255, 255, 255); selection-background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 144, 180, 255), stop:1 rgba(0, 150, 190, 255)); @@ -40,8 +40,9 @@ QMenuBar::item{ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); padding:3px; +padding-left:5px; +padding-right:5px; } - QMenu{ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70, 70, 80, 255), stop:1 rgba(60, 60, 70, 255)); color: rgba(255, 255, 255, 255); @@ -123,7 +124,9 @@ border-style: outset; border-width: 2px; border-color: rgba(50, 50, 60, 255); min-width: 6em; -padding: 5px; +padding: 4px; +padding-left:5px; +padding-right:5px; border-radius: 2px; } @@ -199,17 +202,17 @@ background-color: transparent; QTextEdit{ color: rgba(255, 255, 255, 255); -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); } QSpinBox{ color: rgba(255, 255, 255, 255); -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); } QDoubleSpinBox{ color: rgba(255, 255, 255, 255); -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); } QCheckBox{ @@ -218,14 +221,14 @@ border:none; } QLineEdit{ -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); border: 1px inset; border-radius:0; border-color: rgba(100, 100, 120, 255); } QLineEdit:disabled{ -background-color: rgba(80, 80, 90, 255); +background-color: rgba(90, 90, 100, 255); border: 1px inset; border-radius:0; border-color: rgba(200, 200, 200, 255); @@ -236,16 +239,9 @@ background-color:rgba(60, 60, 70, 255) } QProgressBar{ -border-radius:0; -text-align:center; -color:rgba(255, 255, 255, 255); -background-color:rgba(60,60,80,255); -border: 2px solid; -border-color:rgba(0, 150, 190, 255); -border-radius:5px; +background-color:rgba(60, 60, 70, 255); } QProgressBar::chunk{ -background-color:rgba(0, 150, 190, 255); -width:10px; +background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 150, 190, 255), stop:1 transparent); } From a4c697d25065492acc0ff3410bb29db68cc0fe02 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 14:39:46 +0200 Subject: [PATCH 19/22] [minor] solving some parental issues --- pylot/core/util/widgets.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 5b273182..07409807 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2435,10 +2435,9 @@ class TuneAutopicker(QWidget): def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) - self.setParent(parent) self.setWindowTitle('PyLoT - Tune Autopicker') - self.parameter = parent._inputs - self.fig_dict = parent.fig_dict + self.parameter = self.parent()._inputs + self.fig_dict = self.parent().fig_dict self.data = Data() self.init_main_layouts() self.init_eventlist() @@ -2451,7 +2450,7 @@ class TuneAutopicker(QWidget): self.add_log() self.set_stretch() self.resize(1280, 720) - if hasattr(parent, 'metadata'): + if hasattr(self.parent(), 'metadata'): self.metadata = self.parent().metadata else: self.metadata = None From 197164f849954bb1bda40f96983e242573977d9f Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 15:15:33 +0200 Subject: [PATCH 20/22] [issue] trying to solve FigureCanvas already deleted exception WIP --- QtPyLoT.py | 2 +- pylot/core/util/widgets.py | 46 +++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index 4dac3576..e09e37c7 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -3193,7 +3193,7 @@ def create_window(): def main(args=None): project_filename = None - #args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' + args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' pylot_infile = None if args: if args.project_filename: diff --git a/pylot/core/util/widgets.py b/pylot/core/util/widgets.py index 07409807..b3323fd7 100644 --- a/pylot/core/util/widgets.py +++ b/pylot/core/util/widgets.py @@ -2435,6 +2435,7 @@ class TuneAutopicker(QWidget): def __init__(self, parent): QtGui.QWidget.__init__(self, parent, 1) + self._style = parent._style self.setWindowTitle('PyLoT - Tune Autopicker') self.parameter = self.parent()._inputs self.fig_dict = self.parent().fig_dict @@ -2579,28 +2580,30 @@ class TuneAutopicker(QWidget): def gen_pick_dlg(self): if not self.get_current_event(): - self.pickDlg = None + if self.pdlg_widget: + self.pdlg_widget.setParent(None) + self.pdlg_widget = None return station = self.get_current_station() data = self.data.getWFData() metadata = self.parent().metadata event = self.get_current_event() filteroptions = self.parent().filteroptions - pickDlg = PickDlg(self.parent(), data=data.select(station=station), - station=station, parameter=self.parameter, - picks=self.get_current_event_picks(station), - autopicks=self.get_current_event_autopicks(station), - metadata=metadata, event=event, filteroptions=filteroptions, - embedded=True) - pickDlg.update_picks.connect(self.picks_from_pickdlg) - pickDlg.update_picks.connect(self.fill_eventbox) - pickDlg.update_picks.connect(self.fill_stationbox) - pickDlg.update_picks.connect(lambda: self.parent().setDirty(True)) - pickDlg.update_picks.connect(self.parent().enableSaveEventAction) - self.pickDlg = QtGui.QWidget() + self.pickDlg = PickDlg(self, data=data.select(station=station), + station=station, parameter=self.parameter, + picks=self.get_current_event_picks(station), + autopicks=self.get_current_event_autopicks(station), + metadata=metadata, event=event, filteroptions=filteroptions, + embedded=True) + self.pickDlg.update_picks.connect(self.picks_from_pickdlg) + self.pickDlg.update_picks.connect(self.fill_eventbox) + self.pickDlg.update_picks.connect(self.fill_stationbox) + self.pickDlg.update_picks.connect(lambda: self.parent().setDirty(True)) + self.pickDlg.update_picks.connect(self.parent().enableSaveEventAction) + self.pdlg_widget = QtGui.QWidget(self) hl = QtGui.QHBoxLayout() - self.pickDlg.setLayout(hl) - hl.addWidget(pickDlg) + self.pdlg_widget.setLayout(hl) + hl.addWidget(self.pickDlg) def picks_from_pickdlg(self, picks=None): station = self.get_current_station() @@ -2673,10 +2676,10 @@ class TuneAutopicker(QWidget): def fill_tabs(self, event=None, picked=False): self.clear_all() - canvas_dict = self.parent().canvas_dict self.gen_pick_dlg() + canvas_dict = self.parent().canvas_dict self.overview = self.gen_tab_widget('Overview', canvas_dict['mainFig']) - id0 = self.figure_tabs.insertTab(0, self.pickDlg, 'Traces Plot') + id0 = self.figure_tabs.insertTab(0, self.pdlg_widget, 'Traces Plot') id1 = self.figure_tabs.insertTab(1, self.overview, 'Overview') id2 = self.figure_tabs.insertTab(2, self.p_tabs, 'P') id3 = self.figure_tabs.insertTab(3, self.s_tabs, 'S') @@ -2816,10 +2819,11 @@ class TuneAutopicker(QWidget): self.tune_layout.setStretch(1, 1) def clear_all(self): - if hasattr(self, 'pickDlg'): - if self.pickDlg: - self.pickDlg.setParent(None) - del (self.pickDlg) + if hasattr(self, 'pdlg_widget'): + if self.pdlg_widget: + self.pdlg_widget.setParent(None) + # TODO: removing widget by parent deletion raises exception when activating stationbox: + # RuntimeError: Internal C++ object (PylotCanvas) already deleted. if hasattr(self, 'overview'): self.overview.setParent(None) if hasattr(self, 'p_tabs'): From e333ae0ece7aba8416c85c8c436e7728d6a4d26a Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 15:16:42 +0200 Subject: [PATCH 21/22] [revert] accidently added line for local testing --- QtPyLoT.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QtPyLoT.py b/QtPyLoT.py index e09e37c7..4dac3576 100755 --- a/QtPyLoT.py +++ b/QtPyLoT.py @@ -3193,7 +3193,7 @@ def create_window(): def main(args=None): project_filename = None - args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' + #args.project_filename = 'C:/Shared/AlpArray/alparray_data/project_alparray_test.plp' pylot_infile = None if args: if args.project_filename: From 0418acf472921ad62c39810f4f034ca0e03014ed Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 Sep 2017 15:52:01 +0200 Subject: [PATCH 22/22] [minor] embellish autoPyLoT button --- icons/autopylot_button.png | Bin 53292 -> 30660 bytes icons_rc_2.py | 5242 +++++++++++++----------------------- icons_rc_3.py | 5242 +++++++++++++----------------------- 3 files changed, 3828 insertions(+), 6656 deletions(-) diff --git a/icons/autopylot_button.png b/icons/autopylot_button.png index bab282fb14c90bf2cc5d45a69519925276e44f56..5213cbdc518bee51ad2028826aa7afd890fa0a7a 100644 GIT binary patch literal 30660 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 MYZ$0kJ+X`Wf1E#x<^TWy literal 53292 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 aPZEhOwsW6