

import sys
import re
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QSize, Qt
from PyQt5.Qt import *
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QHBoxLayout, QAbstractItemView, QVBoxLayout, QSplitter, \
    QApplication, QLabel, QGridLayout, QLineEdit, QComboBox, QTextEdit, QCheckBox,QVBoxLayout,QListView, QMainWindow, QStackedWidget, QMessageBox
from PyQt5.QtWidgets import QSizePolicy, QWidget

from ctypes import POINTER, cast
from ctypes.wintypes import MSG


from PyQt5.QtWinExtras import QtWin

from win32 import win32api, win32gui
from win32.lib import win32con
from windoweffect.window_effect import WindowEffect
from windoweffect.c_structures import MINMAXINFO, NCCALCSIZE_PARAMS
from utils.DBModels.DeviceModels import DeviceDB



class DeviceDialog(QDialog):
    BORDER_WIDTH = 5 #设圆角

    def __init__(self,dataTypeAndModel = None, parent=None):
        super().__init__(parent)
        self.dataTypeAndModel = dataTypeAndModel
        self.initUI()

    def initUI(self):
        self.resize(306, 451)

        self.setObjectName('deviceDialog')
        self.deviceNameEdit = QLineEdit()
        self.deviceNameEdit.setPlaceholderText("设备名称")
        self.deviceNameEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        self.deviceNameEdit.setObjectName('deviceMesEdit')

        self.pvUpperEdit = QLineEdit()
        self.pvUpperEdit.setPlaceholderText("量程上限")
        self.pvUpperEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        self.pvUpperEdit.setObjectName('deviceMesEdit')

        self.pvLowerEdit = QLineEdit()
        self.pvLowerEdit.setPlaceholderText("量程下限")
        self.pvLowerEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        self.pvLowerEdit.setObjectName('deviceMesEdit')

        self.pvUnitEdit = QLineEdit()
        self.pvUnitEdit.setPlaceholderText("单位")
        self.pvUnitEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        self.pvUnitEdit.setObjectName('deviceMesEdit')



        self.confirmButton = QPushButton('确定')
        self.confirmButton.setObjectName('confirmButton')
        self.confirmButton.clicked.connect(self.checkInput)
        enterShortcut = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self)
        enterShortcut.activated.connect(self.confirmButton.click)


        self.exitButton = QPushButton('取消')
        self.exitButton.clicked.connect(self.close)
        self.exitButton.setObjectName('exitButton')

        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.addWidget(self.confirmButton)
        self.horizontalLayout.addWidget(self.exitButton)
        self.horizontalLayout.setSpacing(10)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)

        self.verticalLayout = QVBoxLayout(self)

        self.conVerLayout = QVBoxLayout()
        self.conVerLayout.addWidget(QWidget(), 1)
        self.conVerLayout.addWidget(self.deviceNameEdit, 1)
        self.conVerLayout.addWidget(self.pvUpperEdit, 1)
        self.conVerLayout.addWidget(self.pvLowerEdit, 1)
        self.conVerLayout.addWidget(self.pvUnitEdit, 1)
        self.conVerLayout.addLayout(self.horizontalLayout, 1)
        self.conVerLayout.setSpacing(32)
        self.conVerLayout.setContentsMargins(34, 26, 34, 50)

        # self.verticalLayout.addWidget(self.picLabel)
        self.verticalLayout.addLayout(self.conVerLayout)

        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(self.verticalLayout)

        # 设置模态窗口
        self.setWindowFlags(self.windowFlags() | Qt.Window)
        self.setWindowModality(Qt.ApplicationModal)

        self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowSystemMenuHint) 
        self.SHADOW_WIDTH = 0  #边框距离 
        self.isLeftPressDown = False #鼠标左键是否按下 
        self.dragPosition = 0   #拖动时坐标 
        self.padding = 4
        self.Numbers = self.enum(UP=0, DOWN=1, LEFT=2, RIGHT=3, LEFTTOP=4, LEFTBOTTOM=5, RIGHTBOTTOM=6, RIGHTTOP=7, NONE=8) #枚举参数 
        self.setMinimumHeight(451) #窗体最小高度 
        self.setMinimumWidth(306) #窗体最小宽度 
        self.dir = self.Numbers.NONE #初始鼠标状态

        #开启鼠标追踪
        self.setMouseTracking(True)

        #初始化接口
        self.windowEffect = WindowEffect()

        # 添加DWM阴影效果
        self.windowEffect.addWindowAnimation(self.winId())
        self.windowEffect.addShadowEffect(self.winId())

        # 解决报错
        self.windowHandle().screenChanged.connect(self.__onScreenChanged)
        self.setWindowOpacity(0.995) # 设置窗口透明度
        self.setWindowFlag(Qt.FramelessWindowHint)

    def getParameters(self):
        deviceName = self.deviceNameEdit.text() + self.dataTypeAndModel
        pvUpperLimit = self.pvUpperEdit.text()
        pvLowerLimit = self.pvLowerEdit.text()
        pvUnit = self.pvUnitEdit.text()
        return deviceName,  pvUpperLimit, pvLowerLimit, pvUnit


        

    def checkInput(self):

        deviceName, pvUpperLimit, pvLowerLimit, pvUnit = self.getParameters() 

        if not pvUpperLimit and not pvLowerLimit and not pvUnit:
           pass
        else:
            if not pvUpperLimit or not pvLowerLimit or not pvUnit:
                QMessageBox.warning(self, '警告', '有值未输入。')
                return
            if not re.match(r'^[-+]?\d*\.?\d*$', pvUpperLimit) or not re.match(r'^[-+]?\d*\.?\d*$', pvLowerLimit):
                QMessageBox.warning(self, '警告', '请输入数字。')
                return
            if float(pvUpperLimit) <= float(pvLowerLimit):
                QMessageBox.warning(self, '警告', '量程输入有误。')
                return

        if not deviceName:
            QMessageBox.warning(self, '警告', '请输入设备名。')
            return
        
        elif DeviceDB.getByName(deviceName):
            # print(DeviceDB.getByName(deviceName),2343)
            QMessageBox.warning(self, '警告', '设备名重复')
            return
        else:
            self.accept() # 所有输入都是数字且不为空时接受对话框



    def enum(self,**enums): 
        return type('Enum', (), enums) 
     
    def region(self,cursorGlobalPoint): 
        #获取窗体在屏幕上的位置区域，tl为topleft点，rb为rightbottom点 
        rect = self.rect() 
        tl = self.mapToGlobal(rect.topLeft()) 
        rb = self.mapToGlobal(rect.bottomRight()) 
     
        x = cursorGlobalPoint.x() 
        y = cursorGlobalPoint.y() 
     
        if(tl.x() + self.padding >= x and tl.x() <= x and tl.y() + self.padding >= y and tl.y() <= y): 
          #左上角 
            self.dir = self.Numbers.LEFTTOP 
            self.setCursor(QCursor(Qt.SizeFDiagCursor))  #设置鼠标形状 
        elif(x >= rb.x() - self.padding and x <= rb.x() and y >= rb.y() - self.padding and y <= rb.y()): 
          #右下角 
            self.dir = self.Numbers.RIGHTBOTTOM 
            self.setCursor(QCursor(Qt.SizeFDiagCursor)) 
        elif(x <= tl.x() + self.padding and x >= tl.x() and y >= rb.y() - self.padding and y <= rb.y()): 
          #左下角 
            self.dir = self.Numbers.LEFTBOTTOM 
            self.setCursor(QCursor(Qt.SizeBDiagCursor)) 
        elif(x <= rb.x() and x >= rb.x() - self.padding and y >= tl.y() and y <= tl.y() + self.padding): 
          #右上角 
            self.dir = self.Numbers.RIGHTTOP 
            self.setCursor(QCursor(Qt.SizeBDiagCursor)) 
        elif(x <= tl.x() + self.padding and x >= tl.x()): 
          #左边 
            self.dir = self.Numbers.LEFT 
            self.setCursor(QCursor(Qt.SizeHorCursor)) 
        elif( x <= rb.x() and x >= rb.x() - self.padding): 
          #右边 
     
            self.dir = self.Numbers.RIGHT 
            self.setCursor(QCursor(Qt.SizeHorCursor)) 
        elif(y >= tl.y() and y <= tl.y() + self.padding): 
          #上边 
            self.dir = self.Numbers.UP 
            self.setCursor(QCursor(Qt.SizeVerCursor)) 
        elif(y <= rb.y() and y >= rb.y() - self.padding): 
          #下边 
            self.dir = self.Numbers.DOWN 
            self.setCursor(QCursor(Qt.SizeVerCursor)) 
        else: 
          #默认 
            self.dir = self.Numbers.NONE 
            self.setCursor(QCursor(Qt.ArrowCursor)) 
     
    def mouseReleaseEvent(self,event): 
        if(event.button() == Qt.LeftButton): 
            self.isLeftPressDown = False 
            if(self.dir != self.Numbers.NONE): 
                self.releaseMouse() 
                self.setCursor(QCursor(Qt.ArrowCursor)) 
     
    def mousePressEvent(self,event): 
        if(event.button()==Qt.LeftButton): 
            self.isLeftPressDown=True 
            if(self.dir != self.Numbers.NONE): 
                self.mouseGrabber() 
            else: 
                self.dragPosition = event.globalPos() - self.frameGeometry().topLeft() 
 
    def mouseMoveEvent(self,event): 
        gloPoint = event.globalPos() 
        rect = self.rect() 
        tl = self.mapToGlobal(rect.topLeft()) 
        rb = self.mapToGlobal(rect.bottomRight()) 
     
        if(not self.isLeftPressDown): 
          self.region(gloPoint)  
        else: 
            if(self.dir != self.Numbers.NONE): 
                rmove=QRect(tl, rb) 
                if(self.dir==self.Numbers.LEFT): 
                    if(rb.x() - gloPoint.x() <= self.minimumWidth()): 
                        rmove.setX(tl.x()) 
                    else: 
                        rmove.setX(gloPoint.x()) 
                elif(self.dir==self.Numbers.RIGHT): 
                    rmove.setWidth(gloPoint.x() - tl.x()) 
                elif(self.dir==self.Numbers.UP): 
                    if(rb.y() - gloPoint.y() <= self.minimumHeight()): 
                        rmove.setY(tl.y()) 
                    else: 
                        rmove.setY(gloPoint.y()) 
                elif(self.dir==self.Numbers.DOWN): 
                    rmove.setHeight(gloPoint.y() - tl.y()) 
                elif(self.dir==self.Numbers.LEFTTOP): 
                    if(rb.x() - gloPoint.x() <= self.minimumWidth()): 
                        rmove.setX(tl.x()) 
                    else: 
                        rmove.setX(gloPoint.x()) 
                    if(rb.y() - gloPoint.y() <= self.minimumHeight()): 
                        rmove.setY(tl.y()) 
                    else: 
                        rmove.setY(gloPoint.y()) 
                elif(self.dir==self.Numbers.RIGHTTOP): 
                    rmove.setWidth(gloPoint.x() - tl.x()) 
                    rmove.setY(gloPoint.y()) 
                elif(self.dir==self.Numbers.LEFTBOTTOM): 
                    rmove.setX(gloPoint.x()) 
                    rmove.setHeight(gloPoint.y() - tl.y()) 
                elif(self.dir==self.Numbers.RIGHTBOTTOM): 
                    rmove.setWidth(gloPoint.x() - tl.x()) 
                    rmove.setHeight(gloPoint.y() - tl.y()) 
                else: 
                    pass 
                self.setGeometry(rmove) 
            else: 
                self.move(event.globalPos() - self.dragPosition) 
                event.accept() 

    def nativeEvent(self, eventType, message):
        """ 接受windows发送的信息 """
        msg = MSG.from_address(message.__int__())
        if msg.message == win32con.WM_NCHITTEST:
            # 解决 issue #2 and issue #7
            r = self.devicePixelRatioF()
            xPos = (win32api.LOWORD(msg.lParam) -
                    self.frameGeometry().x()*r) % 65536
            yPos = win32api.HIWORD(msg.lParam) - self.frameGeometry().y()*r
            w, h = self.width()*r, self.height()*r
            lx = xPos < self.BORDER_WIDTH
            rx = xPos + 9 > w - self.BORDER_WIDTH
            ty = yPos < self.BORDER_WIDTH
            by = yPos > h - self.BORDER_WIDTH
            if lx and ty:
                return True, win32con.HTTOPLEFT
            elif rx and by:
                return True, win32con.HTBOTTOMRIGHT
            elif rx and ty:
                return True, win32con.HTTOPRIGHT
            elif lx and by:
                return True, win32con.HTBOTTOMLEFT
            elif ty:
                return True, win32con.HTTOP
            elif by:
                return True, win32con.HTBOTTOM
            elif lx:
                return True, win32con.HTLEFT
            elif rx:
                return True, win32con.HTRIGHT
        elif msg.message == win32con.WM_NCCALCSIZE:
            if self.__isWindowMaximized(msg.hWnd):
                self.__monitorNCCALCSIZE(msg)
            return True, 0
        elif msg.message == win32con.WM_GETMINMAXINFO:
            if self.__isWindowMaximized(msg.hWnd):
                window_rect = win32gui.GetWindowRect(msg.hWnd)
                if not window_rect:
                    return False, 0

                # get the monitor handle
                monitor = win32api.MonitorFromRect(window_rect)
                if not monitor:
                    return False, 0

                # get the monitor info
                __monitorInfo = win32api.GetMonitorInfo(monitor)
                monitor_rect = __monitorInfo['Monitor']
                work_area = __monitorInfo['Work']

                # convert lParam to MINMAXINFO pointer
                info = cast(msg.lParam, POINTER(MINMAXINFO)).contents

                # adjust the size of window
                info.ptMaxSize.x = work_area[2] - work_area[0]
                info.ptMaxSize.y = work_area[3] - work_area[1]
                info.ptMaxTrackSize.x = info.ptMaxSize.x
                info.ptMaxTrackSize.y = info.ptMaxSize.y

                # modify the upper left coordinate
                info.ptMaxPosition.x = abs(window_rect[0] - monitor_rect[0])
                info.ptMaxPosition.y = abs(window_rect[1] - monitor_rect[1])
                return True, 1

        return QWidget.nativeEvent(self, eventType, message)


    def __isWindowMaximized(self, hWnd) -> bool:
        """ Determine whether the window is maximized """
        # GetWindowPlacement() returns the display state of the window and the restored,
        # maximized and minimized window position. The return value is tuple
        windowPlacement = win32gui.GetWindowPlacement(hWnd)
        if not windowPlacement:
            return False

        return windowPlacement[1] == win32con.SW_MAXIMIZE

    def __monitorNCCALCSIZE(self, msg: MSG):
        """ 调整窗口大小 """
        monitor = win32api.MonitorFromWindow(msg.hWnd)

        # If the display information is not saved, return directly
        if monitor is None and not self.__monitorInfo:
            return
        elif monitor is not None:
            self.__monitorInfo = win32api.GetMonitorInfo(monitor)

        # adjust the size of window
        params = cast(msg.lParam, POINTER(NCCALCSIZE_PARAMS)).contents
        params.rgrc[0].left = self.__monitorInfo['Work'][0]
        params.rgrc[0].top = self.__monitorInfo['Work'][1]
        params.rgrc[0].right = self.__monitorInfo['Work'][2]
        params.rgrc[0].bottom = self.__monitorInfo['Work'][3]

    def __onScreenChanged(self):
        hWnd = int(self.windowHandle().winId())
        win32gui.SetWindowPos(hWnd, None, 0, 0, 0, 0, win32con.SWP_NOMOVE |
                              win32con.SWP_NOSIZE | win32con.SWP_FRAMECHANGED)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle(QtWidgets.QStyleFactory.create('Fusion'))
    # print(QtWidgets.QStyleFactory.keys())
    ex = LoginWidget()
    ex.show()
    sys.exit(app.exec_())