Exemple #1
0
    def setCurrentValues(self):
        self.settings = Settings()
        self.settings.beginGroup("plot")

        plotStyle = self.settings.value("style", "dark")
        self.plotStyleList.setCurrentText(plotStyle.capitalize())
        # does setCurrentText not emit currentTextChanged signal?
        self._enableDisableDeleteButton(plotStyle)

        self.customStyle.setName(plotStyle)
        self.customStyle.setStyle(self.mainWindow.plot.getStyle(plotStyle))

        customRange = self.settings.value("customRange", False)
        rng = self.settings.value("range", "All")

        self.setCustomRange(customRange)
        if customRange:
            rng = int(rng)
            self.customRangeSpinBox.setValue(rng)
        else:
            items = [
                self.plotRangeCombo.itemText(idx)
                for idx in range(self.plotRangeCombo.count())
            ]
            idx = items.index(rng)
            self.plotRangeCombo.setCurrentIndex(idx)

        self.settings.endGroup()
Exemple #2
0
    def setCurrentValues(self):
        self.settings = Settings()
        self.settings.beginGroup("pb")

        bestMonthCriterion = self.settings.value("bestMonthCriterion",
                                                 "distance").capitalize()
        self.bestMonthCriteria.setCurrentText(bestMonthCriterion)

        numSessions = self.settings.value("numSessions", 5, int)
        self.numSessionsBox.setValue(numSessions)

        for name, widget in self.summaryComboBoxes.items():
            funcName = self.settings.value(f"summary/{name}", None)
            if funcName is None:
                funcName = self.mainWindow.summary.getFunc(name)
            widget.setCurrentText(funcName)

        self.settings.endGroup()
Exemple #3
0
    def __init__(self, style="dark"):

        plotStyleFile = os.path.dirname(Settings().fileName())
        plotStyleFile = os.path.join(plotStyleFile, 'plotStyles.ini')
        self.settings = Settings(plotStyleFile, Settings.NativeFormat)

        self.keys = [
            'speed', 'distance', 'time', 'calories', 'odometer',
            'highlightPoint', 'foreground', 'background'
        ]
        self.symbolKeys = ['speed', 'distance', 'time', 'calories']

        # make defaults
        darkDefault = [
            "#024aeb", "#cf0202", "#19b536", "#ff9100", "#4d4d4d", "#faed00",
            "#969696", "#000000"
        ]
        lightDefault = [
            "#0981cb", "#d80d0d", "#2bb512", "#ff9100", "#9f9f9f", "#deb009",
            "#4d4d4d", "#ffffff"
        ]
        defaults = {
            'dark': dict(zip(self.keys, darkDefault)),
            'light': dict(zip(self.keys, lightDefault))
        }
        defaultSymbols = {key: 'x' for key in self.symbolKeys}

        for styleName, styleDct in defaults.items():
            if styleName not in self.settings.childGroups():
                self.settings.beginGroup(styleName)
                for key, colour in styleDct.items():
                    self.settings.setValue(key, colour)
                for key, symbol in defaultSymbols.items():
                    self.settings.setValue(f"{key}Symbol", symbol)
                self.settings.endGroup()

        self.name = style
