示例#1
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        openmc.capi.init(['-c'])

        self.setWindowTitle('OpenMC Plot Explorer')

        self.restored = False
        self.pixmap = None
        self.zoom = 100

        self.model = PlotModel()
        self.updateRelativeBases()
        self.restoreModelSettings()

        self.cellsModel = DomainTableModel(self.model.activeView.cells)
        self.materialsModel = DomainTableModel(self.model.activeView.materials)

        # Create viewing area
        self.frame = QScrollArea(self)
        self.frame.setAlignment(QtCore.Qt.AlignCenter)
        self.frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setCentralWidget(self.frame)

        # Create plot image
        self.plotIm = PlotImage(self.model, self.frame, self)
        self.frame.setWidget(self.plotIm)

        # Dock
        self.dock = OptionsDock(self.model, FM, self)
        self.dock.setObjectName("OptionsDock")
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)

        # Color Dialog
        self.colorDialog = ColorDialog(self.model, FM, self)
        self.colorDialog.hide()

        # Restore Window Settings
        self.restoreWindowSettings()

        # Create menubar
        self.createMenuBar()

        # Status Bar
        self.coord_label = QLabel()
        self.statusBar().addPermanentWidget(self.coord_label)
        self.coord_label.hide()

        # Load Plot
        self.statusBar().showMessage('Generating Plot...')
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if self.restored:
            self.showCurrentView()
        else:
            # Timer allows GUI to render before plot finishes loading
            QtCore.QTimer.singleShot(0, self.model.generatePlot)
            QtCore.QTimer.singleShot(0, self.showCurrentView)

    # Create and update menus:
    def createMenuBar(self):
        self.mainMenu = self.menuBar()

        # File Menu
        self.saveImageAction = QAction("&Save Image As...", self)
        self.saveImageAction.setShortcut("Ctrl+Shift+S")
        self.saveImageAction.setToolTip('Save plot image')
        self.saveImageAction.setStatusTip('Save plot image')
        self.saveImageAction.triggered.connect(self.saveImage)

        self.saveViewAction = QAction("Save &View Settings...", self)
        self.saveViewAction.setShortcut(QtGui.QKeySequence.Save)
        self.saveViewAction.setStatusTip('Save current view settings')
        self.saveViewAction.triggered.connect(self.saveView)

        self.openAction = QAction("&Open View Settings...", self)
        self.openAction.setShortcut(QtGui.QKeySequence.Open)
        self.openAction.setToolTip('Open saved view settings')
        self.openAction.setStatusTip('Open saved view settings')
        self.openAction.triggered.connect(self.openView)

        self.quitAction = QAction("&Quit", self)
        self.quitAction.setShortcut(QtGui.QKeySequence.Quit)
        self.quitAction.setToolTip('Quit OpenMC Plot Explorer')
        self.quitAction.setStatusTip('Quit OpenMC Plot Explorer')
        self.quitAction.triggered.connect(self.close)

        self.fileMenu = self.mainMenu.addMenu('&File')
        self.fileMenu.addAction(self.saveImageAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.saveViewAction)
        self.fileMenu.addAction(self.openAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAction)

        # Edit Menu
        self.applyAction = QAction("&Apply Changes", self)
        self.applyAction.setShortcut("Shift+Return")
        self.applyAction.setToolTip('Generate new view with changes applied')
        self.applyAction.setStatusTip('Generate new view with changes applied')
        self.applyAction.triggered.connect(self.applyChanges)

        self.undoAction = QAction('&Undo', self)
        self.undoAction.setShortcut(QtGui.QKeySequence.Undo)
        self.undoAction.setToolTip('Undo')
        self.undoAction.setStatusTip('Undo last plot view change')
        self.undoAction.setDisabled(True)
        self.undoAction.triggered.connect(self.undo)

        self.redoAction = QAction('&Redo', self)
        self.redoAction.setDisabled(True)
        self.redoAction.setToolTip('Redo')
        self.redoAction.setStatusTip('Redo last plot view change')
        self.redoAction.setShortcut(QtGui.QKeySequence.Redo)
        self.redoAction.triggered.connect(self.redo)

        self.restoreAction = QAction("&Restore Default Plot", self)
        self.restoreAction.setShortcut("Ctrl+R")
        self.restoreAction.setToolTip('Restore to default plot view')
        self.restoreAction.setStatusTip('Restore to default plot view')
        self.restoreAction.triggered.connect(self.restoreDefault)

        self.editMenu = self.mainMenu.addMenu('&Edit')
        self.editMenu.addAction(self.applyAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.undoAction)
        self.editMenu.addAction(self.redoAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.restoreAction)
        self.editMenu.addSeparator()
        self.editMenu.aboutToShow.connect(self.updateEditMenu)

        # Edit -> Basis Menu
        self.xyAction = QAction('&xy  ', self)
        self.xyAction.setCheckable(True)
        self.xyAction.setShortcut('Alt+X')
        self.xyAction.setToolTip('Change to xy basis')
        self.xyAction.setStatusTip('Change to xy basis')
        self.xyAction.triggered.connect(
            lambda: self.editBasis('xy', apply=True))

        self.xzAction = QAction('x&z  ', self)
        self.xzAction.setCheckable(True)
        self.xzAction.setShortcut('Alt+Z')
        self.xzAction.setToolTip('Change to xz basis')
        self.xzAction.setStatusTip('Change to xz basis')
        self.xzAction.triggered.connect(
            lambda: self.editBasis('xz', apply=True))

        self.yzAction = QAction('&yz  ', self)
        self.yzAction.setCheckable(True)
        self.yzAction.setShortcut('Alt+Y')
        self.yzAction.setToolTip('Change to yz basis')
        self.yzAction.setStatusTip('Change to yz basis')
        self.yzAction.triggered.connect(
            lambda: self.editBasis('yz', apply=True))

        self.basisMenu = self.editMenu.addMenu('&Basis')
        self.basisMenu.addAction(self.xyAction)
        self.basisMenu.addAction(self.xzAction)
        self.basisMenu.addAction(self.yzAction)
        self.basisMenu.aboutToShow.connect(self.updateBasisMenu)

        # Edit -> Color By Menu
        self.cellAction = QAction('&Cell', self)
        self.cellAction.setCheckable(True)
        self.cellAction.setShortcut('Alt+C')
        self.cellAction.setToolTip('Color by cell')
        self.cellAction.setStatusTip('Color plot by cell')
        self.cellAction.triggered.connect(
            lambda: self.editColorBy('cell', apply=True))

        self.materialAction = QAction('&Material', self)
        self.materialAction.setCheckable(True)
        self.materialAction.setShortcut('Alt+M')
        self.materialAction.setToolTip('Color by material')
        self.materialAction.setStatusTip('Color plot by material')
        self.materialAction.triggered.connect(
            lambda: self.editColorBy('material', apply=True))

        self.colorbyMenu = self.editMenu.addMenu('&Color By')
        self.colorbyMenu.addAction(self.cellAction)
        self.colorbyMenu.addAction(self.materialAction)
        self.colorbyMenu.aboutToShow.connect(self.updateColorbyMenu)

        self.editMenu.addSeparator()

        self.maskingAction = QAction('Enable &Masking', self)
        self.maskingAction.setShortcut('Ctrl+M')
        self.maskingAction.setCheckable(True)
        self.maskingAction.setToolTip('Toggle masking')
        self.maskingAction.setStatusTip('Toggle whether masking is enabled')
        self.maskingAction.triggered[bool].connect(
            lambda bool=bool: self.toggleMasking(bool, apply=True))
        self.editMenu.addAction(self.maskingAction)

        self.highlightingAct = QAction('Enable High&lighting', self)
        self.highlightingAct.setShortcut('Ctrl+L')
        self.highlightingAct.setCheckable(True)
        self.highlightingAct.setToolTip('Toggle highlighting')
        self.highlightingAct.setStatusTip(
            'Toggle whether highlighting is enabled')
        self.highlightingAct.triggered[bool].connect(
            lambda bool=bool: self.toggleHighlighting(bool, apply=True))
        self.editMenu.addAction(self.highlightingAct)

        # View Menu
        self.dockAction = QAction('Hide &Dock', self)
        self.dockAction.setShortcut("Ctrl+D")
        self.dockAction.setToolTip('Toggle dock visibility')
        self.dockAction.setStatusTip('Toggle dock visibility')
        self.dockAction.triggered.connect(self.toggleDockView)

        self.zoomAction = QAction('&Zoom...', self)
        self.zoomAction.setShortcut('Alt+Shift+Z')
        self.zoomAction.setToolTip('Edit zoom factor')
        self.zoomAction.setStatusTip('Edit zoom factor')
        self.zoomAction.triggered.connect(self.editZoomAct)

        self.viewMenu = self.mainMenu.addMenu('&View')
        self.viewMenu.addAction(self.dockAction)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.zoomAction)
        self.viewMenu.aboutToShow.connect(self.updateViewMenu)

        # Window Menu
        self.mainWindowAction = QAction('&Main Window', self)
        self.mainWindowAction.setShortcut('Alt+W')
        self.mainWindowAction.setCheckable(True)
        self.mainWindowAction.setToolTip('Bring main window to front')
        self.mainWindowAction.setStatusTip('Bring main window to front')
        self.mainWindowAction.triggered.connect(self.showMainWindow)

        self.colorDialogAction = QAction('Color &Options', self)
        self.colorDialogAction.setShortcut('Alt+D')
        self.colorDialogAction.setCheckable(True)
        self.colorDialogAction.setToolTip('Bring Color Dialog to front')
        self.colorDialogAction.setStatusTip('Bring Color Dialog to front')
        self.colorDialogAction.triggered.connect(self.showColorDialog)

        self.windowMenu = self.mainMenu.addMenu('&Window')
        self.windowMenu.addAction(self.mainWindowAction)
        self.windowMenu.addAction(self.colorDialogAction)
        self.windowMenu.aboutToShow.connect(self.updateWindowMenu)

    def updateEditMenu(self):
        changed = self.model.currentView != self.model.defaultView
        self.restoreAction.setDisabled(not changed)

        self.maskingAction.setChecked(self.model.currentView.masking)
        self.highlightingAct.setChecked(self.model.currentView.highlighting)

        self.undoAction.setText(f'&Undo ({len(self.model.previousViews)})')
        self.redoAction.setText(f'&Redo ({len(self.model.subsequentViews)})')

    def updateBasisMenu(self):
        self.xyAction.setChecked(self.model.currentView.basis == 'xy')
        self.xzAction.setChecked(self.model.currentView.basis == 'xz')
        self.yzAction.setChecked(self.model.currentView.basis == 'yz')

    def updateColorbyMenu(self):
        cv = self.model.currentView
        self.cellAction.setChecked(cv.colorby == 'cell')
        self.materialAction.setChecked(cv.colorby == 'material')

    def updateViewMenu(self):
        if self.dock.isVisible():
            self.dockAction.setText('Hide &Dock')
        else:
            self.dockAction.setText('Show &Dock')

    def updateWindowMenu(self):
        self.colorDialogAction.setChecked(self.colorDialog.isActiveWindow())
        self.mainWindowAction.setChecked(self.isActiveWindow())

    # Menu and shared methods:

    def saveImage(self):
        filename, ext = QFileDialog.getSaveFileName(self, "Save Plot Image",
                                                    "untitled",
                                                    "Images (*.png *.ppm)")
        if filename:
            if "." not in filename:
                filename += ".png"
            self.plotIm.figure.savefig(filename, transparent=True)
            self.statusBar().showMessage('Plot Image Saved', 5000)

    def saveView(self):
        filename, ext = QFileDialog.getSaveFileName(self, "Save View Settings",
                                                    "untitled",
                                                    "View Settings (*.pltvw)")
        if filename:
            if "." not in filename:
                filename += ".pltvw"

            saved = {
                'default': self.model.defaultView,
                'current': self.model.currentView
            }

            with open(filename, 'wb') as file:
                pickle.dump(saved, file)

    def openView(self):
        filename, ext = QFileDialog.getOpenFileName(self, "Open View Settings",
                                                    ".", "*.pltvw")
        if filename:
            try:
                with open(filename, 'rb') as file:
                    saved = pickle.load(file)
            except Exception:
                message = 'Error loading plot settings'
                saved = {'default': None, 'current': None}
            if saved['default'] == self.model.defaultView:
                self.model.activeView = saved['current']
                self.dock.updateDock()
                self.applyChanges()
                message = f'{filename} settings loaded'
            else:
                message = 'Error loading plot settings. Incompatible model.'
            self.statusBar().showMessage(message, 5000)

    def applyChanges(self):
        if self.model.activeView != self.model.currentView:
            self.statusBar().showMessage('Generating Plot...')
            QApplication.processEvents()

            self.model.storeCurrent()
            self.model.subsequentViews = []
            self.model.generatePlot()
            self.resetModels()
            self.showCurrentView()

        else:
            self.statusBar().showMessage('No changes to apply.', 3000)

    def undo(self):
        self.statusBar().showMessage('Generating Plot...')
        QApplication.processEvents()

        self.model.undo()
        self.resetModels()
        self.showCurrentView()
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if not self.model.previousViews:
            self.undoAction.setDisabled(True)
        self.redoAction.setDisabled(False)

    def redo(self):
        self.statusBar().showMessage('Generating Plot...')
        QApplication.processEvents()

        self.model.redo()
        self.resetModels()
        self.showCurrentView()
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if not self.model.subsequentViews:
            self.redoAction.setDisabled(True)
        self.undoAction.setDisabled(False)

    def restoreDefault(self):
        if self.model.currentView != self.model.defaultView:

            self.statusBar().showMessage('Generating Plot...')
            QApplication.processEvents()

            self.model.storeCurrent()
            self.model.activeView = copy.deepcopy(self.model.defaultView)
            self.model.generatePlot()
            self.resetModels()
            self.showCurrentView()
            self.dock.updateDock()
            self.colorDialog.updateDialogValues()

            self.model.subsequentViews = []

    def editBasis(self, basis, apply=False):
        self.model.activeView.basis = basis
        self.dock.updateBasis()
        if apply:
            self.applyChanges()

    def editColorBy(self, domain_kind, apply=False):
        self.model.activeView.colorby = domain_kind
        self.dock.updateColorBy()
        self.colorDialog.updateColorBy()
        if apply:
            self.applyChanges()

    def toggleMasking(self, state, apply=False):
        self.model.activeView.masking = bool(state)
        self.colorDialog.updateMasking()
        if apply:
            self.applyChanges()

    def toggleHighlighting(self, state, apply=False):
        self.model.activeView.highlighting = bool(state)
        self.colorDialog.updateHighlighting()
        if apply:
            self.applyChanges()

    def toggleDockView(self):
        if self.dock.isVisible():
            self.dock.hide()
            if not self.isMaximized() and not self.dock.isFloating():
                self.resize(self.width() - self.dock.width(), self.height())
        else:
            self.dock.setVisible(True)
            if not self.isMaximized() and not self.dock.isFloating():
                self.resize(self.width() + self.dock.width(), self.height())
        self.resizePixmap()
        self.showMainWindow()

    def editZoomAct(self):
        percent, ok = QInputDialog.getInt(self, "Edit Zoom", "Zoom Percent:",
                                          self.dock.zoomBox.value(), 25, 2000)
        if ok:
            self.dock.zoomBox.setValue(percent)

    def editZoom(self, value):
        self.zoom = value
        self.resizePixmap()
        self.dock.zoomBox.setValue(value)

    def showMainWindow(self):
        self.raise_()
        self.activateWindow()

    def showColorDialog(self):
        self.colorDialog.show()
        self.colorDialog.raise_()
        self.colorDialog.activateWindow()

    # Dock methods:

    def editSingleOrigin(self, value, dimension):
        self.model.activeView.origin[dimension] = value

    def editPlotAlpha(self, value):
        self.model.activeView.plotAlpha = value
        self.dock.updatePlotAlpha()

    def editWidth(self, value):
        self.model.activeView.width = value
        self.onRatioChange()
        self.dock.updateWidth()

    def editHeight(self, value):
        self.model.activeView.height = value
        self.onRatioChange()
        self.dock.updateHeight()

    def toggleAspectLock(self, state):
        self.model.activeView.aspectLock = bool(state)
        self.onRatioChange()
        self.dock.updateAspectLock()

    def editVRes(self, value):
        self.model.activeView.v_res = value
        self.dock.updateVRes()

    def editHRes(self, value):
        self.model.activeView.h_res = value
        self.onRatioChange()
        self.dock.updateHRes()

    # Color dialog methods:

    def editMaskingColor(self):
        current_color = self.model.activeView.maskBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.maskBackground = new_color
            self.colorDialog.updateMaskingColor()

    def editHighlightColor(self):
        current_color = self.model.activeView.highlightBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.highlightBackground = new_color
            self.colorDialog.updateHighlightColor()

    def editAlpha(self, value):
        self.model.activeView.highlightAlpha = value

    def editSeed(self, value):
        self.model.activeView.highlightSeed = value

    def editBackgroundColor(self, apply=False):
        current_color = self.model.activeView.plotBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.plotBackground = new_color
            self.colorDialog.updateBackgroundColor()

        if apply:
            self.applyChanges()

    # Plot image methods

    def editPlotOrigin(self, xOr, yOr, zOr=None, apply=False):
        if zOr != None:
            self.model.activeView.origin = [xOr, yOr, zOr]
        else:
            origin = [None, None, None]
            origin[self.xBasis] = xOr
            origin[self.yBasis] = yOr
            origin[self.zBasis] = self.model.activeView.origin[self.zBasis]
            self.model.activeView.origin = origin

        self.dock.updateOrigin()

        if apply:
            self.applyChanges()

    def revertDockControls(self):
        self.dock.revertToCurrent()

    def editDomainColor(self, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        current_color = domain[id].color
        dlg = QColorDialog(self)

        if isinstance(current_color, tuple):
            dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        elif isinstance(current_color, str):
            current_color = openmc.plots._SVG_COLORS[current_color]
            dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            domain[id].color = new_color

        self.applyChanges()

    def toggleDomainMask(self, state, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        domain[id].masked = bool(state)
        self.applyChanges()

    def toggleDomainHighlight(self, state, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        domain[id].highlighted = bool(state)
        self.applyChanges()

    # Helper methods:

    def restoreWindowSettings(self):
        settings = QtCore.QSettings()

        self.resize(settings.value("mainWindow/Size", QtCore.QSize(800, 600)))
        self.move(
            settings.value("mainWindow/Position", QtCore.QPoint(100, 100)))
        self.restoreState(settings.value("mainWindow/State"))

        self.colorDialog.resize(
            settings.value("colorDialog/Size", QtCore.QSize(400, 500)))
        self.colorDialog.move(
            settings.value("colorDialog/Position", QtCore.QPoint(600, 200)))
        self.colorDialog.setVisible(
            bool(settings.value("colorDialog/Visible", 0)))

    def restoreModelSettings(self):
        if os.path.isfile("plot_settings.pkl"):

            with open('plot_settings.pkl', 'rb') as file:
                model = pickle.load(file)

            if model.defaultView == self.model.defaultView:
                self.model.currentView = model.currentView
                self.model.activeView = copy.deepcopy(model.currentView)
                self.model.previousViews = model.previousViews
                self.model.subsequentViews = model.subsequentViews
                if os.path.isfile('plot_ids.binary') \
                    and os.path.isfile('plot.ppm'):
                    self.restored = True

    def resetModels(self):
        self.cellsModel = DomainTableModel(self.model.activeView.cells)
        self.materialsModel = DomainTableModel(self.model.activeView.materials)
        self.cellsModel.beginResetModel()
        self.cellsModel.endResetModel()
        self.materialsModel.beginResetModel()
        self.materialsModel.endResetModel()
        self.colorDialog.updateDomainTabs()

    def showCurrentView(self):
        self.resizePixmap()
        self.updateScale()
        self.updateRelativeBases()

        if self.model.previousViews:
            self.undoAction.setDisabled(False)
        if self.model.subsequentViews:
            self.redoAction.setDisabled(False)
        else:
            self.redoAction.setDisabled(True)

        self.statusBar().showMessage('Done', 1000)
        self.adjustWindow()

    def updateScale(self):
        cv = self.model.currentView
        self.scale = (cv.h_res / cv.width, cv.v_res / cv.height)

    def updateRelativeBases(self):
        cv = self.model.currentView
        self.xBasis = 0 if cv.basis[0] == 'x' else 1
        self.yBasis = 1 if cv.basis[1] == 'y' else 2
        self.zBasis = 3 - (self.xBasis + self.yBasis)

    def adjustWindow(self):
        self.screen = app.desktop().screenGeometry()
        self.setMaximumSize(self.screen.width(), self.screen.height())

    def onRatioChange(self):
        av = self.model.activeView
        if av.aspectLock:
            ratio = av.width / max(av.height, .001)
            av.v_res = int(av.h_res / ratio)
            self.dock.updateVRes()

    def showCoords(self, xPlotPos, yPlotPos):
        cv = self.model.currentView
        if cv.basis == 'xy':
            coords = (f"({round(xPlotPos, 2)}, {round(yPlotPos, 2)}, "
                      f"{round(cv.origin[2], 2)})")
        elif cv.basis == 'xz':
            coords = (f"({round(xPlotPos, 2)}, {round(cv.origin[1], 2)}, "
                      f"{round(yPlotPos, 2)})")
        else:
            coords = (f"({round(cv.origin[0], 2)}, {round(xPlotPos, 2)}, "
                      f"{round(yPlotPos, 2)})")
        self.coord_label.setText(f'{coords}')

    def resizePixmap(self):
        z = self.zoom / 100.
        self.plotIm.setPixmap(self.frame.width() * z, self.frame.height() * z)
        self.plotIm.adjustSize()

    def moveEvent(self, event):
        self.adjustWindow()

    def resizeEvent(self, event):
        if self.pixmap:
            self.adjustWindow()
            self.updateScale()

    def closeEvent(self, event):
        settings = QtCore.QSettings()
        settings.setValue("mainWindow/Size", self.size())
        settings.setValue("mainWindow/Position", self.pos())
        settings.setValue("mainWindow/State", self.saveState())

        settings.setValue("colorDialog/Size", self.colorDialog.size())
        settings.setValue("colorDialog/Position", self.colorDialog.pos())
        visible = int(self.colorDialog.isVisible())
        settings.setValue("colorDialog/Visible", visible)

        if len(self.model.previousViews) > 10:
            self.model.previousViews = self.model.previousViews[-10:]
        if len(self.model.subsequentViews) > 10:
            self.model.subsequentViews = self.model.subsequentViews[-10:]

        with open('plot_settings.pkl', 'wb') as file:
            pickle.dump(self.model, file)
示例#2
0
文件: viewwidget.py 项目: cr0vy/epm
class ViewWidget(QWidget):
    exercise_name_label = None
    exercise_name_line = None

    scroll_area = None
    base_widget = None
    exercises_widget = None

    return_button = None

    add_button = None

    def __init__(self):
        QWidget.__init__(self)

        self.file = ""
        self.setup_widget()

    def setup_widget(self):
        self.exercise_name_label = QLabel("Exercise name:", self)
        self.exercise_name_label.move(5, 5)
        self.exercise_name_label.resize(125, 25)

        self.add_button = QPushButton("Add", self)
        self.add_button.resize(75, 25)
        self.add_button.clicked.connect(self.add_line)

        self.exercise_name_line = QLineEdit(self)
        self.exercise_name_line.move(135, 5)
        self.exercise_name_line.resize(125, 25)

        self.scroll_area = QScrollArea(self)
        self.base_widget = QWidget(self)
        self.scroll_area.setWidget(self.base_widget)

        self.exercises_widget = QVBoxLayout()
        self.exercises_widget.setAlignment(Qt.AlignTop)

        self.base_widget.setLayout(self.exercises_widget)

        self.return_button = QPushButton("Return wo save", self)

    def resizeEvent(self, event):
        self.scroll_area.move(5, 35)
        self.scroll_area.resize(self.width() - 165, self.height() - 40)
        self.add_button.move(self.width() - 160 - 75, 5)
        self.return_button.move(self.width() - 155, 5)
        self.return_button.resize(150, 40)

        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

    def clear_widget(self):
        while self.exercises_widget.count() > 0:
            self.exercises_widget.takeAt(0)

    def open_exercise_file(self, file: str):
        self.file = file

        with open(self.file, "r") as json_file:
            json_data = json.load(json_file)

            name = json_data['name']

            for data in json_data['exercise']:
                movement = data['name']
                description = data['description']
                time = data['time']

                widget = PanelWidget()
                widget.set_data(movement, description, time)
                widget.remove_signal.connect(self.remove_panel_item)
                widget.move_down_signal.connect(self.move_widget_down)
                widget.move_up_signal.connect(self.move_widget_up)

                self.exercises_widget.addWidget(widget)

            json_file.close()

        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

        self.exercise_name_line.setText(name)

    @Slot()
    def add_line(self):
        widget = PanelWidget()
        self.exercises_widget.addWidget(widget)
        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

    @Slot(QWidget)
    def move_widget_down(self, widget: QWidget):
        ind = self.exercises_widget.indexOf(widget)
        self.exercises_widget.removeWidget(widget)
        self.exercises_widget.insertWidget((ind + 1), widget)

    @Slot(QWidget)
    def move_widget_up(self, widget: QWidget):
        ind = self.exercises_widget.indexOf(widget)
        self.exercises_widget.removeWidget(widget)
        self.exercises_widget.insertWidget((ind - 1), widget)

    @Slot(QWidget)
    def remove_panel_item(self, widget: QWidget):
        self.exercises_widget.removeWidget(widget)
        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)