class JonahWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setAcceptDrops(True)#mainwindow是否接收拖动
        pathList = QStandardPaths.standardLocations(QStandardPaths.PicturesLocation)# type:tuple(list,str)
        self.workPath = pathList[-1] if len(pathList)>0 else QDir.currentPath()
        self.zoomIdx = 3
        self.zoomList = [0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0]
        self.originSize = QSize(0, 0)
        self.originSize1 = QSize(0, 0)
        self.penColor = QColor(0, 170, 255)#初始化颜色
        self.opendFile = ''
        self.opendFile1 = ''
        self.initUI()
        screenInfo = QApplication.desktop()
        screenIdx = screenInfo.screenNumber()#current screen index
        screenRect = screenInfo.screenGeometry(screenIdx)
        self.setGeometry((screenRect.width()-1280)/2, (screenRect.height()-720)/2, 1280, 720)
        self.__setTitle()
        
    def initUI(self):
        fileMenu = self.menuBar().addMenu('&File')
        self.menuBar().setStyleSheet('QMenuBar{background:rgb(128,128,128)}QMenuBar::item:selected{background:rgb(128,128,128)}QMenu{background:rgb(128,128,128)}QMenu::item:selected{background-color:#654321;}')
        openFilesAction = QAction('Open files', self)
        exitAction = QAction('Exit', self)
        closeAction = QAction('Close', self)
        fileMenu.addAction(openFilesAction)
        fileMenu.addAction(closeAction)
        fileMenu.addAction(exitAction)
        openFilesAction.triggered.connect(self.onOpenFileAction)
        closeAction.triggered.connect(self.onCloseAction)
        exitAction.triggered.connect(self.onQuit)
        
        zoomMenu = self.menuBar().addMenu('&Zoom')
        zoomInAction = QAction('zoom in', self)
        zoomOutAction = QAction('zoom out', self)
        zoomMenu.addAction(zoomInAction)
        zoomMenu.addAction(zoomOutAction)
        zoomInAction.triggered.connect(self.zoomIn)
        zoomOutAction.triggered.connect(self.zoomOut)
        zoomInAction.setShortcut(QKeySequence(QKeySequence.ZoomIn))
        zoomOutAction.setShortcut(QKeySequence(QKeySequence.ZoomOut))
        
        viewMenu = self.menuBar().addMenu('&View')
        dockWidgetMenu = QMenu('dock widget', self)
        dockWidgetMenu.setStyleSheet('QMenu{background:rgb(128,128,128)}QMenu::item:selected{background-color:#654321;}')
        viewMenu.addMenu(dockWidgetMenu)
        self.penBoxAction = QAction('pen box', self)
        self.colorGamutAction = QAction('color gamut', self)
        dockWidgetMenu.addAction(self.penBoxAction)
        self.penBoxAction.setCheckable(True)
        self.penBoxAction.setChecked(True)
        dockWidgetMenu.addAction(self.colorGamutAction)
        self.colorGamutAction.setCheckable(True)
        self.colorGamutAction.setChecked(True)
                
        aboutMenu = self.menuBar().addMenu('&About')
        aboutQtAction = QAction('About Qt', self)
        aboutQtAction.triggered.connect(self.aboutQt_)
        aboutThisAction = QAction('About this', self)
        aboutThisAction.triggered.connect(self.aboutThis)
        aboutMenu.addAction(aboutQtAction)
        aboutMenu.addAction(aboutThisAction)
        
        self.mainWidget = QFrame()
        self.mainWidget.setFrameStyle(QFrame.Box|QFrame.Sunken)
        scrollAreaLayout = QHBoxLayout()
        self.mainWidget.setLayout(scrollAreaLayout)
        
        self.scrollArea = QScrollArea()
        self.imageLabel = ImageLabel(self.penColor, 2, 'rect')
        self.imageLabel.setText('drag image file to here!')
        self.imageLabel.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
        self.imageLabel.setScaledContents(True)
        self.scrollArea.setWidget(self.imageLabel)
        self.scrollArea.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
        
        self.scrollArea1 = QScrollArea()
        self.imageLabel1 = ImageLabel(self.penColor, 2, 'rect')
        self.imageLabel1.setText('drag image file to here!')
        self.imageLabel1.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
        self.imageLabel1.setScaledContents(True)
        self.scrollArea1.setWidget(self.imageLabel1)
        self.scrollArea1.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
        
        scrollAreaLayout.addWidget(self.scrollArea)
        scrollAreaLayout.addWidget(self.scrollArea1)
        
        self.setCentralWidget(self.mainWidget)
        
        
        self.createDockWidget()
        
        self.paintType_line_btn.toggled.connect(self.__setPaintType_line)
        self.paintType_rect_btn.toggled.connect(self.__setPaintType_rect)
        self.lineWidth_box.currentIndexChanged[str].connect(self.__setPenWidth)
        self.colorBtn.clicked.connect(self.__selectColor)
        self.paintOk.clicked.connect(self.__handleInputPaintPos)
        self.paintOk1.clicked.connect(self.__handleInputPaintPos1)
        self.syncRight.clicked.connect(self.__syncRightPos)
        self.syncLeft.clicked.connect(self.__syncLeftPos)
        
        self.createDockWidget_1()
        self.toolBoxWidget.installEventFilter(self)#拦截消息,关闭dock widget实际是隐藏
        self.plotDockWgt.installEventFilter(self)
        
        self.plot_rgb_contourf_line.clicked.connect(self.plot_rgb_contourf_line_func)
        self.plot_rgb_hist.clicked.connect(self.plot_rgb_hist_func)
        self.imageLabel.inform_real_Pos.connect(self.__flushPaintPosEdit)
        self.imageLabel1.inform_real_Pos.connect(self.__flushPaintPosEdit1)
        self.scrollArea.horizontalScrollBar().valueChanged.connect(self.__syncScrollArea1_horScBarVal)
        self.scrollArea.verticalScrollBar().valueChanged.connect(self.__syncScrollArea1_verScBarVal)
        self.scrollArea1.horizontalScrollBar().valueChanged.connect(self.__syncScrollArea_horScBarVal)
        self.scrollArea1.verticalScrollBar().valueChanged.connect(self.__syncScrollArea_verScBarVal)
        
        self.penBoxAction.toggled.connect(self.__toggleToolBoxDockWgt)
        self.colorGamutAction.toggled.connect(self.__toggleColorGamutWgt)
    
    def __syncScrollArea1_horScBarVal(self, value:int):
        '''
        同步两个图像区域的滚动条位置
        '''
        if not self.scrollArea.horizontalScrollBar().isVisible():
            return
        if not self.scrollArea1.horizontalScrollBar().isVisible():
            return
        try:
            pos_ratio = value/self.scrollArea.horizontalScrollBar().maximum()
            target_val = int(pos_ratio*self.scrollArea1.horizontalScrollBar().maximum()+0.5)
            self.scrollArea1.horizontalScrollBar().setValue(target_val)
        except ZeroDivisionError:
            return
            
    
    def __syncScrollArea1_verScBarVal(self, value:int):
        '''
        同步两个图像区域的滚动条位置
        '''
        if not self.scrollArea.verticalScrollBar().isVisible():
            return
        if not self.scrollArea1.verticalScrollBar().isVisible():
            return
        try:
            pos_ratio = value/self.scrollArea.verticalScrollBar().maximum()
            target_val = int(pos_ratio*self.scrollArea1.verticalScrollBar().maximum()+0.5)
            self.scrollArea1.verticalScrollBar().setValue(target_val)
        except ZeroDivisionError:
            return
    
    def __syncScrollArea_horScBarVal(self, value:int):
        '''
        同步两个图像区域的滚动条位置
        '''
        if not self.scrollArea.horizontalScrollBar().isVisible():
            return
        if not self.scrollArea1.horizontalScrollBar().isVisible():
            return
        try:
            pos_ratio = value/self.scrollArea1.horizontalScrollBar().maximum()
            target_val = int(pos_ratio*self.scrollArea.horizontalScrollBar().maximum()+0.5)
            self.scrollArea.horizontalScrollBar().setValue(target_val)
        except ZeroDivisionError:
            return
        
    def __syncScrollArea_verScBarVal(self, value:int):
        '''
        同步两个图像区域的滚动条位置
        '''
        if not self.scrollArea.verticalScrollBar().isVisible():
            return
        if not self.scrollArea1.verticalScrollBar().isVisible():
            return
        try:
            pos_ratio = value/self.scrollArea1.verticalScrollBar().maximum()
            target_val = int(pos_ratio*self.scrollArea.verticalScrollBar().maximum()+0.5)
            self.scrollArea.verticalScrollBar().setValue(target_val)
        except ZeroDivisionError:
            return
    
    def __setPaintType_line(self):
        '''
        设置绘图类型为直线
        '''
        self.imageLabel.setPaintType_Line()
        self.imageLabel1.setPaintType_Line()
    
    def __setPaintType_rect(self):
        '''
        设置绘图类型为矩形
        '''
        self.imageLabel.setPaintType_Rect()
        self.imageLabel1.setPaintType_Rect()
        
    def __setPenWidth(self, width:str):
        '''
        设置绘图线宽
        '''
        self.imageLabel.setPenWidth(width)
        self.imageLabel1.setPenWidth(width)
        
    def __toggleToolBoxDockWgt(self, checked:bool):
        '''
        菜单切换dock widget显示
        '''
        if checked:
            self.toolBoxWidget.show()
        else:
            self.toolBoxWidget.close()
    
    def __toggleColorGamutWgt(self, checked:bool):
        '''
        菜单切换dock widget显示
        '''
        if checked:
            self.plotDockWgt.show()
        else:
            self.plotDockWgt.close()
            
    def __syncRightPos(self):
        '''
        当点击面板上的sync按钮后,同步左右两侧的绘图坐标
        '''
        self.start_x_edit1.setText(self.start_x_edit.text())
        self.start_y_edit1.setText(self.start_y_edit.text())
        self.end_x_edit1.setText(self.end_x_edit.text())
        self.end_y_edit1.setText(self.end_y_edit.text())
        
    def __syncLeftPos(self):
        '''
        当点击面板上的sync按钮后,同步左右两侧的绘图坐标
        '''
        self.start_x_edit.setText(self.start_x_edit1.text())
        self.start_y_edit.setText(self.start_y_edit1.text())
        self.end_x_edit.setText(self.end_x_edit1.text())
        self.end_y_edit.setText(self.end_y_edit1.text())
    
    def createDockWidget(self):
        '''
        创建面板---绘图工具箱
        '''
        self.toolBoxWidget = QDockWidget(self)
        self.toolBoxWidget.setWindowTitle('pen box')
        self.toolBoxWidget.setAllowedAreas(Qt.LeftDockWidgetArea|Qt.RightDockWidgetArea)
        toolBoxContainer = QWidget()
        vlayout = QVBoxLayout()
        toolBoxContainer.setLayout(vlayout)
        self.toolBoxWidget.setWidget(toolBoxContainer)
        toolBoxContainer.setStyleSheet('QPushButton{background-color:rgb(156,156,156)}QComboBox{border:1px solid gray}')
        
        penGroup = QButtonGroup()
        penLayout = QHBoxLayout()
        self.paintType_line_btn = QRadioButton('line')
        self.paintType_rect_btn = QRadioButton('rect')
        self.paintType_rect_btn.setChecked(True)#初始形状 矩形
        penGroup.addButton(self.paintType_line_btn)
        penGroup.addButton(self.paintType_rect_btn)
        penLayout.addWidget(self.paintType_line_btn, 1)
        penLayout.addWidget(self.paintType_rect_btn, 1)
        penLayout.addStretch(1)
        
        lineWidth_layout = QHBoxLayout()
        lineWidth_text = QLabel('line width:')
        self.lineWidth_box = QComboBox()
        self.lineWidth_box.addItems(['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '12', '14', '16', '18', '20', '24', '28', '32'])
        self.lineWidth_box.setCurrentIndex(1)
        lineWidth_layout.addWidget(lineWidth_text, 1)
        lineWidth_layout.addWidget(self.lineWidth_box, 1)
        lineWidth_layout.addStretch(1)
        
        colorLayout = QHBoxLayout()
        colorText = QLabel('color:')
        self.colorBtn = QPushButton('')
        colorLayout.addWidget(colorText, 1)
        colorLayout.addWidget(self.colorBtn, 1)
        colorLayout.addStretch(1)
        
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        
        imageSizeValidator = QIntValidator(0, 10000)
        paintPosLayout0 = QGridLayout()
        start_x_text = QLabel('start x:')
        self.start_x_edit = QLineEdit()
        self.start_x_edit.setMaximumWidth(55)
        self.start_x_edit.setValidator(imageSizeValidator)
        start_y_text = QLabel('y:')
        self.start_y_edit = QLineEdit()
        self.start_y_edit.setMaximumWidth(55)
        self.start_y_edit.setValidator(imageSizeValidator)
        paintPosLayout0.addWidget(start_x_text, 0, 0, 1, 1)
        paintPosLayout0.addWidget(self.start_x_edit, 0, 1, 1, 1)
        paintPosLayout0.addWidget(start_y_text, 1, 0, 1, 1)
        paintPosLayout0.addWidget(self.start_y_edit, 1, 1, 1, 1)
        
        end_x_text = QLabel('end x:')
        self.end_x_edit = QLineEdit()
        self.end_x_edit.setMaximumWidth(55)
        self.end_x_edit.setValidator(imageSizeValidator)
        end_y_text = QLabel('y:')
        self.end_y_edit = QLineEdit()
        self.end_y_edit.setMaximumWidth(55)
        self.end_y_edit.setValidator(imageSizeValidator)
        paintPosLayout0.addWidget(end_x_text, 2, 0, 1, 1)
        paintPosLayout0.addWidget(self.end_x_edit, 2, 1, 1, 1)
        paintPosLayout0.addWidget(end_y_text, 3, 0, 1, 1)
        paintPosLayout0.addWidget(self.end_y_edit, 3, 1, 1, 1)
        
        self.paintOk = QPushButton('ok')
        paintPosLayout0.addWidget(self.paintOk, 4, 1, 1, 1)
        
        vline1 = QFrame()
        vline1.setFrameShape(QFrame.VLine)
        syncLayout = QVBoxLayout()
        self.syncRight = QPushButton('--->')
        self.syncLeft = QPushButton('<---')

        syncLayout.addWidget(self.syncRight)
        syncLayout.addWidget(self.syncLeft)
        vline2 = QFrame()
        vline2.setFrameShape(QFrame.VLine)
        
        paintPosLayout1 = QGridLayout()
        start_x_text1 = QLabel('start x:')
        self.start_x_edit1 = QLineEdit()
        self.start_x_edit1.setMaximumWidth(55)
        self.start_x_edit1.setValidator(imageSizeValidator)
        start_y_text1 = QLabel('y:')
        self.start_y_edit1 = QLineEdit()
        self.start_y_edit1.setMaximumWidth(55)
        self.start_y_edit1.setValidator(imageSizeValidator)
        paintPosLayout1.addWidget(start_x_text1, 0, 0, 1, 1)
        paintPosLayout1.addWidget(self.start_x_edit1, 0, 1, 1, 1)
        paintPosLayout1.addWidget(start_y_text1, 1, 0, 1, 1)
        paintPosLayout1.addWidget(self.start_y_edit1, 1, 1, 1, 1)
        end_x_text1 = QLabel('end x:')
        self.end_x_edit1 = QLineEdit()
        self.end_x_edit1.setMaximumWidth(55)
        self.end_x_edit1.setValidator(imageSizeValidator)
        end_y_text1 = QLabel('y:')
        self.end_y_edit1 = QLineEdit()
        self.end_y_edit1.setMaximumWidth(55)
        self.end_y_edit1.setValidator(imageSizeValidator)
        paintPosLayout1.addWidget(end_x_text1, 2, 0, 1, 1)
        paintPosLayout1.addWidget(self.end_x_edit1, 2, 1, 1, 1)
        paintPosLayout1.addWidget(end_y_text1, 3, 0, 1, 1)
        paintPosLayout1.addWidget(self.end_y_edit1, 3, 1, 1, 1)
        
        self.paintOk1 = QPushButton('ok')
        paintPosLayout1.addWidget(self.paintOk1, 4, 1, 1, 1)
        
        paintPosLayout = QHBoxLayout()
        paintPosLayout.addLayout(paintPosLayout0)
        paintPosLayout.addWidget(vline1)
        paintPosLayout.addLayout(syncLayout)
        paintPosLayout.addWidget(vline2)
        paintPosLayout.addLayout(paintPosLayout1)
        
        vlayout.addLayout(penLayout)
        vlayout.addLayout(lineWidth_layout)
        vlayout.addLayout(colorLayout)
        vlayout.addWidget(hline)
        vlayout.addLayout(paintPosLayout)
        vlayout.addStretch(1)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.toolBoxWidget)
        
        self.__setPenBtnColor()
        
    def __flushPaintPosEdit(self, startPt:QPointF, endPt:QPointF):
        '''
        接收的坐标是imagelabel的绘图坐标,需要根据当前的zoom计算出真实的图片坐标,并显示在面板上
        '''
        realStartPt = (startPt/self.zoomList[self.zoomIdx]).toPoint()
        realEndPt = (endPt/self.zoomList[self.zoomIdx]).toPoint()
        self.start_x_edit.setText(str(realStartPt.x()))
        self.start_y_edit.setText(str(realStartPt.y()))
        self.end_x_edit.setText(str(realEndPt.x()))
        self.end_y_edit.setText(str(realEndPt.y()))
        
    def __flushPaintPosEdit1(self, startPt:QPointF, endPt:QPointF):
        '''
        接收的坐标是imagelabel的绘图坐标,需要根据当前的zoom计算出真实的图片坐标
        '''
        realStartPt = (startPt/self.zoomList[self.zoomIdx]).toPoint()
        realEndPt = (endPt/self.zoomList[self.zoomIdx]).toPoint()
        self.start_x_edit1.setText(str(realStartPt.x()))
        self.start_y_edit1.setText(str(realStartPt.y()))
        self.end_x_edit1.setText(str(realEndPt.x()))
        self.end_y_edit1.setText(str(realEndPt.y()))
    
    def __handleInputPaintPos(self):
        try:
            if self.imageLabel.pixmap()==None:
                return
            else:
                maxWidth = self.imageLabel.pixmap().width()
                maxHeight = self.imageLabel.pixmap().height()
                start_x = int(self.start_x_edit.text())
                start_x = maxWidth if start_x>=maxWidth else start_x
                start_y = int(self.start_y_edit.text())
                start_y = maxHeight if start_y>=maxHeight else start_y
                end_x = int(self.end_x_edit.text())
                end_x = maxWidth if end_x>=maxWidth else end_x
                end_y = int(self.end_y_edit.text())
                end_y = maxHeight if end_y>=maxHeight else end_y
                
                scale_ratio = self.zoomList[self.zoomIdx]
                self.imageLabel.paintCoordinates[0] = QPointF(float(start_x)*scale_ratio, float(start_y)*scale_ratio)
                self.imageLabel.paintCoordinates[1] = QPointF(float(end_x)*scale_ratio, float(end_y)*scale_ratio)
                self.imageLabel.paintEnd = True
                self.imageLabel.repaint()
        except ValueError:
            pass
            
    def __handleInputPaintPos1(self):
        try:
            if self.imageLabel1.pixmap()==None:
                return
            else:
                maxWidth = self.imageLabel1.pixmap().width()
                maxHeight = self.imageLabel1.pixmap().height()
                start_x = int(self.start_x_edit.text())
                start_x = maxWidth if start_x>=maxWidth else start_x
                start_y = int(self.start_y_edit.text())
                start_y = maxHeight if start_y>=maxHeight else start_y
                end_x = int(self.end_x_edit.text())
                end_x = maxWidth if end_x>=maxWidth else end_x
                end_y = int(self.end_y_edit.text())
                end_y = maxHeight if end_y>=maxHeight else end_y
                
                scale_ratio = self.zoomList[self.zoomIdx]
                self.imageLabel1.paintCoordinates[0] = QPointF(float(start_x)*scale_ratio, float(start_y)*scale_ratio)
                self.imageLabel1.paintCoordinates[1] = QPointF(float(end_x)*scale_ratio, float(end_y)*scale_ratio)
                self.imageLabel1.paintEnd = True
                self.imageLabel1.repaint()
        except ValueError:
            pass
            
    def createDockWidget_1(self):
        '''
        创建绘图工具箱,包含绘图类型,线宽,颜色,坐标值
        '''
        self.plotDockWgt = QDockWidget(self)
        self.plotDockWgt.setAllowedAreas(Qt.LeftDockWidgetArea|Qt.RightDockWidgetArea)
        self.plotDockWgt.setWindowTitle('color gamut type')
        #self.plotDockWgt.setFeatures(QDockWidget.DockWidgetClosable|QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetFloatable|QDockWidget.DockWidgetVerticalTitleBar)
        pltWgtContainer = QWidget()
        vlayout = QVBoxLayout()
        pltWgtContainer.setLayout(vlayout)
        self.plotDockWgt.setWidget(pltWgtContainer)
        pltWgtContainer.setStyleSheet('QPushButton{background-color:rgb(156,156,156)}')
        
        plot_btn_layout = QGridLayout()
        self.plot_rgb_contourf_line = QPushButton('rgb contour/line')
        self.plot_rgb_hist = QPushButton('rgb hist')
        self.plot_yuv_contourf_line = QPushButton('yuv contour/line')
        self.plot_yuv_hist = QPushButton('yuv hist')
        self.plot_hsv_contourf_line = QPushButton('hsv contour/line')
        self.plot_hsv_hist = QPushButton('hsv hist')
        plot_btn_layout.addWidget(self.plot_rgb_contourf_line, 0, 0, 1, 1)
        plot_btn_layout.addWidget(self.plot_rgb_hist, 0, 1, 1, 1)
        plot_btn_layout.addWidget(self.plot_yuv_contourf_line, 1, 0, 1, 1)
        plot_btn_layout.addWidget(self.plot_yuv_hist, 1, 1, 1, 1)
        plot_btn_layout.addWidget(self.plot_hsv_contourf_line, 2, 0, 1, 1)
        plot_btn_layout.addWidget(self.plot_hsv_hist, 2, 1, 1, 1)
        
        vlayout.addLayout(plot_btn_layout)
        
        rgb2yuv_mat_layout = QGridLayout()
        rgb2yuv_mat_label = QLabel('rgb2yuv:')
        rgb2yuv_mat_layout.addWidget(rgb2yuv_mat_label, 0, 0, 1, 1)
        validtor = QDoubleValidator(-5.0, 5.0, 10)
        self.rgb2yuv_mat_0 = QLineEdit('0.299')
        self.rgb2yuv_mat_0.setMaximumWidth(55)
        self.rgb2yuv_mat_0.setValidator(validtor)
        self.rgb2yuv_mat_1 = QLineEdit('0.587')
        self.rgb2yuv_mat_1.setMaximumWidth(55)
        self.rgb2yuv_mat_1.setValidator(validtor)
        self.rgb2yuv_mat_2 = QLineEdit('0.114')
        self.rgb2yuv_mat_2.setMaximumWidth(55)
        self.rgb2yuv_mat_2.setValidator(validtor)
        self.rgb2yuv_mat_3 = QLineEdit('-0.147')
        self.rgb2yuv_mat_3.setMaximumWidth(55)
        self.rgb2yuv_mat_3.setValidator(validtor)
        self.rgb2yuv_mat_4 = QLineEdit('-0.289')
        self.rgb2yuv_mat_4.setMaximumWidth(55)
        self.rgb2yuv_mat_4.setValidator(validtor)
        self.rgb2yuv_mat_5 = QLineEdit('0.436')
        self.rgb2yuv_mat_5.setMaximumWidth(55)
        self.rgb2yuv_mat_5.setValidator(validtor)
        self.rgb2yuv_mat_6 = QLineEdit('0.615')
        self.rgb2yuv_mat_6.setMaximumWidth(55)
        self.rgb2yuv_mat_6.setValidator(validtor)
        self.rgb2yuv_mat_7 = QLineEdit('-0.515')
        self.rgb2yuv_mat_7.setMaximumWidth(55)
        self.rgb2yuv_mat_7.setValidator(validtor)
        self.rgb2yuv_mat_8 = QLineEdit('-0.100')
        self.rgb2yuv_mat_8.setMaximumWidth(55)
        self.rgb2yuv_mat_8.setValidator(validtor)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_0, 1, 0, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_1, 1, 1, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_2, 1, 2, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_3, 2, 0, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_4, 2, 1, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_5, 2, 2, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_6, 3, 0, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_7, 3, 1, 1, 1)
        rgb2yuv_mat_layout.addWidget(self.rgb2yuv_mat_8, 3, 2, 1, 1)
        rgb2yuv_mat_layout.setColumnMinimumWidth(0, 20)
        rgb2yuv_mat_layout.setColumnMinimumWidth(1, 20)
        rgb2yuv_mat_layout.setColumnMinimumWidth(2, 20)
        
        vlayout.addLayout(rgb2yuv_mat_layout)
        vlayout.addStretch(1)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.plotDockWgt)
    
    def plot_rgb_contourf_line_func(self):
        f = self.__plot_rgb_contourf_line(self.imageLabel, self.opendFile, 0)
        f1 = self.__plot_rgb_contourf_line(self.imageLabel1, self.opendFile1, 1)
        if f is None and f1 is None:
            return
        else:
            plt.show()

            
    def __plot_rgb_contourf_line(self, label:ImageLabel, file:str, figCnt:int):
        if label.paintEnd==True and label.pixmap()!=None:
            pos_0, pos_1 = QPointF(label.paintCoordinates[0])/self.zoomList[self.zoomIdx], QPointF(label.paintCoordinates[1])/self.zoomList[self.zoomIdx]
            x_0, x_1, y_0, y_1 = pos_0.x(), pos_1.x(), pos_0.y(), pos_1.y()
            if x_0!=x_1 and y_0!=y_1 and self.paintType_rect_btn.isChecked():
                if x_0 > x_1:
                    x_0, x_1 = x_1, x_0
                if y_0 > y_1:
                    y_0, y_1 = y_1, y_0
                if file.endswith(('.jpg',  '.jpeg',  'JPG',  'JPEG')):
                    reader = decompress_jpeg.jpeg_reader(bytes(file,  encoding='utf-8'))
                    rgb_data, out_rgb = reader.get_rgb_data()
                    if rgb_data is None:
                        QMessageBox.information(self, 'information', 'can not open image', QMessageBox.Ok)
                        return None
                    data = rgb_data.reshape((out_rgb.image_height,  out_rgb.image_width, 3)).copy()
                    del rgb_data
                    reader.releaseBuffer()
                    data = data[:, :, ::-1]# rgb->bgr
                else:
                    data = cv.imread(file)
                    if data is None:
                        QMessageBox.information(self, 'information', 'can not open image', QMessageBox.Ok)
                        return None
                data_r = data[int(y_0):int(y_1), int(x_0):int(x_1), 2]
                data_g = data[int(y_0):int(y_1), int(x_0):int(x_1), 1]
                data_b = data[int(y_0):int(y_1), int(x_0):int(x_1), 0]
                data_max = np.max([data_r.max(), data_g.max(), data_b.max()])
                data_min = np.min([data_r.min(), data_g.min(), data_b.min()])
                X = np.arange(data_r.shape[1])
                Y = np.arange(data_r.shape[0])
                X, Y = np.meshgrid(X, Y)
                fig = plt.figure(figCnt, figsize=(4, 9))
                ax1 = fig.add_subplot(311)
                surf1 = ax1.contourf(X, Y, data_r, np.linspace(data_min-5, data_max+5, 11), cmap=cm.get_cmap('coolwarm'))
                ax1.set_ylim([data_r.shape[0], 0])
                ax1.set_title('r contour')
                fig.colorbar(surf1)
        
                ax2 = fig.add_subplot(312)
                surf2 = ax2.contourf(X, Y, data_g, np.linspace(data_min-5, data_max+5, 11), cmap=cm.get_cmap('coolwarm'))
                ax2.set_ylim([data_g.shape[0], 0])
                ax2.set_title('g contour')
                fig.colorbar(surf2)
        
                ax3 = fig.add_subplot(313)
                surf3 = ax3.contourf(X, Y, data_b, np.linspace(data_min-5, data_max+5, 11), cmap=cm.get_cmap('coolwarm'))
                ax3.set_ylim([data_b.shape[0], 0])
                ax3.set_title('b contour')
                fig.colorbar(surf3)
                fig.tight_layout()
                return fig
            elif self.paintType_line_btn.isChecked() and not(x_0==x_1 and y_0==y_1):
                if x_0 > x_1:
                    x_0, x_1 = x_1, x_0
                    y_0, y_1 = y_1, y_0
                data = cv.imread(file)
                if data is None:
                    QMessageBox.information(self, 'information', 'can not open image %s'%self.opendFile, QMessageBox.Ok)
                    return None
                if x_0==x_1:
                    if y_0<y_1:
                        data_r = data[y_0:y_1, x_0, 2]
                        data_g = data[y_0:y_1, x_0, 1]
                        data_b = data[y_0:y_1, x_0, 0]
                    else:
                        data_r = data[y_0:y_1:-1, x_0, 2]
                        data_g = data[y_0:y_1:-1, x_0, 1]
                        data_b = data[y_0:y_1:-1, x_0, 0]
                elif y_0==y_1:
                    data_r = data[y_0, x_0:x_1, 2]
                    data_g = data[y_0, x_0:x_1, 1]
                    data_b = data[y_0, x_0:x_1, 0]
                else:
                    length = math.sqrt((x_1-x_0)*(x_1-x_0) + (y_1-y_0)*(y_1-y_0))
                    data_r = np.zeros((int(length), ), np.uint8)
                    data_g = np.zeros((int(length), ), np.uint8)
                    data_b = np.zeros((int(length), ), np.uint8)
                    k = (y_1-y_0)/(x_1-x_0)
                    for l in range(int(length)):
                        delt_x = math.sqrt((l*l)/(1+k*k))
                        delt_y = k*delt_x
                        data_r[l] = data[int(y_0+delt_y+0.5), int(x_0+delt_x+0.5), 2]
                        data_g[l] = data[int(y_0+delt_y+0.5), int(x_0+delt_x+0.5), 1]
                        data_b[l] = data[int(y_0+delt_y+0.5), int(x_0+delt_x+0.5), 0]
                fig = plt.figure(figCnt, figsize=(6, 4))
                ax = fig.add_subplot(111)
                ax.plot(data_r, 'r-', data_g, 'g-', data_b, 'b-')
                return fig
            else:
                return None
        else:
            return None
                
    def eventFilter(self, obj:QObject, event:QEvent):
        if obj is self.toolBoxWidget and event.type()==QEvent.Close:
            self.penBoxAction.setChecked(False)
            return True
        if obj is self.plotDockWgt and event.type()==QEvent.Close:
            self.colorGamutAction.setChecked(False)
            return True
        
        return super().eventFilter(obj, event)
            
    
    def plot_rgb_hist_func(self):
        fig, fig1 = None, None
        if self.imageLabel.paintEnd==True and self.imageLabel.pixmap()!=None:
            pos_0, pos_1 = QPointF(self.imageLabel.paintCoordinates[0])/self.zoomList[self.zoomIdx], QPointF(self.imageLabel.paintCoordinates[1])/self.zoomList[self.zoomIdx]
            x_0, x_1, y_0, y_1 = pos_0.x(), pos_1.x(), pos_0.y(), pos_1.y()
            if x_0 > x_1:
                x_0, x_1 = x_1, x_0
            if y_0 > y_1:
                y_0, y_1 = y_1, y_0
            
            data = cv.imread(self.opendFile)
            if data is None:
                QMessageBox.information(self, 'information', 'can not open image %s'%self.opendFile, QMessageBox.Ok)
                return

            data_r = data[int(y_0):int(y_1), int(x_0):int(x_1), 2].flatten()
            data_g = data[int(y_0):int(y_1), int(x_0):int(x_1), 1].flatten()
            data_b = data[int(y_0):int(y_1), int(x_0):int(x_1), 0].flatten()
            n_bins = 64
        
            fig = plt.figure(0, figsize=(4, 6))
            ax1 = fig.add_subplot(311)
            N1, bins1, pathch1 = ax1.hist(data_r, n_bins, histtype='bar', color='r')
            ax1.set_title('r0 hist')
        
            ax2 = fig.add_subplot(312)
            N2, bins2, pathch2 = ax2.hist(data_g, n_bins, histtype='bar', color='g')
            ax2.set_title('g0 hist')

            ax3 = fig.add_subplot(313)
            N3, bins3, pathch3 = ax3.hist(data_b, n_bins, histtype='bar', color='b')
            ax3.set_title('b0 hist')

            N_max_0 = np.max([N1.max(), N2.max(), N3.max()])
            ax1.set_ylim([0, N_max_0])
            ax1.set_xlim([0, 255])
            ax2.set_ylim([0, N_max_0])
            ax2.set_xlim([0, 255])
            ax3.set_ylim([0, N_max_0])
            ax3.set_xlim([0, 255])
            fig.tight_layout()
        
        if self.imageLabel1.paintEnd==True and self.imageLabel1.pixmap()!=None:            
            pos_1_0, pos_1_1 = QPointF(self.imageLabel1.paintCoordinates[0])/self.zoomList[self.zoomIdx], QPointF(self.imageLabel1.paintCoordinates[1])/self.zoomList[self.zoomIdx]
            x_1_0, x_1_1, y_1_0, y_1_1 = pos_1_0.x(), pos_1_1.x(), pos_1_0.y(), pos_1_1.y()
            if x_1_0 > x_1_1:
                x_1_0, x_1_1 = x_1_1, x_1_0
            if y_1_0 > y_1_1:
                y_1_0, y_1_1 = y_1_1, y_1_0
            data1 = cv.imread(self.opendFile1)
            if data1 is None:
                QMessageBox.information(self, 'information', 'can not open image %s'%self.opendFile1, QMessageBox.Ok)
                return
            data1_r = data1[int(y_1_0):int(y_1_1), int(x_1_0):int(x_1_1), 2].flatten()
            data1_g = data1[int(y_1_0):int(y_1_1), int(x_1_0):int(x_1_1), 1].flatten()
            data1_b = data1[int(y_1_0):int(y_1_1), int(x_1_0):int(x_1_1), 0].flatten()
            fig1 = plt.figure(1, figsize=(4, 6))
            ax1_1 = fig1.add_subplot(311)
            N1_1, bins1_1, pathch1_1 = ax1_1.hist(data1_r, n_bins, histtype='bar', color='r')
            ax1_1.set_title('r0 hist')
        
            ax1_2 = fig1.add_subplot(312)
            N1_2, bins1_2, pathch1_2 = ax1_2.hist(data1_g, n_bins, histtype='bar', color='g')
            ax1_2.set_title('g0 hist')

            ax1_3 = fig1.add_subplot(313)
            N1_3, bins1_3, pathch1_3 = ax1_3.hist(data1_b, n_bins, histtype='bar', color='b')
            ax1_3.set_title('b0 hist')

            N_max_1 = np.max([N1_1.max(), N1_2.max(), N1_3.max()])
            ax1_1.set_ylim([0, N_max_1])
            ax1_1.set_xlim([0, 255])
            ax1_2.set_ylim([0, N_max_1])
            ax1_2.set_xlim([0, 255])
            ax1_3.set_ylim([0, N_max_1])
            ax1_3.set_xlim([0, 255])
            fig1.tight_layout()
        if fig is None and fig1 is None:
            return
        plt.show()

        
    def __setPenBtnColor(self):        
        self.colorBtn.setStyleSheet('QPushButton{background:rgb(%d,%d,%d);border:none;}'%(self.penColor.red(), self.penColor.green(), self.penColor.blue()))

        
    def __selectColor(self):
        dlg = QColorDialog(self.penColor, self.toolBoxWidget)
        reply = dlg.exec_()
        if reply == QColorDialog.Accepted:
            self.penColor = dlg.selectedColor()
            self.__setPenBtnColor()
            self.imageLabel.setPaintPenColor(self.penColor)
            self.imageLabel1.setPaintPenColor(self.penColor)
        

    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'question', 'are you sure to quit?', QMessageBox.Yes|QMessageBox.No)
        if reply == QMessageBox.Yes:
            super().closeEvent(event)
        else:
            event.ignore()
            
    def onQuit(self):
        self.close()
    
    def onCloseAction(self):
        if self.imageLabel.pixmap()==None and self.imageLabel1.pixmap()==None:
            return
        self.imageLabel.clear()
        self.imageLabel.setText('drag image file to here!')
        self.imageLabel.adjustSize()
        self.imageLabel.paintBegin = False
        self.imageLabel.paintEnd = False
        self.imageLabel1.clear()
        self.imageLabel1.setText('drag image file to here!')
        self.imageLabel1.adjustSize()
        self.imageLabel1.paintBegin = False
        self.imageLabel1.paintEnd = False
        self.opendFile = ''
        self.opendFile1 = ''
        self.__setTitle()
        self.start_x_edit.setText('')
        self.start_y_edit.setText('')
        self.end_x_edit.setText('')
        self.end_y_edit.setText('')
        self.start_x_edit1.setText('')
        self.start_y_edit1.setText('')
        self.end_x_edit1.setText('')
        self.end_y_edit1.setText('')
        
    def onOpenFileAction(self):
        fileList = QFileDialog.getOpenFileNames(self, 'open', self.workPath, 'Images(*.jpg *.jpeg *.png *.bmp);;All file(*.*)')# type:list[str]
        if len(fileList)<=0 or len(fileList[0])<=0:
            return
        reader = QImageReader(fileList[0][0])
        reader.setAutoTransform(True)
        img = reader.read()
        if img.isNull():
            QMessageBox.information(self, 'error', 'can not open %s as image!'%fileList[0][0], QMessageBox.Ok)
            return
        self.opendFile = fileList[0][0]
        self.__setImage(img, self.zoomList[self.zoomIdx])
        if len(fileList[0])>=2:
            reader1 =QImageReader(fileList[0][1])
            reader1.setAutoTransform(True)
            img1 = reader1.read()
            if img1.isNull():
                QMessageBox.information(self, 'error', 'can not open %s as image!'%fileList[0][0], QMessageBox.Ok)
                return
            self.__setImage1(img1, self.zoomList[self.zoomIdx])
            self.opendFile1 = fileList[0][1]
        self.__setTitle()
        
    def __setTitle(self):
        if self.opendFile=='' and self.opendFile1=='':
            self.setWindowTitle('raw_image_data_visual')
        elif self.opendFile=='' or self.opendFile1=='':
            self.setWindowTitle(self.opendFile + self.opendFile1)
        else:
            self.setWindowTitle(self.opendFile +'<--->'+ self.opendFile1)
        
    def __setImage(self, image:QImage, factor:float):
        pixMap = QPixmap.fromImage(image)
        self.originSize = pixMap.size()
        self.imageLabel.paintBegin = False
        self.imageLabel.paintEnd = False
        self.imageLabel.setPixmap(pixMap)
        self.__adjustImgLabelSize_scrollbarPos()
        
    def __setImage1(self, image:QImage, factor:float):
        pixMap = QPixmap.fromImage(image)
        self.originSize1 = pixMap.size()
        self.imageLabel1.paintBegin = False
        self.imageLabel1.paintEnd = False
        self.imageLabel1.setPixmap(pixMap)
        self.__adjustImgLabelSize_scrollbarPos1()
    
    def zoomIn(self):
        if self.imageLabel.pixmap() == None or self.originSize == QSize(0, 0):
            return
        if(self.zoomIdx < len(self.zoomList)-1):
            self.zoomIdx = self.zoomIdx + 1
        else:
            return
        scale_ratio = self.zoomList[self.zoomIdx]
        if self.imageLabel.paintEnd == True:
            self.imageLabel.paintCoordinates[0] = QPointF(float(self.start_x_edit.text())*scale_ratio, float(self.start_y_edit.text())*scale_ratio)
            self.imageLabel.paintCoordinates[1] = QPointF(float(self.end_x_edit.text())*scale_ratio, float(self.end_y_edit.text())*scale_ratio)
        self.__adjustImgLabelSize_scrollbarPos()#缩放image label
        if self.imageLabel1.paintEnd == True:
            self.imageLabel1.paintCoordinates[0] = QPointF(float(self.start_x_edit1.text())*scale_ratio, float(self.start_y_edit1.text())*scale_ratio)
            self.imageLabel1.paintCoordinates[1] = QPointF(float(self.end_x_edit1.text())*scale_ratio, float(self.end_y_edit1.text())*scale_ratio)
        self.__adjustImgLabelSize_scrollbarPos1()#因为已经关联了另一个scrollbar,会自动调整
            
    def zoomOut(self):
        if self.imageLabel.pixmap() == None or self.originSize == QSize(0, 0):
            return
        if self.zoomIdx > 0:
            self.zoomIdx = self.zoomIdx - 1
        else:
            return
        scale_ratio = self.zoomList[self.zoomIdx]/self.zoomList[self.zoomIdx+1]
        if self.imageLabel.paintEnd == True:
            self.imageLabel.paintCoordinates[0] = self.imageLabel.paintCoordinates[0]*scale_ratio
            self.imageLabel.paintCoordinates[1] = self.imageLabel.paintCoordinates[1]*scale_ratio
        self.__adjustImgLabelSize_scrollbarPos()
        if self.imageLabel1.paintEnd == True:
            self.imageLabel1.paintCoordinates[0] = self.imageLabel1.paintCoordinates[0]*scale_ratio
            self.imageLabel1.paintCoordinates[1] = self.imageLabel1.paintCoordinates[1]*scale_ratio #缩放绘图
        self.__adjustImgLabelSize_scrollbarPos1()#缩放image label

            
    def __adjustImgLabelSize_scrollbarPos(self):
        self.imageLabel.resize(self.originSize*self.zoomList[self.zoomIdx])
        if self.scrollArea.horizontalScrollBar().maximum() - self.scrollArea.horizontalScrollBar().minimum() > 0:
            self.scrollArea.horizontalScrollBar().setValue((self.scrollArea.horizontalScrollBar().maximum() - self.scrollArea.horizontalScrollBar().minimum())//2)
        if self.scrollArea.verticalScrollBar().maximum() - self.scrollArea.verticalScrollBar().minimum() > 0:
            self.scrollArea.verticalScrollBar().setValue((self.scrollArea.verticalScrollBar().maximum() - self.scrollArea.verticalScrollBar().minimum())//2)
            
    def __adjustImgLabelSize_scrollbarPos1(self):
        self.imageLabel1.resize(self.originSize1*self.zoomList[self.zoomIdx])
        if self.scrollArea1.horizontalScrollBar().maximum() - self.scrollArea1.horizontalScrollBar().minimum() > 0:
            self.scrollArea1.horizontalScrollBar().setValue((self.scrollArea1.horizontalScrollBar().maximum() - self.scrollArea1.horizontalScrollBar().minimum())//2)
        if self.scrollArea1.verticalScrollBar().maximum() - self.scrollArea1.verticalScrollBar().minimum() > 0:
            self.scrollArea1.verticalScrollBar().setValue((self.scrollArea1.verticalScrollBar().maximum() - self.scrollArea1.verticalScrollBar().minimum())//2)
            
    def dragEnterEvent(self, event:QDragEnterEvent):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
        else:
            event.ignore()
        
    def dropEvent(self, event:QDropEvent):
        mainWidget_rect = self.mainWidget.geometry()
        dropPt = event.pos()
        if dropPt.x()<mainWidget_rect.left() or dropPt.x()>mainWidget_rect.right() or dropPt.y()<mainWidget_rect.top() or dropPt.y()>mainWidget_rect.bottom():
            return
        mData = event.mimeData()
        if not mData.hasUrls():
            return        
        urlList = mData.urls()
        if len(urlList)==1:
            scrollArea_rect = self.scrollArea.geometry().translated(mainWidget_rect.topLeft())
            scrollArea1_rect = self.scrollArea1.geometry().translated(mainWidget_rect.topLeft())
            if dropPt.x()>scrollArea_rect.left() and dropPt.x()<scrollArea_rect.right():
                fileName = urlList[0].toLocalFile()
                if len(fileName)<=0 or fileName==None:
                    return
                if fileName.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')):
                    reader = QImageReader(fileName)
                    reader.setAutoTransform(True)
                    img = reader.read()
                    if img.isNull():
                        QMessageBox.information(self, 'error', 'can not open %s as image!'%fileName, QMessageBox.Ok)
                        return
                    self.opendFile = fileName
                    self.__setTitle()
                    self.__setImage(img, self.zoomList[self.zoomIdx])
            elif dropPt.x()>scrollArea1_rect.left() and dropPt.x()<scrollArea1_rect.right():
                fileName = urlList[0].toLocalFile()
                if len(fileName)<=0 or fileName==None:
                    return
                if fileName.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')):
                    reader = QImageReader(fileName)
                    reader.setAutoTransform(True)
                    img = reader.read()
                    if img.isNull():
                        QMessageBox.information(self, 'error', 'can not open %s as image!'%fileName, QMessageBox.Ok)
                        return
                    self.opendFile1 = fileName
                    self.__setTitle()
                    self.__setImage1(img, self.zoomList[self.zoomIdx])
            else:
                pass
                    
        elif len(urlList)>=2:
            fileName = urlList[0].toLocalFile()
            fileName1 = urlList[1].toLocalFile()
            if len(fileName)<=0 or fileName==None or len(fileName1)<=0 or fileName1==None:
                return
            if fileName.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')) and fileName1.endswith(('.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.bmp', '.BMP')):
                reader = QImageReader(fileName)
                reader.setAutoTransform(True)
                img = reader.read()
                reader1 = QImageReader(fileName1)
                reader1.setAutoTransform(True)
                img1 = reader1.read()
                if img.isNull() or img1.isNull():
                    QMessageBox.information(self, 'error', 'can not open %s %sas image!'%(fileName, fileName1), QMessageBox.Ok)
                    return
                self.opendFile = fileName
                self.opendFile1 = fileName1
                self.__setTitle()
                self.__setImage(img, self.zoomList[self.zoomIdx])
                self.__setImage1(img1, self.zoomList[self.zoomIdx])
        else:
            pass
        
    def aboutQt_(self):
        QApplication.instance().aboutQt()
    
    def aboutThis(self):
        dlg = aboutDlg(self)
        dlg.exec_()
Esempio n. 2
0
class main_class(QWidget):
    def __init__(self):
        super().__init__()

        self.thread_subs = QThread()
        self.obj = thread_subtitles()
        self.obj.update_subtitles.connect(self.render_subtitles)
        self.obj.moveToThread(self.thread_subs)
        self.thread_subs.started.connect(self.obj.main)
        self.thread_subs.start()

        self.thread_translations = QThread()
        self.obj2 = thread_translations()
        self.obj2.get_translations.connect(self.render_popup)
        self.obj2.moveToThread(self.thread_translations)
        self.thread_translations.started.connect(self.obj2.main)
        self.thread_translations.start()

        # start the forms
        self.subtitles_base()
        self.subtitles_base2()
        self.popup_base()

    def clearLayout(self, layout):
        if layout == 'subs':
            layout = self.subtitles_vbox
            self.subtitles.hide()
        elif layout == 'subs2':
            layout = self.subtitles_vbox2
            self.subtitles2.hide()
        elif layout == 'popup':
            layout = self.popup_vbox
            self.popup.hide()

        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()

                if widget is not None:
                    widget.deleteLater()
                else:
                    self.clearLayout(item.layout())

    def subtitles_base(self):
        self.subtitles = QFrame()
        self.subtitles.setAttribute(Qt.WA_TranslucentBackground)
        self.subtitles.setWindowFlags(Qt.X11BypassWindowManagerHint)
        self.subtitles.setStyleSheet(config.style_subs)

        self.subtitles_vbox = QVBoxLayout(self.subtitles)
        self.subtitles_vbox.setSpacing(config.subs_padding_between_lines)
        self.subtitles_vbox.setContentsMargins(0, 0, 0, 0)

    def subtitles_base2(self):
        self.subtitles2 = QFrame()
        self.subtitles2.setAttribute(Qt.WA_TranslucentBackground)
        self.subtitles2.setWindowFlags(Qt.X11BypassWindowManagerHint)
        self.subtitles2.setStyleSheet(config.style_subs)

        self.subtitles_vbox2 = QVBoxLayout(self.subtitles2)
        self.subtitles_vbox2.setSpacing(config.subs_padding_between_lines)
        self.subtitles_vbox2.setContentsMargins(0, 0, 0, 0)

        if config.pause_during_translation_B:
            self.subtitles2.enterEvent = lambda event: [
                mpv_pause(),
                setattr(config, 'block_popup', False)
            ][0]
            self.subtitles2.leaveEvent = lambda event: [
                mpv_resume(),
                setattr(config, 'block_popup', True)
            ][0] if not config.avoid_resuming else [
                setattr(config, 'avoid_resuming', False),
                setattr(config, 'block_popup', True)
            ][0]

    def popup_base(self):
        self.popup = QFrame()
        self.popup.setAttribute(Qt.WA_TranslucentBackground)
        self.popup.setWindowFlags(Qt.X11BypassWindowManagerHint)
        self.popup.setStyleSheet(config.style_popup)

        self.popup_inner = QFrame()
        outer_box = QVBoxLayout(self.popup)
        outer_box.addWidget(self.popup_inner)

        self.popup_vbox = QVBoxLayout(self.popup_inner)
        self.popup_vbox.setSpacing(0)

    def render_subtitles(self, hide=False, redraw=False):
        if hide or not len(subs):
            try:
                self.subtitles.hide()
                self.subtitles2.hide()
            finally:
                return

        if redraw:
            self.subtitles.setStyleSheet(config.style_subs)
            self.subtitles2.setStyleSheet(config.style_subs)
        else:
            self.clearLayout('subs')
            self.clearLayout('subs2')

            if hasattr(self, 'popup'):
                self.popup.hide()

            # if subtitle consists of one overly long line - split into two
            if config.split_long_lines_B and len(
                    subs.split('\n')) == 1 and len(subs.split(
                        ' ')) > config.split_long_lines_words_min - 1:
                subs2 = split_long_lines(subs)
            else:
                subs2 = subs

            subs2 = re.sub(' +', ' ', subs2).strip()

            ##############################

            for line in subs2.split('\n'):
                line2 = ' %s ' % line.strip()
                ll = drawing_layer(line2, subs2)

                hbox = QHBoxLayout()
                hbox.setContentsMargins(0, 0, 0, 0)
                hbox.setSpacing(0)
                hbox.addStretch()
                hbox.addWidget(ll)
                hbox.addStretch()
                self.subtitles_vbox.addLayout(hbox)

                ####################################

                hbox = QHBoxLayout()
                hbox.setContentsMargins(0, 0, 0, 0)
                hbox.setSpacing(0)
                hbox.addStretch()

                if config.R2L_from_B:
                    line2 = line2[::-1]

                line2 += '\00'
                word = ''
                for smbl in line2:
                    if smbl.isalpha():
                        word += smbl
                    else:
                        if len(word):
                            if config.R2L_from_B:
                                word = word[::-1]

                            ll = events_class(word, subs2)
                            ll.mouseHover.connect(self.render_popup)
                            ll.redraw.connect(self.render_subtitles)

                            hbox.addWidget(ll)
                            word = ''

                        if smbl != '\00':
                            ll = events_class(smbl, subs2, skip=True)
                            hbox.addWidget(ll)

                hbox.addStretch()
                self.subtitles_vbox2.addLayout(hbox)

        self.subtitles.adjustSize()
        self.subtitles2.adjustSize()

        w = self.subtitles.geometry().width()
        h = self.subtitles.height = self.subtitles.geometry().height()

        x = (config.screen_width / 2) - (w / 2)

        if config.subs_top_placement_B:
            y = config.subs_screen_edge_padding
        else:
            y = config.screen_height - config.subs_screen_edge_padding - h

        self.subtitles.setGeometry(int(x), int(y), 0, 0)
        self.subtitles.show()

        self.subtitles2.setGeometry(int(x), int(y), 0, 0)
        self.subtitles2.show()

    def render_popup(self, text, x_cursor_pos, is_line):
        if text == '':
            if hasattr(self, 'popup'):
                self.popup.hide()
            return

        self.clearLayout('popup')

        if is_line:
            QApplication.setOverrideCursor(Qt.WaitCursor)

            line = globals()[config.translation_function_name_full_sentence](
                text)
            if config.translation_function_name_full_sentence == 'google':
                try:
                    line = line[0][0][0].strip()
                except:
                    line = 'Google translation failed.'

            if config.split_long_lines_B and len(
                    line.split('\n')) == 1 and len(line.split(
                        ' ')) > config.split_long_lines_words_min - 1:
                line = split_long_lines(line)

            ll = QLabel(line)
            ll.setObjectName("first_line")
            self.popup_vbox.addWidget(ll)
        else:
            word = text

            for translation_function_name_i, translation_function_name in enumerate(
                    config.translation_function_names):
                pairs, word_descr = globals()[translation_function_name](word)

                if not len(pairs):
                    pairs = [['', '[Not found]']]
                    #return

                # ~pairs = [ [ str(i) + ' ' + pair[0], pair[1] ] for i, pair in enumerate(pairs) ]

                if word in config.scroll:
                    if len(pairs[config.scroll[word]:]
                           ) > config.number_of_translations:
                        pairs = pairs[config.scroll[word]:]
                    else:
                        pairs = pairs[-config.number_of_translations:]
                        if len(config.translation_function_names) == 1:
                            config.scroll[word] -= 1

                for i1, pair in enumerate(pairs):
                    if i1 == config.number_of_translations:
                        break

                    if config.split_long_lines_in_popup_B:
                        pair[0] = split_long_lines(
                            pair[0],
                            max_symbols_per_line=config.
                            split_long_lines_in_popup_symbols_min)
                        pair[1] = split_long_lines(
                            pair[1],
                            max_symbols_per_line=config.
                            split_long_lines_in_popup_symbols_min)

                    if pair[0] == '-':
                        pair[0] = ''
                    if pair[1] == '-':
                        pair[1] = ''

                    # ~if config.R2L_from_B:
                    # ~pair[0] = pair[0][::-1]
                    # ~if config.R2L_to_B:
                    # ~pair[1] = pair[1][::-1]

                    if pair[0] != '':
                        # to emphasize the exact form of the word
                        # to ignore case on input and match it on output
                        chnks = re.split(word, pair[0], flags=re.I)
                        exct_words = re.findall(word, pair[0], flags=re.I)

                        hbox = QHBoxLayout()
                        hbox.setContentsMargins(0, 0, 0, 0)

                        for i2, chnk in enumerate(chnks):
                            if len(chnk):
                                ll = QLabel(chnk)
                                ll.setObjectName("first_line")
                                hbox.addWidget(ll)
                            if i2 + 1 < len(chnks):
                                ll = QLabel(exct_words[i2])
                                ll.setObjectName("first_line_emphasize_word")
                                hbox.addWidget(ll)

                        # filling the rest of the line with empty bg
                        ll = QLabel()
                        ll.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Preferred)
                        hbox.addWidget(ll)

                        self.popup_vbox.addLayout(hbox)

                    if pair[1] != '':
                        ll = QLabel(pair[1])
                        ll.setObjectName("second_line")
                        self.popup_vbox.addWidget(ll)

                        # padding
                        ll = QLabel()
                        ll.setStyleSheet("font-size: 6px;")
                        self.popup_vbox.addWidget(ll)

                if len(word_descr[0]):
                    ll = QLabel(word_descr[0])
                    ll.setProperty("morphology", word_descr[1])
                    ll.setAlignment(Qt.AlignRight)
                    self.popup_vbox.addWidget(ll)

                # delimiter between dictionaries
                if translation_function_name_i + 1 < len(
                        config.translation_function_names):
                    ll = QLabel()
                    ll.setObjectName("delimiter")
                    self.popup_vbox.addWidget(ll)

        self.popup_inner.adjustSize()
        self.popup.adjustSize()

        w = self.popup.geometry().width()
        h = self.popup.geometry().height()

        if w > config.screen_width:
            w = config.screen_width - 20

        if not is_line:
            if w < config.screen_width / 3:
                w = config.screen_width / 3

        if x_cursor_pos == -1:
            x = (config.screen_width / 2) - (w / 2)
        else:
            x = x_cursor_pos - w / 5
            if x + w > config.screen_width:
                x = config.screen_width - w

        if config.subs_top_placement_B:
            y = self.subtitles.height + config.subs_screen_edge_padding
        else:
            y = config.screen_height - config.subs_screen_edge_padding - self.subtitles.height - h

        self.popup.setGeometry(int(x), int(y), int(w), 0)
        self.popup.show()

        QApplication.restoreOverrideCursor()
Esempio n. 3
0
class MWindow(QFrame, MHierarchicalElement):
    def __init__(self, content, title):
        super().__init__()

        # if not (type(content) is MContainer):
        #     raise TypeError("Expected type %s, got %s" % (str(MContainer), type(content)))
        self.content = content
        content.setMouseTracking(True)
        self.setObjectName("main_m_window_frame")
        # Construct top-level window elements

        self.main_layout = QVBoxLayout()
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.main_layout)

        self.header_frame = MHeaderBar(self)
        self.header_frame.setTitle(title)

        self.main_layout.addWidget(self.header_frame)
        self.main_layout.addStretch(0)
        self.main_layout.addWidget(self.content)
        self.main_layout.setStretchFactor(self.content, 1)

        self.show()

        self.setStyleSheet(
            self.styleSheet() +
            "QFrame#main_m_window_frame{border: 2px solid black}\r\n"
            "QFrame#main_m_window_frame{background-color:rgb(120,120,130)}")

        self.drop_region_top_frame = QFrame(self)
        self.drop_region_left_frame = QFrame(self)
        self.drop_region_right_frame = QFrame(self)
        self.drop_region_bottom_frame = QFrame(self)
        self.drop_region_onto_frame = QFrame(self)

        self.drop_region_stylesheet = "background-color: rgba(50, 50, 150, 0);"
        self.drop_region_focused_stylesheet = "background-color: rgba(50, 50, 80, 100);" \
                                 "border: 2px solid grey"

        self.drop_region_top_frame.setStyleSheet(self.drop_region_stylesheet)
        self.drop_region_left_frame.setStyleSheet(self.drop_region_stylesheet)
        self.drop_region_right_frame.setStyleSheet(self.drop_region_stylesheet)
        self.drop_region_bottom_frame.setStyleSheet(
            self.drop_region_stylesheet)
        self.drop_region_onto_frame.setStyleSheet(self.drop_region_stylesheet)

        self.drop_regions = {
            "top": self.drop_region_top_frame,
            "left": self.drop_region_left_frame,
            "right": self.drop_region_right_frame,
            "bottom": self.drop_region_bottom_frame,
            "onto": self.drop_region_onto_frame
        }
        self.setMinimumHeight(24)
        self.setMinimumWidth(128)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.uid = None

    def get_content(self):
        return self.content

    def set_title(self, title):
        self.header_frame.setTitle(title)

    def get_title(self):
        return self.header_frame.getTitle()

    def show_drop_regions(self):
        window_geometry = self.geometry()

        self.drop_region_top_frame.setGeometry(0, 0, window_geometry.width(),
                                               window_geometry.height() / 5)

        self.drop_region_left_frame.setGeometry(0, 0,
                                                window_geometry.width() / 5,
                                                window_geometry.height())

        self.drop_region_right_frame.setGeometry(
            4 * window_geometry.width() / 5, 0,
            window_geometry.width() / 5, window_geometry.height())

        self.drop_region_bottom_frame.setGeometry(
            0, 4 * window_geometry.height() / 5, window_geometry.width(),
            window_geometry.height() / 5)

        self.drop_region_onto_frame.setGeometry(
            1 * window_geometry.width() / 3, 1 * window_geometry.height() / 3,
            window_geometry.width() / 3,
            window_geometry.height() / 3)

        self.drop_region_top_frame.show()
        self.drop_region_left_frame.show()
        self.drop_region_right_frame.show()
        self.drop_region_bottom_frame.show()
        self.drop_region_onto_frame.show()

        self.drop_region_top_frame.raise_()
        self.drop_region_top_frame.updateGeometry()

    def hide_drop_regions(self):
        #print("hiding drop regions of", str(self))
        for child in self.child_containers:
            child.hide_drop_regions()
        self.drop_region_top_frame.hide()
        self.drop_region_left_frame.hide()
        self.drop_region_right_frame.hide()
        self.drop_region_bottom_frame.hide()
        self.drop_region_onto_frame.hide()

    def over_drop_regions(self, pos):

        if self.drop_region_top_frame.geometry().contains(
                self.mapFromGlobal(pos)):
            return self.drop_region_top_frame
        elif self.drop_region_left_frame.geometry().contains(
                self.mapFromGlobal(pos)):
            return self.drop_region_left_frame
        elif self.drop_region_right_frame.geometry().contains(
                self.mapFromGlobal(pos)):
            return self.drop_region_right_frame
        elif self.drop_region_bottom_frame.geometry().contains(
                self.mapFromGlobal(pos)):
            return self.drop_region_bottom_frame
        elif self.drop_region_onto_frame.geometry().contains(
                self.mapFromGlobal(pos)):
            return self.drop_region_onto_frame
        else:
            return None

    def focus_drop_region(self, pos):
        active_region = self.over_drop_regions(pos)
        for drop_region in self.drop_regions.values():
            if drop_region is active_region:
                drop_region.setStyleSheet(self.drop_region_focused_stylesheet)
            else:
                drop_region.setStyleSheet(self.drop_region_stylesheet)

    def get_drop_region(self, key):
        return self.drop_regions[key]

    def __str__(self):
        return self.get_title()