Exemple #4
0
class PlotPreferences(QWidget):
    def __init__(self, mainWindow):
        super().__init__()
        self.mainWindow = mainWindow

        plotStyleGroup = GroupWidget("Plot style")
        styles = self.mainWindow.plot.getValidStyles()
        self.customStyle = StyleDesigner(
            styleKeys=self.mainWindow.plot.getStyleKeys(),
            symbolKeys=self.mainWindow.plot.getStyleSymbolKeys(),
            invalidNames=styles)
        self.customStyle.setEnabled(False)
        self.customStyle.saveStyle.connect(self._saveStyle)

        self.plotStyleList = QComboBox()
        styles = [s.capitalize() for s in styles]
        styles += ["Add custom theme..."]
        self.plotStyleList.addItems(styles)
        self.plotStyleList.currentTextChanged.connect(
            self._updateCustomStyleWidget)

        foregroundColour = self.palette().windowText().color()
        icon = makeForegroundIcon("edit", foregroundColour)
        self.editPlotStyleButton = QPushButton(icon, "")
        self.editPlotStyleButton.setCheckable(True)
        self.editPlotStyleButton.setToolTip("Edit theme")
        self.editPlotStyleButton.toggled.connect(self._editStyle)

        icon = makeForegroundIcon("trash", foregroundColour)
        self.deletePlotStyleButton = QPushButton(icon, "")
        self.deletePlotStyleButton.setToolTip("Delete theme")
        self.deletePlotStyleButton.clicked.connect(self._deleteTheme)

        self.plotStyleList.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Preferred)
        self.editPlotStyleButton.setSizePolicy(QSizePolicy.Minimum,
                                               QSizePolicy.Minimum)
        self.deletePlotStyleButton.setSizePolicy(QSizePolicy.Minimum,
                                                 QSizePolicy.Minimum)

        plotStyleBox = QHBoxLayout()
        plotStyleBox.addWidget(self.plotStyleList)
        plotStyleBox.addWidget(self.editPlotStyleButton)
        plotStyleBox.addWidget(self.deletePlotStyleButton)

        plotStyleGroup.addLayout(plotStyleBox)
        plotStyleGroup.addWidget(self.customStyle)

        plotConfigGroup = GroupWidget("Default plot range", layout="vbox")

        self.plotRangeCombo = QComboBox()
        ranges = [
            "1 month", "3 months", "6 months", "1 year", "Current year", "All"
        ]
        self.plotRangeCombo.addItems(ranges)

        self.customRangeCheckBox = QCheckBox("Custom range")
        self.customRangeSpinBox = QSpinBox()
        self.customRangeSpinBox.setSuffix(" months")
        maxMonths = len(mainWindow.data.splitMonths())
        self.customRangeSpinBox.setRange(1, maxMonths)
        self.customRangeCheckBox.clicked.connect(self.setCustomRange)

        plotRangeLayout = QHBoxLayout()
        plotRangeLayout.addWidget(self.plotRangeCombo)

        customRangeLayout = QHBoxLayout()
        customRangeLayout.addWidget(self.customRangeCheckBox)
        customRangeLayout.addWidget(self.customRangeSpinBox)

        plotConfigGroup.addLayout(plotRangeLayout)
        plotConfigGroup.addLayout(customRangeLayout)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(plotStyleGroup)
        mainLayout.addWidget(plotConfigGroup)
        mainLayout.addStretch(1)

        self.setLayout(mainLayout)

        self.setCurrentValues()
        # apply initial state
        self.apply()

    def setCurrentValues(self):
        self.settings = Settings()
        self.settings.beginGroup("plot")

        plotStyle = self.settings.value("style", "dark")
        self.plotStyleList.setCurrentText(plotStyle.capitalize())
        # does setCurrentText not emit currentTextChanged signal?
        self._enableDisableDeleteButton(plotStyle)

        self.customStyle.setName(plotStyle)
        self.customStyle.setStyle(self.mainWindow.plot.getStyle(plotStyle))

        customRange = self.settings.value("customRange", False)
        rng = self.settings.value("range", "All")

        self.setCustomRange(customRange)
        if customRange:
            rng = int(rng)
            self.customRangeSpinBox.setValue(rng)
        else:
            items = [
                self.plotRangeCombo.itemText(idx)
                for idx in range(self.plotRangeCombo.count())
            ]
            idx = items.index(rng)
            self.plotRangeCombo.setCurrentIndex(idx)

        self.settings.endGroup()

    def _saveStyle(self, name, style, setStyle=False):
        self.mainWindow.plot.addCustomStyle(name, style, setStyle=setStyle)
        idx = self.plotStyleList.count() - 1
        self.plotStyleList.insertItem(idx, name.capitalize())
        self.plotStyleList.setCurrentIndex(idx)

    def _editStyle(self, edit):
        self.customStyle.setEditMode(edit)
        self._updateCustomStyleWidget()

    def apply(self):

        styleName = self.plotStyleList.currentText().lower()
        if styleName == "add custom theme...":
            styleName, styleDct = self.customStyle.getStyle()
            self._saveStyle(styleName, styleDct, setStyle=True)
        else:
            self.mainWindow.plot.setStyle(styleName)

        customRange = self.customRangeCheckBox.isChecked()
        if customRange:
            months = self.customRangeSpinBox.value()
        else:
            text = self.plotRangeCombo.currentText()
            if text == "1 year":
                text = "12 months"
            elif text == "Current year":
                text = f"{date.today().month} months"
            months = None if text == 'All' else int(text.strip(' months'))
        self.mainWindow.plot.setXAxisRange(months)

        self.settings.beginGroup("plot")
        self.settings.setValue("style", styleName)

        self.settings.setValue("customRange", customRange)
        if customRange:
            self.settings.setValue("range", self.customRangeSpinBox.value())
        else:
            self.settings.setValue("range", self.plotRangeCombo.currentText())
        self.settings.endGroup()

    @Slot(bool)
    def setCustomRange(self, custom):
        self.customRangeCheckBox.setChecked(custom)
        if custom:
            self.customRangeSpinBox.setEnabled(True)
            self.plotRangeCombo.setEnabled(False)
        else:
            self.customRangeSpinBox.setEnabled(False)
            self.plotRangeCombo.setEnabled(True)

    def _updateCustomStyleWidget(self, name=None):
        if name is None or name == "Add custom theme...":
            self.customStyle.setEnabled(True)
            if name is None:
                name = self.customStyle.name
            else:
                name = f"custom-{self.customStyle.name}"
            self.customStyle.setName(name)
        else:
            name = name.lower()
            style = self.mainWindow.plot.getStyle(name)
            self.customStyle.setStyle(style, name=name)
            self.customStyle.setEnabled(False)
            self._enableDisableDeleteButton(name)

    def _enableDisableDeleteButton(self, plotStyle):
        if plotStyle in self.mainWindow.plot.getDefaultStyles():
            self.deletePlotStyleButton.setEnabled(False)
            self.deletePlotStyleButton.setToolTip(
                "Cannot delete default theme")
        else:
            self.deletePlotStyleButton.setEnabled(True)
            self.deletePlotStyleButton.setToolTip("Delete theme")

    def _deleteTheme(self):
        styleName = self.plotStyleList.currentText()
        items = [
            self.plotStyleList.itemText(idx)
            for idx in range(self.plotStyleList.count())
        ]
        idx = items.index(styleName)
        self.plotStyleList.removeItem(idx)
        self.mainWindow.plot.removeCustomStyle(styleName.lower())
Exemple #5
0
class DataPreferences(QWidget):
    def __init__(self, mainWindow):
        super().__init__()
        self.mainWindow = mainWindow

        bestMonthGroup = GroupWidget("Best month", layout="grid")
        self.bestMonthCriteria = QComboBox()
        self.bestMonthCriteria.addItems(
            ["Time", "Distance", "Avg. speed", "Calories", "Gear"])

        bestMonthLabel = QLabel("Criterion:")
        bestMonthGroup.addWidget(bestMonthLabel, 0, 0)
        bestMonthGroup.addWidget(self.bestMonthCriteria, 0, 1)

        topSessionsGroup = GroupWidget("Top sessions", layout="grid")
        self.numSessionsBox = QSpinBox()
        self.numSessionsBox.setMinimum(1)
        numSessionsLabel = QLabel("Number of top sessions:")

        topSessionsGroup.addWidget(numSessionsLabel, 0, 0)
        topSessionsGroup.addWidget(self.numSessionsBox, 0, 1)

        summaryCriteriaGroup = GroupWidget("Summary criteria", layout="grid")
        names = ["Time", "Distance", "Calories", "Speed", "Gear"]
        self.summaryComboBoxes = {}
        for row, name in enumerate(names):
            summaryCriteriaGroup.addWidget(QLabel(name), row, 0)
            box = FuncComboBox()
            self.summaryComboBoxes[name.lower()] = box
            summaryCriteriaGroup.addWidget(box, row, 1)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(summaryCriteriaGroup)
        mainLayout.addWidget(bestMonthGroup)
        mainLayout.addWidget(topSessionsGroup)
        mainLayout.addStretch(1)

        self.setLayout(mainLayout)
        self.setCurrentValues()

        # apply initial state
        self.apply()

    def setCurrentValues(self):
        self.settings = Settings()
        self.settings.beginGroup("pb")

        bestMonthCriterion = self.settings.value("bestMonthCriterion",
                                                 "distance").capitalize()
        self.bestMonthCriteria.setCurrentText(bestMonthCriterion)

        numSessions = self.settings.value("numSessions", 5, int)
        self.numSessionsBox.setValue(numSessions)

        for name, widget in self.summaryComboBoxes.items():
            funcName = self.settings.value(f"summary/{name}", None)
            if funcName is None:
                funcName = self.mainWindow.summary.getFunc(name)
            widget.setCurrentText(funcName)

        self.settings.endGroup()

    def apply(self):

        bestMonthCriterion = self.bestMonthCriteria.currentText().lower()
        self.mainWindow.pb.bestMonth.setColumn(bestMonthCriterion)

        numSessions = self.numSessionsBox.value()
        self.mainWindow.pb.bestSessions.setNumRows(numSessions)

        self.settings.beginGroup("pb")
        self.settings.setValue("bestMonthCriterion", bestMonthCriterion)
        self.settings.setValue("numSessions", numSessions)

        # make dict to pass to `setFunc` so it doesn't remake the viewer five times
        summaryFuncs = {}
        for name, widget in self.summaryComboBoxes.items():
            funcName = widget.currentText()
            self.settings.setValue(f"summary/{name}", funcName)
            summaryFuncs[name] = funcName
        self.mainWindow.summary.setFunc(summaryFuncs)

        self.settings.endGroup()
Exemple #6
0
    def __init__(self):
        super().__init__()
        
        self.settings = Settings()
        
        self._saveLabel = QLabel()
        self._summaryLabel = QLabel()
        self.statusBar().addWidget(self._saveLabel)
        self.statusBar().addWidget(self._summaryLabel)
        
        self.file = self.getFile()
        self.sep = ','
        if not os.path.exists(self.file):
            header = ['Date', 'Time', 'Distance (km)', 'Calories', 'Gear']
            s = self.sep.join(header)
            with open(self.file, 'w') as fileobj:
                fileobj.write(s+'\n')
                
        df = pd.read_csv(self.file, sep=self.sep, parse_dates=['Date'])
        self.data = CycleData(df)
        self.save()
        self.dataAnalysis = CycleDataAnalysis(self.data)
        
        self.summary = Summary()

        numTopSessions = self.settings.value("pb/numSessions", 5, int)
        monthCriterion = self.settings.value("pb/bestMonthCriterion", "distance")
        self.pb = PersonalBests(self, numSessions=numTopSessions, 
                                monthCriterion=monthCriterion)
        self.viewer = CycleDataViewer(self)
        self.addData = AddCycleData()
        plotStyle = self.settings.value("plot/style", "dark")
        self.plot = CyclePlotWidget(self, style=plotStyle)
        
        self.pb.bestMonth.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        self.pb.bestSessions.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        self.addData.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        
        self.summary.valueChanged.connect(self.viewer.newData)
        self.summary.valueChanged.connect(self.pb.newData)
        self.addData.newData.connect(self.data.append)
        self.data.dataChanged.connect(self.viewer.newData)
        self.data.dataChanged.connect(self.plot.newData)
        self.data.dataChanged.connect(self.pb.newData)
        self.data.dataChanged.connect(self.save)
        self.plot.pointSelected.connect(self.viewer.highlightItem)
        self.viewer.itemSelected.connect(self.plot.setCurrentPointFromDate)
        self.viewer.selectedSummary.connect(self._summaryLabel.setText)
        self.pb.itemSelected.connect(self.plot.setCurrentPointFromDate)
        self.pb.numSessionsChanged.connect(self.setPbSessionsDockLabel)
        self.pb.monthCriterionChanged.connect(self.setPbMonthDockLabel)
        
        self.fileChangedTimer = QTimer()
        self.fileChangedTimer.setInterval(100)
        self.fileChangedTimer.setSingleShot(True)
        self.fileChangedTimer.timeout.connect(self.csvFileChanged)
        self.fileWatcher = QFileSystemWatcher([self.file])
        self.fileWatcher.fileChanged.connect(self.startTimer)
        
        
        dockWidgets = [(self.pb.bestMonth, Qt.LeftDockWidgetArea, 
                        f"Best month ({monthCriterion})", "PB month"),
                       (self.pb.bestSessions, Qt.LeftDockWidgetArea, 
                        f"Top {intToStr(numTopSessions)} sessions", "PB sessions"),
                       (self.viewer, Qt.LeftDockWidgetArea, "Monthly data"),
                       (self.addData, Qt.LeftDockWidgetArea, "Add data")]
        
        for args in dockWidgets:
            self.createDockWidget(*args)
        self.setCentralWidget(self.plot)
        
        state = self.settings.value("window/state", None)
        if state is not None:
            self.restoreState(state)
            
        geometry = self.settings.value("window/geometry", None)    
        if geometry is not None:
            self.restoreGeometry(geometry)
        
        self.prefDialog = PreferencesDialog(self)
        
        self.createActions()
        self.createMenus()
        
        fileDir = os.path.split(__file__)[0]
        path = os.path.join(fileDir, "..", "images/icon.png")
        icon = QIcon(path)
        self.setWindowIcon(icon)
Exemple #7
0
class CycleTracks(QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.settings = Settings()
        
        self._saveLabel = QLabel()
        self._summaryLabel = QLabel()
        self.statusBar().addWidget(self._saveLabel)
        self.statusBar().addWidget(self._summaryLabel)
        
        self.file = self.getFile()
        self.sep = ','
        if not os.path.exists(self.file):
            header = ['Date', 'Time', 'Distance (km)', 'Calories', 'Gear']
            s = self.sep.join(header)
            with open(self.file, 'w') as fileobj:
                fileobj.write(s+'\n')
                
        df = pd.read_csv(self.file, sep=self.sep, parse_dates=['Date'])
        self.data = CycleData(df)
        self.save()
        self.dataAnalysis = CycleDataAnalysis(self.data)
        
        self.summary = Summary()

        numTopSessions = self.settings.value("pb/numSessions", 5, int)
        monthCriterion = self.settings.value("pb/bestMonthCriterion", "distance")
        self.pb = PersonalBests(self, numSessions=numTopSessions, 
                                monthCriterion=monthCriterion)
        self.viewer = CycleDataViewer(self)
        self.addData = AddCycleData()
        plotStyle = self.settings.value("plot/style", "dark")
        self.plot = CyclePlotWidget(self, style=plotStyle)
        
        self.pb.bestMonth.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        self.pb.bestSessions.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        self.addData.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        
        self.summary.valueChanged.connect(self.viewer.newData)
        self.summary.valueChanged.connect(self.pb.newData)
        self.addData.newData.connect(self.data.append)
        self.data.dataChanged.connect(self.viewer.newData)
        self.data.dataChanged.connect(self.plot.newData)
        self.data.dataChanged.connect(self.pb.newData)
        self.data.dataChanged.connect(self.save)
        self.plot.pointSelected.connect(self.viewer.highlightItem)
        self.viewer.itemSelected.connect(self.plot.setCurrentPointFromDate)
        self.viewer.selectedSummary.connect(self._summaryLabel.setText)
        self.pb.itemSelected.connect(self.plot.setCurrentPointFromDate)
        self.pb.numSessionsChanged.connect(self.setPbSessionsDockLabel)
        self.pb.monthCriterionChanged.connect(self.setPbMonthDockLabel)
        
        self.fileChangedTimer = QTimer()
        self.fileChangedTimer.setInterval(100)
        self.fileChangedTimer.setSingleShot(True)
        self.fileChangedTimer.timeout.connect(self.csvFileChanged)
        self.fileWatcher = QFileSystemWatcher([self.file])
        self.fileWatcher.fileChanged.connect(self.startTimer)
        
        
        dockWidgets = [(self.pb.bestMonth, Qt.LeftDockWidgetArea, 
                        f"Best month ({monthCriterion})", "PB month"),
                       (self.pb.bestSessions, Qt.LeftDockWidgetArea, 
                        f"Top {intToStr(numTopSessions)} sessions", "PB sessions"),
                       (self.viewer, Qt.LeftDockWidgetArea, "Monthly data"),
                       (self.addData, Qt.LeftDockWidgetArea, "Add data")]
        
        for args in dockWidgets:
            self.createDockWidget(*args)
        self.setCentralWidget(self.plot)
        
        state = self.settings.value("window/state", None)
        if state is not None:
            self.restoreState(state)
            
        geometry = self.settings.value("window/geometry", None)    
        if geometry is not None:
            self.restoreGeometry(geometry)
        
        self.prefDialog = PreferencesDialog(self)
        
        self.createActions()
        self.createMenus()
        
        fileDir = os.path.split(__file__)[0]
        path = os.path.join(fileDir, "..", "images/icon.png")
        icon = QIcon(path)
        self.setWindowIcon(icon)
        
    def show(self):
        super().show()
        self.prefDialog.ok()
        
    @staticmethod
    def getFile():
        home = os.path.expanduser('~')
        path = os.path.join(home, '.cycletracks')
        os.makedirs(path, exist_ok=True)
        file = os.path.join(path, 'cycletracks.csv')
        return file
        
    @Slot()
    def save(self):
        self.data.df.to_csv(self.file, sep=self.sep, index=False)
        self.backup()
        saveTime = datetime.now().strftime("%H:%M:%S")
        self._saveLabel.setText(f"Last saved at {saveTime}")
        
    @Slot()
    def backup(self):
        bak = self.file + '.bak'
        self.data.df.to_csv(bak, sep=self.sep, index=False)
        
    @Slot(str)
    def startTimer(self, file):
        self._fileChanged = file
        self.fileChangedTimer.start()
        
    @Slot()
    def csvFileChanged(self):
        df = pd.read_csv(self._fileChanged, sep=self.sep, parse_dates=['Date'])
        try: 
            assert_frame_equal(self.data.df, df, check_exact=False)
        except AssertionError:
            msg = "CycleTracks csv file changed on disk. Do you want to reload?"
            btn = QMessageBox.question(self, "File changed on disk", msg)
            if btn == QMessageBox.Yes:
                self.loadCsvFile()
            
    def loadCsvFile(self):
        df = pd.read_csv(self.file, sep=self.sep, parse_dates=['Date'])
        self.backup()
        self.data.setDataFrame(df)
        
    def createDockWidget(self, widget, area, title, key=None):
        dock = QDockWidget()
        dock.setWidget(widget)
        dock.setWindowTitle(title)
        dock.setObjectName(title)
        self.addDockWidget(area, dock)
        if not hasattr(self, "dockWidgets"):
            self.dockWidgets = {}
        if key is None:
            key = title
        self.dockWidgets[key] = dock
        
    def setPbSessionsDockLabel(self, num):
        label = f"Top {intToStr(num)} sessions"
        self.dockWidgets["PB sessions"].setWindowTitle(label)
    
    def setPbMonthDockLabel(self, monthCriterion):
        label = f"Best month ({monthCriterion})"
        self.dockWidgets["PB month"].setWindowTitle(label)
        
    def closeEvent(self, *args, **kwargs):
        self.backup()
        state = self.saveState()
        geometry = self.saveGeometry()
        self.settings.setValue("window/state", state)
        self.settings.setValue("window/geometry", geometry)
        
    def createActions(self):
        
        self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q",
                               statusTip="Exit the application", 
                               triggered=self.close)
            
        self.saveAct = QAction("&Save", self, shortcut="Ctrl+S", 
                               statusTip="Save data", triggered=self.save)
        
        self.preferencesAct = QAction("&Preferences", self, shortcut="F12",
                                      statusTip="Edit preferences",
                                      triggered=self.prefDialog.show)
        
    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAct)
        
        self.editMenu = self.menuBar().addMenu("&Edit")
        self.editMenu.addAction(self.preferencesAct)
        
        self.viewMenu = self.menuBar().addMenu("&View")
        self.panelMenu = self.viewMenu.addMenu("&Panels")
        for key in sorted(self.dockWidgets):
            dock = self.dockWidgets[key]
            self.panelMenu.addAction(dock.toggleViewAction())
Exemple #8
0
class PlotStyle:

    defaultStyles = ["dark", "light"]

    def __init__(self, style="dark"):

        plotStyleFile = os.path.dirname(Settings().fileName())
        plotStyleFile = os.path.join(plotStyleFile, 'plotStyles.ini')
        self.settings = Settings(plotStyleFile, Settings.NativeFormat)

        self.keys = [
            'speed', 'distance', 'time', 'calories', 'odometer',
            'highlightPoint', 'foreground', 'background'
        ]
        self.symbolKeys = ['speed', 'distance', 'time', 'calories']

        # make defaults
        darkDefault = [
            "#024aeb", "#cf0202", "#19b536", "#ff9100", "#4d4d4d", "#faed00",
            "#969696", "#000000"
        ]
        lightDefault = [
            "#0981cb", "#d80d0d", "#2bb512", "#ff9100", "#9f9f9f", "#deb009",
            "#4d4d4d", "#ffffff"
        ]
        defaults = {
            'dark': dict(zip(self.keys, darkDefault)),
            'light': dict(zip(self.keys, lightDefault))
        }
        defaultSymbols = {key: 'x' for key in self.symbolKeys}

        for styleName, styleDct in defaults.items():
            if styleName not in self.settings.childGroups():
                self.settings.beginGroup(styleName)
                for key, colour in styleDct.items():
                    self.settings.setValue(key, colour)
                for key, symbol in defaultSymbols.items():
                    self.settings.setValue(f"{key}Symbol", symbol)
                self.settings.endGroup()

        self.name = style

    @property
    def name(self):
        return self._styleName

    @name.setter
    def name(self, name):
        if name.lower() not in self.validStyles:
            msg = f"Plot style must be one of {', '.join(self.validStyles)}, not '{name}'."
            raise ValueError(msg)
        self._styleName = name.lower()

    @property
    def validStyles(self):
        return self.settings.childGroups()

    def __getattr__(self, name):
        if name in self.keys:
            return self._getStyle(name)
        else:
            return self.__getattribute__(name)

    def __getitem__(self, name):
        if name in self.keys:
            return self._getStyle(name)
        else:
            raise KeyError(f"PlotStyle has no field '{name}'")

    def _getStyle(self, field):
        if field in ['foreground', 'background']:
            return self.settings.value(f"{self.name}/{field}")

        dct = {'colour': self.settings.value(f"{self.name}/{field}")}
        symbol = self.settings.value(f"{self.name}/{field}Symbol")
        if symbol is not None:
            dct['symbol'] = symbol
        return dct

    def getStyleDict(self, name=None):
        if name is None:
            name = self.name
        style = {}
        for field in self.keys:
            dct = {'colour': self.settings.value(f"{name}/{field}")}
            symbol = self.settings.value(f"{name}/{field}Symbol")
            if symbol is not None:
                dct['symbol'] = symbol
            style[field] = dct
        return style

    def addStyle(self, name, style):
        self.settings.beginGroup(name)
        for key, value in style.items():
            self.settings.setValue(key, value)
        self.settings.endGroup()

    def removeStyle(self, name):
        self.settings.remove(name)