From c9d6197c0ec1faeefffdc16e2e6746f84f7e9478 Mon Sep 17 00:00:00 2001 From: "amaork@Home_WIN7" Date: Tue, 8 Mar 2022 22:42:48 +0800 Subject: [PATCH] migrate to PySide2, move core.uimailbox ==> gui.mailbox --- chart/PyAppFramework.html | 314 ------------------ chart/PyAppFramework.png | Bin 3311 -> 0 bytes chart/PyAppFramework.xmind | Bin 171313 -> 0 bytes .../images/BaseButton 2.jpg | Bin 2983 -> 0 bytes .../images/BaseButton.jpg | Bin 2983 -> 0 bytes .../images/BasicDataType 2.jpg | Bin 2640 -> 0 bytes .../images/BasicDataType.jpg | Bin 2640 -> 0 bytes .../images/ColorWidget 2.jpg | Bin 2294 -> 0 bytes .../images/ColorWidget.jpg | Bin 2294 -> 0 bytes .../images/PaintWidget 2.jpg | Bin 3999 -> 0 bytes .../images/PaintWidget.jpg | Bin 3999 -> 0 bytes .../images/PyAppFramework 2.jpg | Bin 3263 -> 0 bytes .../images/PyAppFramework.jpg | Bin 3263 -> 0 bytes .../images/RectButton 2.jpg | Bin 1879 -> 0 bytes .../images/RectButton.jpg | Bin 1879 -> 0 bytes .../images/RoundButton 2.jpg | Bin 2035 -> 0 bytes .../images/RoundButton.jpg | Bin 2035 -> 0 bytes .../images/SerialPortProtocolSimulate.jpg | Bin 4790 -> 0 bytes .../PyAppFramework_files/images/binder 2.jpg | Bin 2702 -> 0 bytes chart/PyAppFramework_files/images/binder.jpg | Bin 2702 -> 0 bytes .../PyAppFramework_files/images/button 2.jpg | Bin 1558 -> 0 bytes chart/PyAppFramework_files/images/button.jpg | Bin 1558 -> 0 bytes .../images/container 2.jpg | Bin 3199 -> 0 bytes .../PyAppFramework_files/images/container.jpg | Bin 3199 -> 0 bytes chart/PyAppFramework_files/images/core 2.jpg | Bin 2640 -> 0 bytes chart/PyAppFramework_files/images/core.jpg | Bin 2159 -> 0 bytes .../images/datatype 2.jpg | Bin 6075 -> 0 bytes .../PyAppFramework_files/images/datatype.jpg | Bin 4911 -> 0 bytes .../PyAppFramework_files/images/dialog 2.jpg | Bin 3736 -> 0 bytes chart/PyAppFramework_files/images/dialog.jpg | Bin 1925 -> 0 bytes chart/PyAppFramework_files/images/ftp 2.jpg | Bin 1121 -> 0 bytes chart/PyAppFramework_files/images/ftp.jpg | Bin 1121 -> 0 bytes chart/PyAppFramework_files/images/gui 2.jpg | Bin 3975 -> 0 bytes chart/PyAppFramework_files/images/gui.jpg | Bin 3748 -> 0 bytes chart/PyAppFramework_files/images/misc 2.jpg | Bin 4103 -> 0 bytes chart/PyAppFramework_files/images/misc 3.jpg | Bin 2724 -> 0 bytes chart/PyAppFramework_files/images/misc.jpg | Bin 1983 -> 0 bytes .../PyAppFramework_files/images/msgbox 2.jpg | Bin 3174 -> 0 bytes chart/PyAppFramework_files/images/msgbox.jpg | Bin 3174 -> 0 bytes chart/PyAppFramework_files/images/process.jpg | Bin 3177 -> 0 bytes .../images/protocol 2.jpg | Bin 3240 -> 0 bytes .../PyAppFramework_files/images/protocol.jpg | Bin 3161 -> 0 bytes .../images/serialport.jpg | Bin 6113 -> 0 bytes chart/PyAppFramework_files/images/setup 2.jpg | Bin 4844 -> 0 bytes chart/PyAppFramework_files/images/setup.jpg | Bin 4844 -> 0 bytes .../images/showMessageBox 2.jpg | Bin 3045 -> 0 bytes .../images/showMessageBox.jpg | Bin 3045 -> 0 bytes .../PyAppFramework_files/images/stransfer.jpg | Bin 1803 -> 0 bytes .../images/tarmanager 2.jpg | Bin 1969 -> 0 bytes .../images/tarmanager.jpg | Bin 1969 -> 0 bytes chart/PyAppFramework_files/images/timer.jpg | Bin 2585 -> 0 bytes .../images/uimailbox 2.jpg | Bin 4875 -> 0 bytes .../PyAppFramework_files/images/uimailbox.jpg | Bin 4875 -> 0 bytes .../PyAppFramework_files/images/upgrade 2.jpg | Bin 3414 -> 0 bytes chart/PyAppFramework_files/images/upgrade.jpg | Bin 3060 -> 0 bytes .../PyAppFramework_files/images/widget 2.jpg | Bin 3878 -> 0 bytes chart/PyAppFramework_files/images/widget.jpg | Bin 3187 -> 0 bytes core/__init__.py | 2 +- core/database.py | 16 +- core/timer.py | 10 +- dashboard/input.py | 46 ++- dashboard/monitor.py | 13 +- dashboard/status.py | 7 +- demos/binder_demo.py | 4 +- demos/button_demo.py | 7 +- demos/checkbox_demo.py | 8 +- demos/container_demo.py | 2 +- demos/dashboard_input_test.py | 6 +- demos/dialog_demo.py | 7 +- demos/event_filter_test.py | 9 +- demos/monitor_demo.py | 4 +- demos/msgbox_demo.py | 4 +- demos/serial_transfer_test.py | 3 +- demos/setup_test.py | 1 - demos/status_demo.py | 6 +- demos/tabbar_demo.py | 5 +- demos/tarmanager_test.py | 1 - demos/widget_demo.py | 17 +- gui/__init__.py | 2 +- gui/binder.py | 5 +- gui/button.py | 11 +- gui/checkbox.py | 9 +- gui/container.py | 19 +- gui/dialog.py | 69 ++-- gui/icon.py | 5 +- core/uimailbox.py => gui/mailbox.py | 24 +- gui/misc.py | 34 +- gui/msgbox.py | 21 +- gui/srm.py | 26 +- gui/view.py | 23 +- gui/widget.py | 184 +++++++--- media/image.py | 4 +- misc/__init__.py | 2 +- misc/crypto.py | 2 +- misc/process.py | 2 +- misc/settings.py | 12 +- misc/tarmanager.py | 6 +- misc/windpi.py | 18 +- network/gogs_request.py | 4 +- network/netsh.py | 2 +- network/utility.py | 2 +- protocol/__init__.py | 2 +- protocol/ftp.py | 14 +- protocol/protobuf.py | 4 +- protocol/rmi_shell.py | 2 +- protocol/serialport.py | 6 +- protocol/upgrade.py | 16 +- requments.txt | 25 ++ tests/crypto_test.py | 2 +- 109 files changed, 475 insertions(+), 574 deletions(-) delete mode 100644 chart/PyAppFramework.html delete mode 100644 chart/PyAppFramework.png delete mode 100644 chart/PyAppFramework.xmind delete mode 100644 chart/PyAppFramework_files/images/BaseButton 2.jpg delete mode 100644 chart/PyAppFramework_files/images/BaseButton.jpg delete mode 100644 chart/PyAppFramework_files/images/BasicDataType 2.jpg delete mode 100644 chart/PyAppFramework_files/images/BasicDataType.jpg delete mode 100644 chart/PyAppFramework_files/images/ColorWidget 2.jpg delete mode 100644 chart/PyAppFramework_files/images/ColorWidget.jpg delete mode 100644 chart/PyAppFramework_files/images/PaintWidget 2.jpg delete mode 100644 chart/PyAppFramework_files/images/PaintWidget.jpg delete mode 100644 chart/PyAppFramework_files/images/PyAppFramework 2.jpg delete mode 100644 chart/PyAppFramework_files/images/PyAppFramework.jpg delete mode 100644 chart/PyAppFramework_files/images/RectButton 2.jpg delete mode 100644 chart/PyAppFramework_files/images/RectButton.jpg delete mode 100644 chart/PyAppFramework_files/images/RoundButton 2.jpg delete mode 100644 chart/PyAppFramework_files/images/RoundButton.jpg delete mode 100644 chart/PyAppFramework_files/images/SerialPortProtocolSimulate.jpg delete mode 100644 chart/PyAppFramework_files/images/binder 2.jpg delete mode 100644 chart/PyAppFramework_files/images/binder.jpg delete mode 100644 chart/PyAppFramework_files/images/button 2.jpg delete mode 100644 chart/PyAppFramework_files/images/button.jpg delete mode 100644 chart/PyAppFramework_files/images/container 2.jpg delete mode 100644 chart/PyAppFramework_files/images/container.jpg delete mode 100644 chart/PyAppFramework_files/images/core 2.jpg delete mode 100644 chart/PyAppFramework_files/images/core.jpg delete mode 100644 chart/PyAppFramework_files/images/datatype 2.jpg delete mode 100644 chart/PyAppFramework_files/images/datatype.jpg delete mode 100644 chart/PyAppFramework_files/images/dialog 2.jpg delete mode 100644 chart/PyAppFramework_files/images/dialog.jpg delete mode 100644 chart/PyAppFramework_files/images/ftp 2.jpg delete mode 100644 chart/PyAppFramework_files/images/ftp.jpg delete mode 100644 chart/PyAppFramework_files/images/gui 2.jpg delete mode 100644 chart/PyAppFramework_files/images/gui.jpg delete mode 100644 chart/PyAppFramework_files/images/misc 2.jpg delete mode 100644 chart/PyAppFramework_files/images/misc 3.jpg delete mode 100644 chart/PyAppFramework_files/images/misc.jpg delete mode 100644 chart/PyAppFramework_files/images/msgbox 2.jpg delete mode 100644 chart/PyAppFramework_files/images/msgbox.jpg delete mode 100644 chart/PyAppFramework_files/images/process.jpg delete mode 100644 chart/PyAppFramework_files/images/protocol 2.jpg delete mode 100644 chart/PyAppFramework_files/images/protocol.jpg delete mode 100644 chart/PyAppFramework_files/images/serialport.jpg delete mode 100644 chart/PyAppFramework_files/images/setup 2.jpg delete mode 100644 chart/PyAppFramework_files/images/setup.jpg delete mode 100644 chart/PyAppFramework_files/images/showMessageBox 2.jpg delete mode 100644 chart/PyAppFramework_files/images/showMessageBox.jpg delete mode 100644 chart/PyAppFramework_files/images/stransfer.jpg delete mode 100644 chart/PyAppFramework_files/images/tarmanager 2.jpg delete mode 100644 chart/PyAppFramework_files/images/tarmanager.jpg delete mode 100644 chart/PyAppFramework_files/images/timer.jpg delete mode 100644 chart/PyAppFramework_files/images/uimailbox 2.jpg delete mode 100644 chart/PyAppFramework_files/images/uimailbox.jpg delete mode 100644 chart/PyAppFramework_files/images/upgrade 2.jpg delete mode 100644 chart/PyAppFramework_files/images/upgrade.jpg delete mode 100644 chart/PyAppFramework_files/images/widget 2.jpg delete mode 100644 chart/PyAppFramework_files/images/widget.jpg rename core/uimailbox.py => gui/mailbox.py (93%) create mode 100644 requments.txt diff --git a/chart/PyAppFramework.html b/chart/PyAppFramework.html deleted file mode 100644 index c00ba5a..0000000 --- a/chart/PyAppFramework.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - -PyAppFramework - - -

-PyAppFramework -

-
-
-

-gui -

-
-
-

- button -

-
-
-

-  BaseButton -

-
-
-

-   IconButton -

-

-   TextButton -

-

-   RectButton -

-
-
-

-    RoundButton -

-
-
-

-     StatusButton -

-

- binder -

-
-
-

-  ComboBoxBinder -

-

-  SpinBoxBinder -

-

- container -

-
-
-

-  ComboBoxGroup -

-

-  ComponentManager -

-

- msgbox -

-
-
-

-  showMessageBox -

-
-
-

-   info -

-

-   error -

-

-   warning -

-

-  showQuestionBox -

-

- widget -

-
-
-

-  PaintWidget -

-
-
-

-   ColorWidget -

-
-
-

-    CursorWidget -

-

-   ImageWidget -

-

-   LumWidget -

-

-   RgbWidget -

-

-  ListWidget -

-

-  TableWidget -

-

-  SerialPortSettingWidget -

-

- dialog -

-
-
-

-  SimpleColorDialog -

-

-  SerialPortSettingDialog -

-

-  ProgressDialog -

-

- misc -

-
-
-

-  TabBar -

-

-  SerialPortSelector -

-

-core -

-
-
-

- datatype -

-
-
-

-  str2float -

-

-  str2number -

-

-  new_class -

-

-  new_instance -

-

-  ip4_check -

-

-  BasicDataType -

-
-
-

-   BasicTypeLE -

-

-   BasicTypeBE -

-

-  DynamicObject -

-

-  ComparableXml -

-

- uimailbox -

-
-
-

-  UiMailBox -

-

-  StatusBarMail -

-

-  MessageBoxMail -

-

-  WindowsTitleMail -

-

-  CallbackFuncMail -

-

- timer -

-
-
-

-  SwTimer -

-

-misc -

-
-
-

- tarmanager -

-
-
-

-  TarManager -

-

- setup -

-
-
-

-  get_git_release_date -

-

-  get_git_release_hash -

-

-  get_git_commit_count -

-

-  py2exe_clear_setup -

-

-  py2exe_setup_module -

-

- process -

-
-
-

-  ProcessManager -

-

-protocol -

-
-
-

- crc16 -

-

- ftp -

-
-
-

-  FTPClient -

-

- serialport -

-
-
-

-  SerialTransferProtocol -

-

-  SerialPort -

-

-  SerialPortProtocolSimulate -

-
-
-

-   SerialTransferProtocolReadSimulate -

-

- upgrade -

-
-
-

-  UpgradeClient -

-

-  UpgradeServer -

-

-  UpgradeServerHandler -

- - diff --git a/chart/PyAppFramework.png b/chart/PyAppFramework.png deleted file mode 100644 index de206f397737d16e4fe232302669c60109c873a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3311 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 diff --git a/chart/PyAppFramework.xmind b/chart/PyAppFramework.xmind deleted file mode 100644 index 7aa9de7b98324513680bfa3fd3e4c7b7e3eb4d0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171313 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 Q@ZY!KyYGB&BK+(B18q#w00000 diff --git a/chart/PyAppFramework_files/images/BaseButton 2.jpg b/chart/PyAppFramework_files/images/BaseButton 2.jpg deleted file mode 100644 index a0d6c66e5e7e9872e2143f1e772768d51a53f773..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2983 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 SYAE}FLk>E)*_YV{B>V~U6V?F$ diff --git a/chart/PyAppFramework_files/images/BaseButton.jpg b/chart/PyAppFramework_files/images/BaseButton.jpg deleted file mode 100644 index a0d6c66e5e7e9872e2143f1e772768d51a53f773..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2983 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 SYAE}FLk>E)*_YV{B>V~U6V?F$ diff --git a/chart/PyAppFramework_files/images/BasicDataType 2.jpg b/chart/PyAppFramework_files/images/BasicDataType 2.jpg deleted file mode 100644 index 65c96fa1106b00bc786a054f489b1acf0894dcbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2640 zcmbtWdpOgJ8y^Z0CN*-Wi^$~^a+}M<85MPM8M&tBHcLhJWiCl+Ho3&)Hk_lVv!NSK zjCC2MLWk%WqrM&1#^x-tG2`d=oag!dcb@0>bpH7~@9p!v@AJIx`#hh#6TV0lC2b`L z1ft^Y<#7@Mk=eIl(-dVl5NX|D1A!=MdV3)Jfogu0GbsS6dtK@^saB*0y?<20!(0{y zGu_R<$&UKntoVje2n})C^NmFU%){KHC@3h1Ku{zGY2E)J(kONy!#Qb&|8}B_v&xxX z7DC@Z%hv7dJyfOr(;)OMwYl7VNr^gv{YM(YDw*6Ah2>FGyp`ZKlXwQBPY#TQ&>LX}K+@Z#gEPtXAj< znVj@&43;!x;1WwX-S(B@rXUFO(MSF6hyam%7gy!o*AZ#F^g;Kh9upAjxS7Pkr#M(j z7aYg)sY%MGx}F~DM&-2nNFM47!|w^W3iDX{^yc9?Hc=q+Idt*E+Rgb z-(E*yYFZ1Z`Kfz6;St`eIQl^OeewN#Gcx*Y`C;asnxq?#<6{^AQHPI_)tj_z*fzgR|!tn^gy?8KevoUOu9_2Z`HE`c!8-L_uh8LEOsPNu`FQsf+HdN?9A zeZ}+u4lXHIjZYtJvR^c8D+>}3sh;=Nf_oiOEKaJT=N}Awrjo)s<@Gt;*8$kdlKf$m zy}$@`y~0PYpk4mbz|vHwyE?{Icl@#TaS8YU6o@L_)0%TPIyHti8jQZEk`<=E=&5+R zrSD>7g&$&G-TZTBMm^5J*cZO8Xsyl21=@0gYFcYcTPbDZtvEz%EbIr$&NB>cA(-2O zS&D*>=V9m4a=X!+{@~m_U?Ixy5%)S>kA8~So|a;3@nchgfs;)5rB?g{R`k_Gb#<#u zF>6%1c5x}4+Q4{fQj>Lz*50dpj-E(BF1Zna8RcYBTF5m($IA@d+3MfeFw>kTv1dCp zp#?TqffZ5Ffg3ngp)I~{9Zwe!2i8_>drG7iwt_us5u%i~z&CZ0!fF2DW+BUGefe3v z_SCvFGE{9-dUmt!C-1pN91%?uo@KNm>0drkL)o^%YB}Tcr)Sg?tvf4uC@kr;=7@Mw zb7PQKR;ag$F5fat(PIe-!OJPOo>`06feSBCVMer?R{!=+;sTK~W}qh4pC2jdnnmKf zBI+u!o=hN=eL=faGhwD`Y)gU zay3)3wn}bz0@?g->x_}^P7nA&_i#pL#^+uYZeWpZ4)8=?_)ry`)@HtOB;3M4t!53w zn-O%{KPLQIfcYs#)?Xi=QJiqi;awe+n3R;1+f`6XLwl7=V%i#iynX1f+d*5RX!^~q z`ucjQRNAmQSnIkj7S<<|%#I9?`_$SwXPrNP9stDLVG}N_@3y0`QYWl_Vz}}69Ub@X zuJq-vtX52a)*T(=q7EiTaLMP6Yr5Ew4So2EGgw4}55Hv43UL&uzr;2i1))|-K)UoBN z!HE${#$y+1oI!%+)nWO48ifPD=MVBGbYE+<+#T|_ntZI_RH!=@{_W#qtrGNgU&&AW z2|Fv;y1>7E0VcQbFrIh7={enZVJG2Kq3@QMmSmSI#@`)1iH#N^6mn3&xycN{J;EvW z(zompii-9(i+Gj%;+XV6(anj}-SJ6#G9B%n&m4JnhwCt`u542S{InlvJ=M=>sz-4B zq(eF)) z%$LxHnEPoq1iSg+<($zb3&~;!ccN!M`Q{=vt21zyviBnO;+*^Ql(+AEweB{T?p-d;l@91_#Z%VL#FcxA~mAURZ9R8bI8 zCuCZiOtEn0lsz89n@NJ%Rr;$3MX|~WuD{{evEg3WAoCgPBPIC(#I<@8?7rAwUDuM@ z{D1)M4;89mbq|{YjX|yrb p2&&V_Ln=C?ewWVrpAcJ@bFr(ueeg!y-VLP)@%HrfXm*dh@*h*~1v~%% diff --git a/chart/PyAppFramework_files/images/BasicDataType.jpg b/chart/PyAppFramework_files/images/BasicDataType.jpg deleted file mode 100644 index 65c96fa1106b00bc786a054f489b1acf0894dcbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2640 zcmbtWdpOgJ8y^Z0CN*-Wi^$~^a+}M<85MPM8M&tBHcLhJWiCl+Ho3&)Hk_lVv!NSK zjCC2MLWk%WqrM&1#^x-tG2`d=oag!dcb@0>bpH7~@9p!v@AJIx`#hh#6TV0lC2b`L z1ft^Y<#7@Mk=eIl(-dVl5NX|D1A!=MdV3)Jfogu0GbsS6dtK@^saB*0y?<20!(0{y zGu_R<$&UKntoVje2n})C^NmFU%){KHC@3h1Ku{zGY2E)J(kONy!#Qb&|8}B_v&xxX z7DC@Z%hv7dJyfOr(;)OMwYl7VNr^gv{YM(YDw*6Ah2>FGyp`ZKlXwQBPY#TQ&>LX}K+@Z#gEPtXAj< znVj@&43;!x;1WwX-S(B@rXUFO(MSF6hyam%7gy!o*AZ#F^g;Kh9upAjxS7Pkr#M(j z7aYg)sY%MGx}F~DM&-2nNFM47!|w^W3iDX{^yc9?Hc=q+Idt*E+Rgb z-(E*yYFZ1Z`Kfz6;St`eIQl^OeewN#Gcx*Y`C;asnxq?#<6{^AQHPI_)tj_z*fzgR|!tn^gy?8KevoUOu9_2Z`HE`c!8-L_uh8LEOsPNu`FQsf+HdN?9A zeZ}+u4lXHIjZYtJvR^c8D+>}3sh;=Nf_oiOEKaJT=N}Awrjo)s<@Gt;*8$kdlKf$m zy}$@`y~0PYpk4mbz|vHwyE?{Icl@#TaS8YU6o@L_)0%TPIyHti8jQZEk`<=E=&5+R zrSD>7g&$&G-TZTBMm^5J*cZO8Xsyl21=@0gYFcYcTPbDZtvEz%EbIr$&NB>cA(-2O zS&D*>=V9m4a=X!+{@~m_U?Ixy5%)S>kA8~So|a;3@nchgfs;)5rB?g{R`k_Gb#<#u zF>6%1c5x}4+Q4{fQj>Lz*50dpj-E(BF1Zna8RcYBTF5m($IA@d+3MfeFw>kTv1dCp zp#?TqffZ5Ffg3ngp)I~{9Zwe!2i8_>drG7iwt_us5u%i~z&CZ0!fF2DW+BUGefe3v z_SCvFGE{9-dUmt!C-1pN91%?uo@KNm>0drkL)o^%YB}Tcr)Sg?tvf4uC@kr;=7@Mw zb7PQKR;ag$F5fat(PIe-!OJPOo>`06feSBCVMer?R{!=+;sTK~W}qh4pC2jdnnmKf zBI+u!o=hN=eL=faGhwD`Y)gU zay3)3wn}bz0@?g->x_}^P7nA&_i#pL#^+uYZeWpZ4)8=?_)ry`)@HtOB;3M4t!53w zn-O%{KPLQIfcYs#)?Xi=QJiqi;awe+n3R;1+f`6XLwl7=V%i#iynX1f+d*5RX!^~q z`ucjQRNAmQSnIkj7S<<|%#I9?`_$SwXPrNP9stDLVG}N_@3y0`QYWl_Vz}}69Ub@X zuJq-vtX52a)*T(=q7EiTaLMP6Yr5Ew4So2EGgw4}55Hv43UL&uzr;2i1))|-K)UoBN z!HE${#$y+1oI!%+)nWO48ifPD=MVBGbYE+<+#T|_ntZI_RH!=@{_W#qtrGNgU&&AW z2|Fv;y1>7E0VcQbFrIh7={enZVJG2Kq3@QMmSmSI#@`)1iH#N^6mn3&xycN{J;EvW z(zompii-9(i+Gj%;+XV6(anj}-SJ6#G9B%n&m4JnhwCt`u542S{InlvJ=M=>sz-4B zq(eF)) z%$LxHnEPoq1iSg+<($zb3&~;!ccN!M`Q{=vt21zyviBnO;+*^Ql(+AEweB{T?p-d;l@91_#Z%VL#FcxA~mAURZ9R8bI8 zCuCZiOtEn0lsz89n@NJ%Rr;$3MX|~WuD{{evEg3WAoCgPBPIC(#I<@8?7rAwUDuM@ z{D1)M4;89mbq|{YjX|yrb p2&&V_Ln=C?ewWVrpAcJ@bFr(ueeg!y-VLP)@%HrfXm*dh@*h*~1v~%% diff --git a/chart/PyAppFramework_files/images/ColorWidget 2.jpg b/chart/PyAppFramework_files/images/ColorWidget 2.jpg deleted file mode 100644 index 7415892ae8745528906b1bfe7bbd85cecd36d4d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 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 F_8;wWB{Bd2 diff --git a/chart/PyAppFramework_files/images/PaintWidget.jpg b/chart/PyAppFramework_files/images/PaintWidget.jpg deleted file mode 100644 index aa65fb26ca671280bc58180171e23d06870d23bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3999 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 F_8;wWB{Bd2 diff --git a/chart/PyAppFramework_files/images/PyAppFramework 2.jpg b/chart/PyAppFramework_files/images/PyAppFramework 2.jpg deleted file mode 100644 index 4120605b1187979d41eaa683583107eb67c016b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3263 zcmd5On=h zi=s8JU5l=_8kIa$h96Bhd4S%!V;hqsc4W|%i!at3o7Cx-=Ne-G$v#)%56Z*yaD!v4 z&hE1|!9PCJa_4EZ@JAS2o6pmtqVbYVazjbOY&u6K7QT=^Du{=sMIpR#4Ia>c%nc$$ z6cLm=UeQ48X#qI)kUbWV=>=g>g7}|9&SNL5U!uQ%B#=;STh4X`uRC>C6f#eHu=`cm z9eu@G$DJws ztn1MjN>H{m%!ZJS#6)ZcpT`dL#69B7vX$5EM`o;w-P>eQ@WS)X@MDboE&c&%s^)i> z!v(;nzwFU`hg9MM*XY%W5zBtg6B91glkb-!*CHJiwe72UG}JDpE++tAYQEIQq%l)2 z8<0W*LxMxeC2@rwQj3|Sr^e!j$-1MePg#}2MfL}({2Ut3XjC-5eCC2ABJy~3cF!W< zZS}lhrayPcdNxeG+ILM@Z9c~xog>hN+@6v#?P1FbPcpTYN^_+o0<_*0Q->e2{XfhY zZ`PqOs*ghsU`7>sZ`W7fc7&MoQQ3AV$oM9ufBIGEx|fn>`EA36PO@$Fosf)`t8(qq zI0TFqWAl*7nC|xHg5~&m+YCRQmbCkuGAm``d9BvkPEC%D>h2ERb+Pq>r^GOQp{Y_U z&=Y9~WifUMdib)&O|YLTKqw|LU0pWTO`=44^+bsK8ijrWGxQ~mQ z^U8rW;soPucHmI&_8wnp4Rw)rAvh$BxQkwo;s-B&IVSWYe7fP2Hxk_g%GjdHS>D$Q zS}pi0J3>cAYt}|;-9BzM@H(cwSSZ|IxAA(Y5$p1Z@$;6LAG&XSeZcP284KIaA*E|S#?$1f@84I~GVhA%I_(iXTr>5P{L z?L*TJlT}3b>UQ30eY>Bzl#HM4(D0rblgE8w$TAnUY9Ozsg;5z(3SeWzJsK&}N+!KJ zt`w~UhImy%DphiR>A?aq6wMCYuOqpO>t@9p8V!DG^%WcWvtUCip&D_m^);D;69mDR z&l}20nV%F^Gz&H>_f=bmd!3}Z=5l3wzd211++z?TMviAWWV0o6ZRaHz3w5liz8V5= z_%Ezgm8$$HXzteUi*9T?O8?XwR0WgkcO|WlQZW=}-@5`7yp6~tcxhwEd~40Mw0+bX zjs{3hC4?BYtWGUI9=xEOLZLi)I9JIhm3@8FF1_QsAyx!d#BC}lZ%Dx>@A1Ig zHG@X9#@^}yX0HFe-D7iuf^)9VKiG=uuxE7-PHS<4%m=k}I<=ASND-bA6b*a?VIR1` zSOK^(5<(~;uufQf-Jd2rVktrx-3N~z;UczH=H}*xYp;-?uCwv+@$&NWo}Qlm6U|*t zN^ez>a7Ot0{N&{1coT_``zvw#>yuY{OX9wAtX($SU96Ygk*chubfy!<@?c$OMP_V< zE{zg5mzXBOtvQJx-GAajLUyB;x2gdA*|-&PW2P%-RM4bgpu(l}Q`E+y-BR44 zzS~G;s}H47ff|>TEN|KLS!dKNPrU3I%k<5_zhucge7&D@Wr>Hu!AaO|9{?S@DjI=$o-bqKTeMJ}y)tPC*{DT2+8w zx{AMEoZ&V`@}TNGtamuBJoYk*^SQ5R&vn!iz7`N*(Pxb5& z6di|*fBruxKqpgl;yK^H(W7$mm%q21H-ijh@#L+4S-Z)eQhu6)_(*{U|zZYdXDzyL1HOdbYs6g(sKe?st>+Ci^G$&P&BJ%<mw>Wp zdAmIEnFkH3LpPhYk#rOTvpzNfvtb5{+_9;cEMqln%TT?7!vaX|36X~82H%V^#)k=C zPy4F)iOm$$S>6{0t%SVdCFCqV9e|M-H%=|q5_7wS+VL>$aW zrSzBg2G@)zC&-&VtgqhzjQCHeN|kq?(5EaoKU)|doNA>y$gp@dEwixLvP#4xaq-ZS z`XK6$(EvJE*T^J$x9af@f3a>$+ABEBZPm2(ea-Wy8o)JMyPWtJwTmSKvF7Lg g&8_|y&Up@Rug;h|(uVkX?=b;P49rf`^j&ZK9g@=I(EtDd diff --git a/chart/PyAppFramework_files/images/PyAppFramework.jpg b/chart/PyAppFramework_files/images/PyAppFramework.jpg deleted file mode 100644 index 4120605b1187979d41eaa683583107eb67c016b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3263 zcmd5On=h zi=s8JU5l=_8kIa$h96Bhd4S%!V;hqsc4W|%i!at3o7Cx-=Ne-G$v#)%56Z*yaD!v4 z&hE1|!9PCJa_4EZ@JAS2o6pmtqVbYVazjbOY&u6K7QT=^Du{=sMIpR#4Ia>c%nc$$ z6cLm=UeQ48X#qI)kUbWV=>=g>g7}|9&SNL5U!uQ%B#=;STh4X`uRC>C6f#eHu=`cm z9eu@G$DJws ztn1MjN>H{m%!ZJS#6)ZcpT`dL#69B7vX$5EM`o;w-P>eQ@WS)X@MDboE&c&%s^)i> z!v(;nzwFU`hg9MM*XY%W5zBtg6B91glkb-!*CHJiwe72UG}JDpE++tAYQEIQq%l)2 z8<0W*LxMxeC2@rwQj3|Sr^e!j$-1MePg#}2MfL}({2Ut3XjC-5eCC2ABJy~3cF!W< zZS}lhrayPcdNxeG+ILM@Z9c~xog>hN+@6v#?P1FbPcpTYN^_+o0<_*0Q->e2{XfhY zZ`PqOs*ghsU`7>sZ`W7fc7&MoQQ3AV$oM9ufBIGEx|fn>`EA36PO@$Fosf)`t8(qq zI0TFqWAl*7nC|xHg5~&m+YCRQmbCkuGAm``d9BvkPEC%D>h2ERb+Pq>r^GOQp{Y_U z&=Y9~WifUMdib)&O|YLTKqw|LU0pWTO`=44^+bsK8ijrWGxQ~mQ z^U8rW;soPucHmI&_8wnp4Rw)rAvh$BxQkwo;s-B&IVSWYe7fP2Hxk_g%GjdHS>D$Q zS}pi0J3>cAYt}|;-9BzM@H(cwSSZ|IxAA(Y5$p1Z@$;6LAG&XSeZcP284KIaA*E|S#?$1f@84I~GVhA%I_(iXTr>5P{L z?L*TJlT}3b>UQ30eY>Bzl#HM4(D0rblgE8w$TAnUY9Ozsg;5z(3SeWzJsK&}N+!KJ zt`w~UhImy%DphiR>A?aq6wMCYuOqpO>t@9p8V!DG^%WcWvtUCip&D_m^);D;69mDR z&l}20nV%F^Gz&H>_f=bmd!3}Z=5l3wzd211++z?TMviAWWV0o6ZRaHz3w5liz8V5= z_%Ezgm8$$HXzteUi*9T?O8?XwR0WgkcO|WlQZW=}-@5`7yp6~tcxhwEd~40Mw0+bX zjs{3hC4?BYtWGUI9=xEOLZLi)I9JIhm3@8FF1_QsAyx!d#BC}lZ%Dx>@A1Ig zHG@X9#@^}yX0HFe-D7iuf^)9VKiG=uuxE7-PHS<4%m=k}I<=ASND-bA6b*a?VIR1` zSOK^(5<(~;uufQf-Jd2rVktrx-3N~z;UczH=H}*xYp;-?uCwv+@$&NWo}Qlm6U|*t zN^ez>a7Ot0{N&{1coT_``zvw#>yuY{OX9wAtX($SU96Ygk*chubfy!<@?c$OMP_V< zE{zg5mzXBOtvQJx-GAajLUyB;x2gdA*|-&PW2P%-RM4bgpu(l}Q`E+y-BR44 zzS~G;s}H47ff|>TEN|KLS!dKNPrU3I%k<5_zhucge7&D@Wr>Hu!AaO|9{?S@DjI=$o-bqKTeMJ}y)tPC*{DT2+8w zx{AMEoZ&V`@}TNGtamuBJoYk*^SQ5R&vn!iz7`N*(Pxb5& z6di|*fBruxKqpgl;yK^H(W7$mm%q21H-ijh@#L+4S-Z)eQhu6)_(*{U|zZYdXDzyL1HOdbYs6g(sKe?st>+Ci^G$&P&BJ%<mw>Wp zdAmIEnFkH3LpPhYk#rOTvpzNfvtb5{+_9;cEMqln%TT?7!vaX|36X~82H%V^#)k=C zPy4F)iOm$$S>6{0t%SVdCFCqV9e|M-H%=|q5_7wS+VL>$aW zrSzBg2G@)zC&-&VtgqhzjQCHeN|kq?(5EaoKU)|doNA>y$gp@dEwixLvP#4xaq-ZS z`XK6$(EvJE*T^J$x9af@f3a>$+ABEBZPm2(ea-Wy8o)JMyPWtJwTmSKvF7Lg g&8_|y&Up@Rug;h|(uVkX?=b;P49rf`^j&ZK9g@=I(EtDd diff --git a/chart/PyAppFramework_files/images/RectButton 2.jpg b/chart/PyAppFramework_files/images/RectButton 2.jpg deleted file mode 100644 index 587dee3ebe243e3fae98762b917d29166e30f727..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1879 zcmcgtSx{346pa-Xp%_t6cFG7Nihzvx6heq17z6=jiAm4|McJNFphAGK6smDB8mcI$ z5vm9{$V&)?7nTq~rO?Wz6cQ2^w;-k@K@EWr1WG&ov>n^&^y8j;=AN1RbI+ZVdms>N zpl7CsKp+hE`FaO0_OZo+biY_cQ z4ZRL|m)!Qv?&TyJQA_jskHC?>e<2a2d#W6*fXFSQ>T$> zBg13Qst|+YrZlU(=r&&u4YI`yS|Js z&{})wq-R$8j8Da6pA*Y%KN!Be$rF^~o5Ctv21h-jDcCOOj*UtEbb_%n8t#ZJ zNmPCYkVc@5UqF@e1FjYioN#SFrkHXxHSta+KR-xQq8tlp#zV@Xmzi6OYJvLc*N-sY zvKk?+;IcjXNOfRBE{mJdDBQ6%zUh^}JcZ3Zr-G8mPdzCOcd@t=KAqP)AWFB~H601A zEptvZ_McBzQhVOh!tT0Lc6x#1yacM70j}=YFAQ(y8MDOUEKwHQJV}(m7D?x{lH;o+dSKB)u|fu^YYz~ zh?Za^8vH;DN)a~)#JmxmO8mKbCa$@hrH6grCVt-=!cU$7=Fd8T3eoUVb|>%+{w zxLKQ80C=bC5jyTaSkPN+x!12pe!(MOeBvZzSBm|w9QvoX3tgZ&rBrm^WbrSa*e8Lz zf0D^$ePKKCT%11CzZ8U9i0IFt43$b%Q5nyTV6U5m(-sk5xk4D1{eRP|F^WnCCX+U= zzsaVGG`}5QwZyNM*GQ;a$h5O7jbl_K>3##-8bjA|;87j0EP~?pkhlpS9>~S%2@BSK z))-(5QdKbkjd!!r439EILm73NwrGH+c@wfkxGvNMvOGr;@=j{f)!bmIe0WmW9mSaL zUV?VuxvR3QBss91ORGdS(q{_JhC#EcmX*~!TRLG@Jy#=^Kl^bkt>YdeU%W+glVmN6 zmF9-2nd2DLgf_pDg_Ef{_t&bs3u*w;q!y`s`brwtFHX!C)TWPCCpXJ$s)lPp6=^E3 zhsfvIWNx0mL@s)Q+Ue>QUnjM`F72r)EU54hDvNA{97+sNhxCNwl+mBSoG5NEqn1ZS zvN@-?@C|=|oE2znQcHj8Qc=bjyp@_XbeT^5sO`)Y^`8cS0ZC_>okJe1Czps$nT>$= zIpM`Yk;K8-Y(qS&-W9TB4P$i`&%$?Su<7t5yv!wD0JzCy7eQ1;O{e5zJr7hwbt>>I zC-)uZ{$w*Dvx~c3=Xr6!MELYR7LUrD*s`g9!|VNzrw{L`M?H{P=KItIT8&(3`h9cu zI84C+R_&gZBLP=(K+X((S_DoM`l9$lk!OAQv~Y)n`HS1qV(};dSWtH!UH?5Bd}Z!&06YG3%(xq21P0wY)qOvFB)KyQv$M9y!y{j;M0 diff --git a/chart/PyAppFramework_files/images/RectButton.jpg b/chart/PyAppFramework_files/images/RectButton.jpg deleted file mode 100644 index 587dee3ebe243e3fae98762b917d29166e30f727..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1879 zcmcgtSx{346pa-Xp%_t6cFG7Nihzvx6heq17z6=jiAm4|McJNFphAGK6smDB8mcI$ z5vm9{$V&)?7nTq~rO?Wz6cQ2^w;-k@K@EWr1WG&ov>n^&^y8j;=AN1RbI+ZVdms>N zpl7CsKp+hE`FaO0_OZo+biY_cQ z4ZRL|m)!Qv?&TyJQA_jskHC?>e<2a2d#W6*fXFSQ>T$> zBg13Qst|+YrZlU(=r&&u4YI`yS|Js z&{})wq-R$8j8Da6pA*Y%KN!Be$rF^~o5Ctv21h-jDcCOOj*UtEbb_%n8t#ZJ zNmPCYkVc@5UqF@e1FjYioN#SFrkHXxHSta+KR-xQq8tlp#zV@Xmzi6OYJvLc*N-sY zvKk?+;IcjXNOfRBE{mJdDBQ6%zUh^}JcZ3Zr-G8mPdzCOcd@t=KAqP)AWFB~H601A zEptvZ_McBzQhVOh!tT0Lc6x#1yacM70j}=YFAQ(y8MDOUEKwHQJV}(m7D?x{lH;o+dSKB)u|fu^YYz~ zh?Za^8vH;DN)a~)#JmxmO8mKbCa$@hrH6grCVt-=!cU$7=Fd8T3eoUVb|>%+{w zxLKQ80C=bC5jyTaSkPN+x!12pe!(MOeBvZzSBm|w9QvoX3tgZ&rBrm^WbrSa*e8Lz zf0D^$ePKKCT%11CzZ8U9i0IFt43$b%Q5nyTV6U5m(-sk5xk4D1{eRP|F^WnCCX+U= zzsaVGG`}5QwZyNM*GQ;a$h5O7jbl_K>3##-8bjA|;87j0EP~?pkhlpS9>~S%2@BSK z))-(5QdKbkjd!!r439EILm73NwrGH+c@wfkxGvNMvOGr;@=j{f)!bmIe0WmW9mSaL zUV?VuxvR3QBss91ORGdS(q{_JhC#EcmX*~!TRLG@Jy#=^Kl^bkt>YdeU%W+glVmN6 zmF9-2nd2DLgf_pDg_Ef{_t&bs3u*w;q!y`s`brwtFHX!C)TWPCCpXJ$s)lPp6=^E3 zhsfvIWNx0mL@s)Q+Ue>QUnjM`F72r)EU54hDvNA{97+sNhxCNwl+mBSoG5NEqn1ZS zvN@-?@C|=|oE2znQcHj8Qc=bjyp@_XbeT^5sO`)Y^`8cS0ZC_>okJe1Czps$nT>$= zIpM`Yk;K8-Y(qS&-W9TB4P$i`&%$?Su<7t5yv!wD0JzCy7eQ1;O{e5zJr7hwbt>>I zC-)uZ{$w*Dvx~c3=Xr6!MELYR7LUrD*s`g9!|VNzrw{L`M?H{P=KItIT8&(3`h9cu zI84C+R_&gZBLP=(K+X((S_DoM`l9$lk!OAQv~Y)n`HS1qV(};dSWtH!UH?5Bd}Z!&06YG3%(xq21P0wY)qOvFB)KyQv$M9y!y{j;M0 diff --git a/chart/PyAppFramework_files/images/RoundButton 2.jpg b/chart/PyAppFramework_files/images/RoundButton 2.jpg deleted file mode 100644 index 821195ac2810cd724c5f385ac7a78258e27e7ae0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2035 zcmb`Idpwkh8pmJLh<8%dn^v7NX62=_%viTAEltYMU?mj0yfc$nWaP3gsTgl|a~ZQ) z=5>k0TCEwEkXwU6%0`)0Vq9{kC6|=z8IE)Q-u>+7bI$qWd4Au|?|J_J-ulYUYCB;c z0RVvQ)-=nr03f$zlLd;n%{|9;hX6pK#@h14xvuKdGV!+uNUpvL0 zO>c3A3Bi|xb7)n#{+!GX2h@>gkwZU`3~TK=N+1w^8b(pe&|UH`TUYv<2j;_Crb_R~ zT6!iVZg(qQt0&ca9siu$oEQX{n%6V>fhgSuJP-{6I0(SQfFd1G!2k`ioCSi5`jf+L z+vWKQ?KiR#TiWxLw|s3Ef9jR=8|%k44^HfMiUUyuM_Sk%0<3cHe~m``d#2Y2N9eMc zSY1@@4DUA=Rqphhy&2-MWY>Xq#rJntT@Ci@pZ?bK8XYTJ=z8?zYF-i;G-D<+n|#UU z&PReCxyix;Q0=xRvgSZALJDbP_r;Ktl)dIx7C*mXTc{RMvF2*_8NO%(~3 z^FL`7NptyR1_r(oT`{RPZ}{=kqL~>ov|pB)+!edW?xSh83vTVntg(GTio@&~?;X*u z##$eJ0`(b<8c^n^LGgEgO-Q{G5KpEQ=PH7nd0@`n;$G zvJrP2Oz%J^_xqQJQv*tRJ5luoG$2PefAAYRO@vA&K#c6eyjEFICO!DTGbMM0`>;tw zM5w(|3DYs##5YIl*$}^j{Z8j+7Yc(`qgxspmOWTEtyK3};C08`DOu~1sabo7;iNxj zjd>(6PLDr0P4pP{^S62HL_c2vN{Ic>*(YW9lnk2D!EEj3q&IKb4l zPsi-gHmt+|YTOd*4W5oLpL;DQEz^x>z?Og17K}H{LmpWls!`;z6%meEpHYMqTMuFu zKX5=)=l>IhV!*U0umz#Q2#134 zKnzj(?`m>5lr_7tvKHfUi;=Y<qEn%ry5@Zv4QAb3?w7*Ng)35FS>ct6&!7 z69`U>kN(@D)E$nD_--n{X?k&8yJ_Fio|+3@#_prkrI?o^Mc|Ir(OQ?Dse!n^IIN4{TWJq-qc&x zBOA%`AQmz(@~N#EcZY+%*Ws^as?VBc^Iz>9xL}{*x)LETbUb$Q?t}CEG!=8dvb|4+ z3OjC2vs1m6PJ2Aoq*(=R{Z`^Zpg+xSmNATOIpP)WUQ#D9XkpvPSTdq<*T<3nMdD>+CU? z6gOx)q<6TA;zTn(aY$jRLO&L+nh{%3#Kd=|+K=)43Zoojf3S<^rgbt4q{y6ExECl_ zPzpZ(ASou@2&m7)J6TlRPLJQMcc1APKFR}U&Lk~1eV0ZtInwL053=cMK|5tlQqvrF z!9wd4Q$uoI_g7(Q*s&W6uP^FNkX|M9+!wl*#=0xMytMnX?-LE1HV&5j;go%VL2cca zR`Nx>pz7FIosN+gV}dEU=Bz(CKAIz~FF5r}o{#UwfZ5QcnDKkgqa|n3cSdIH49kuJ zwR~B)>IVpQ55fs2leUq?W*AQ%L)7U{adfgWd{GX@6rcwH)D{C?hyusO=%(cs{_cHn zo~YcmadOzm{>nB%A%ch5xCWg+_uyX&a$Uja{Q=!wCgc~JG6$?r*;y7*5zfB==3Rpq diff --git a/chart/PyAppFramework_files/images/RoundButton.jpg b/chart/PyAppFramework_files/images/RoundButton.jpg deleted file mode 100644 index 821195ac2810cd724c5f385ac7a78258e27e7ae0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2035 zcmb`Idpwkh8pmJLh<8%dn^v7NX62=_%viTAEltYMU?mj0yfc$nWaP3gsTgl|a~ZQ) z=5>k0TCEwEkXwU6%0`)0Vq9{kC6|=z8IE)Q-u>+7bI$qWd4Au|?|J_J-ulYUYCB;c z0RVvQ)-=nr03f$zlLd;n%{|9;hX6pK#@h14xvuKdGV!+uNUpvL0 zO>c3A3Bi|xb7)n#{+!GX2h@>gkwZU`3~TK=N+1w^8b(pe&|UH`TUYv<2j;_Crb_R~ zT6!iVZg(qQt0&ca9siu$oEQX{n%6V>fhgSuJP-{6I0(SQfFd1G!2k`ioCSi5`jf+L z+vWKQ?KiR#TiWxLw|s3Ef9jR=8|%k44^HfMiUUyuM_Sk%0<3cHe~m``d#2Y2N9eMc zSY1@@4DUA=Rqphhy&2-MWY>Xq#rJntT@Ci@pZ?bK8XYTJ=z8?zYF-i;G-D<+n|#UU z&PReCxyix;Q0=xRvgSZALJDbP_r;Ktl)dIx7C*mXTc{RMvF2*_8NO%(~3 z^FL`7NptyR1_r(oT`{RPZ}{=kqL~>ov|pB)+!edW?xSh83vTVntg(GTio@&~?;X*u z##$eJ0`(b<8c^n^LGgEgO-Q{G5KpEQ=PH7nd0@`n;$G zvJrP2Oz%J^_xqQJQv*tRJ5luoG$2PefAAYRO@vA&K#c6eyjEFICO!DTGbMM0`>;tw zM5w(|3DYs##5YIl*$}^j{Z8j+7Yc(`qgxspmOWTEtyK3};C08`DOu~1sabo7;iNxj zjd>(6PLDr0P4pP{^S62HL_c2vN{Ic>*(YW9lnk2D!EEj3q&IKb4l zPsi-gHmt+|YTOd*4W5oLpL;DQEz^x>z?Og17K}H{LmpWls!`;z6%meEpHYMqTMuFu zKX5=)=l>IhV!*U0umz#Q2#134 zKnzj(?`m>5lr_7tvKHfUi;=Y<qEn%ry5@Zv4QAb3?w7*Ng)35FS>ct6&!7 z69`U>kN(@D)E$nD_--n{X?k&8yJ_Fio|+3@#_prkrI?o^Mc|Ir(OQ?Dse!n^IIN4{TWJq-qc&x zBOA%`AQmz(@~N#EcZY+%*Ws^as?VBc^Iz>9xL}{*x)LETbUb$Q?t}CEG!=8dvb|4+ z3OjC2vs1m6PJ2Aoq*(=R{Z`^Zpg+xSmNATOIpP)WUQ#D9XkpvPSTdq<*T<3nMdD>+CU? z6gOx)q<6TA;zTn(aY$jRLO&L+nh{%3#Kd=|+K=)43Zoojf3S<^rgbt4q{y6ExECl_ zPzpZ(ASou@2&m7)J6TlRPLJQMcc1APKFR}U&Lk~1eV0ZtInwL053=cMK|5tlQqvrF z!9wd4Q$uoI_g7(Q*s&W6uP^FNkX|M9+!wl*#=0xMytMnX?-LE1HV&5j;go%VL2cca zR`Nx>pz7FIosN+gV}dEU=Bz(CKAIz~FF5r}o{#UwfZ5QcnDKkgqa|n3cSdIH49kuJ zwR~B)>IVpQ55fs2leUq?W*AQ%L)7U{adfgWd{GX@6rcwH)D{C?hyusO=%(cs{_cHn zo~YcmadOzm{>nB%A%ch5xCWg+_uyX&a$Uja{Q=!wCgc~JG6$?r*;y7*5zfB==3Rpq diff --git a/chart/PyAppFramework_files/images/SerialPortProtocolSimulate.jpg b/chart/PyAppFramework_files/images/SerialPortProtocolSimulate.jpg deleted file mode 100644 index ef06751e87fe5ff1dcdcfe7a5f22dc04ef314b13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4790 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 T{;qYZNfF_G(i2nT5|;80M~&i$ diff --git a/chart/PyAppFramework_files/images/core.jpg b/chart/PyAppFramework_files/images/core.jpg deleted file mode 100644 index 7e7a58e83cad4535c1682bb654f89192ef4d6f17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2159 zcmcImX;6~~8U|T~a)=y@2oyRhBISrFi{Ns}r5u4!E(@tpgw`rYM2f&-zEo1wiVznO ziU@4m0LrOC2oS=@A&DUn1RB7kxDc50l_ zc-v6QL}gsa;CwS2zOfY{cfINNNtnY$#rT*b$59mlt3N;-Cb_5_(t~e5>A}7}@|&r& zMWK{WOj!V2(oqfq6a^3^wImVc2mud0`SkAtuWa0U>vAANAaOq^<>>-pvW7pybgYLg z=p7|eVhSpzopPb*9xS{`_&=E*bt&Ar?Fnhg3#FWugrCP32b6cNmg%}&utIq^!iW)$vEo`$4s{AmW{copTyb}jsa}n zE$)v%4Pva=U#(YV#hdabdd2k8Ou%QMmnN<47MsXuZC9I{#3t8TN{3g+vNCQ}^V2)i z{0UIHgi3(St0WjJSp!#Wew>b_kw9h2CY7TnrS6wa{S-On@eB&G?+CIjm}KCN12(>y zyE{Wnw(=c2$#Z6M*B)OU1?}Eg7CO(M6fuHy*r=KzMwoV`HzC@nc>Gdng&UMQlYx;? zy*axkq$~ZS^J27-y~n-W0OL?BonEF*6_F{FiWw3t0fp4Sv~|v z%6hR4(@uYYX>@akv61X>Ae{7x^xt91i0;JgY;KBpqcmApw^+GXJ-->5Lt>(Zhx^~& zFDex~PFVi0zc8*j7p;2r@cI0akr5`7S%QcqG3<=wGKGjo>Fev8nz}f<#VSEKm^X)X z;&=J4lMTUi;rJ|rSVc9+MZu@XT9G^Q^@Y(7{q-FjU2n?XpcZOsYDRG%pbi3M?~o2} zYS5J=m%`HmZ}If>*^a}vm_68L+c?2NFTnqV*r`lk6)7}Gi>(;@*fI+o>P1duAJZF5 zh^y9Kiuu#AJ*7~(A)FYcy}qNaYwn8M4(~YJU*kiD?2SM ztV1j67Sz!#em+gHm$=x<8nobpT7YmL*q8IWWrzx?XXE*8N|*Us0$zFI+}orJYdkZ- zitzG4#0iT_MMFm5JmXvA*)Q{;wfM95r7!!ja^y$!%(pWX*!WO;M)~6-j6PxA6eEVusKC;*{C<3{sr7mt2wHY+Ns*Y2l3KDR#T? zDtq4ej#k;fwg3!PBnbW7&_jRNise0fQH=Ea8kYmv)sZ2FDPeQq#?|_-v?VSvt!~@6 z&eT-;xb*n5cBttbCXpa-Ze}nhy8HEo88P2naW#qc+EnTM!Nb|ye4QKG#D>6=>sLZL zYnIYT$geHpEnDPEgXS;hO$!D=-;jqjs4~HNaxe$r9RS@_ySSLj{m#apcWu>P@@kj1 zRF>;U3by8o1Xibl+6`wG`EZiekArBy>?b!%N{VX*JMaaYi>4xnS{A*@cgBj@m%}8~ z>o*)YnsqA<*Q=MMR6xU~d*(u-?En~UXYiidWpV_a-?-tQWmpEMK$GqP?VgJAi)vB$ z(;tAQ?8dd%GBTN1e_Ks1z+V1VM~JRlZ>9&X{^jXf_Da;ozK!w-XRzTsed;M{v$&~$ zjdo>)idfB6G{#o0PS`I|9J&L3DHu5utF+5t75xCsr^m^|nnuJ2^I4TR4$+SxL79d} z^80VqbAn?4YN%*2L+>B7xu@tufeqV*>)9{wowOupGDlja3u`)6+pLSm^Yh*e1+FC43%44$rmml0#$)@v=UPdpmjvd%3o5 zr81n-TASz1z~MYVM=8pI%td35JVif_dINNl%Qi#!V&SfxpCrW8MGmyR1usN z$lErFtJcz@?vC`k0_WwK<8@Xb_Vgl>8>v8unYtH-r%eRelPG`NQ jo#wOwZ}$I0gS!m@sn*bPxclBCq2liw?9=G=Mb19~tb)M5 diff --git a/chart/PyAppFramework_files/images/datatype 2.jpg b/chart/PyAppFramework_files/images/datatype 2.jpg deleted file mode 100644 index bb0fffe8ab57661443b1de5aaf81669abbce30a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6075 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 diff --git a/chart/PyAppFramework_files/images/dialog 2.jpg b/chart/PyAppFramework_files/images/dialog 2.jpg deleted file mode 100644 index 216b149154e39f088108bdf93f7dede1f968d36d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3736 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 diff --git a/chart/PyAppFramework_files/images/ftp 2.jpg b/chart/PyAppFramework_files/images/ftp 2.jpg deleted file mode 100644 index 2e330c94634c89e76d68b5c5f3c7b1848c6633c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1121 zcmeAS@N?(olHy`uVBq!ia0vp^Z9u$+g9%6)>NrnhU|`Ykba4!+nDh3oy|;9s%<+$Q zOYSj$U=-O@s;R`+%Eu?WBs)X)h@WnRx9p`w3tr4PsM@_)!OFs-qlv@G+&%sF?uk&Y8>qauTX%lX-=z6( ze*3=`R^qgO^WxJvyPE|8lQw8^uAB6LRAQ^@%Rg~BDw}pxMf}|nujhG8`OK@btDEai zsvJK%&$(E?^2LU~jP*yaOnj2~uJ@SJ?#WhLwx5bW^2+0r!FRXhpBAMV)s%#60zr-V5e+R7f;A)dQyCt$l!!c;imu)I1jiYuHe0@GIcE==@ zjpD~$sxoj+VKLMT6cR~Fs>9u=rT1hB7 zr(4!}>CaX9Yxl5ZlGDk)R+Vb6Nnh?iuPWYFW3`k!{K(9x7w@F^=AMv=Hm+X%G&5`F z*;vK;@#&~8-=+ax$pH#s{i-yP1XL{{%fLCRc^BC z{_`k%aq;3k_N!eg)zPBydR-nu+Y>w0d3=Rp<6fGor^)l$a))_Oy7)%5U$*L@*BhnC ze9tyD$*Ssp53jN`&o=d)_ba^HtbfEQo$T<)lQ)~a=%<+RlQ+)nzc(%vpS&dRyvoVk zU$341t1b<9dlu^5Jn_rBNy6r*f<2Q|8N-BPR1b#YB1(l+?Dww^`PYAP`HF`-j`<}W jll3f^$RbXN_{sky^Of3~rX{+-qJzQH)z4*}Q$iB}%76)e diff --git a/chart/PyAppFramework_files/images/ftp.jpg b/chart/PyAppFramework_files/images/ftp.jpg deleted file mode 100644 index 2e330c94634c89e76d68b5c5f3c7b1848c6633c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1121 zcmeAS@N?(olHy`uVBq!ia0vp^Z9u$+g9%6)>NrnhU|`Ykba4!+nDh3oy|;9s%<+$Q zOYSj$U=-O@s;R`+%Eu?WBs)X)h@WnRx9p`w3tr4PsM@_)!OFs-qlv@G+&%sF?uk&Y8>qauTX%lX-=z6( ze*3=`R^qgO^WxJvyPE|8lQw8^uAB6LRAQ^@%Rg~BDw}pxMf}|nujhG8`OK@btDEai zsvJK%&$(E?^2LU~jP*yaOnj2~uJ@SJ?#WhLwx5bW^2+0r!FRXhpBAMV)s%#60zr-V5e+R7f;A)dQyCt$l!!c;imu)I1jiYuHe0@GIcE==@ zjpD~$sxoj+VKLMT6cR~Fs>9u=rT1hB7 zr(4!}>CaX9Yxl5ZlGDk)R+Vb6Nnh?iuPWYFW3`k!{K(9x7w@F^=AMv=Hm+X%G&5`F z*;vK;@#&~8-=+ax$pH#s{i-yP1XL{{%fLCRc^BC z{_`k%aq;3k_N!eg)zPBydR-nu+Y>w0d3=Rp<6fGor^)l$a))_Oy7)%5U$*L@*BhnC ze9tyD$*Ssp53jN`&o=d)_ba^HtbfEQo$T<)lQ)~a=%<+RlQ+)nzc(%vpS&dRyvoVk zU$341t1b<9dlu^5Jn_rBNy6r*f<2Q|8N-BPR1b#YB1(l+?Dww^`PYAP`HF`-j`<}W jll3f^$RbXN_{sky^Of3~rX{+-qJzQH)z4*}Q$iB}%76)e diff --git a/chart/PyAppFramework_files/images/gui 2.jpg b/chart/PyAppFramework_files/images/gui 2.jpg deleted file mode 100644 index 2c9b20bd772bb0a240d8346da36101b6061c83fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3975 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 J1^m*TKLbdV6!HK7 diff --git a/chart/PyAppFramework_files/images/misc 2.jpg b/chart/PyAppFramework_files/images/misc 2.jpg deleted file mode 100644 index 7fc2c6e3dc0df28467df4d778f63112daac0d8a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4103 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 Q+I_;jz5G1u_v5Jl03KSp{r~^~ diff --git a/chart/PyAppFramework_files/images/misc.jpg b/chart/PyAppFramework_files/images/misc.jpg deleted file mode 100644 index f3f126f3c472070732b1f1ea2aa8230eee2c465b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1983 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 Q{2yR8R(6)<$1lYH6J}`@)Bpeg diff --git a/chart/PyAppFramework_files/images/msgbox.jpg b/chart/PyAppFramework_files/images/msgbox.jpg deleted file mode 100644 index 0f74caca1a2695f3941cc4d751d00803812fe7f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3174 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 Q{2yR8R(6)<$1lYH6J}`@)Bpeg diff --git a/chart/PyAppFramework_files/images/process.jpg b/chart/PyAppFramework_files/images/process.jpg deleted file mode 100644 index 75a86e05eadcd88d172d62e8ca537bc1ce8baba9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3177 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 I?FW&62Y&F);s5{u diff --git a/chart/PyAppFramework_files/images/protocol 2.jpg b/chart/PyAppFramework_files/images/protocol 2.jpg deleted file mode 100644 index fbbb263010ae26ec62eae0bdd185d045291b288e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3240 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 b@Wbh|(RP<*h)0CqcM(@-4|u)PnaqC!MDx`t diff --git a/chart/PyAppFramework_files/images/showMessageBox.jpg b/chart/PyAppFramework_files/images/showMessageBox.jpg deleted file mode 100644 index 0342b76cdb2d3a728f21702158370943690fc753..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3045 zcmb`JXHXN^7RP}F5ik%0qy`8kN|nv*_rn~y_wy4`{mA=|2g+RznOE+otx+7;R29W zlNJ#X0l1!o`-q5$S_tFEd&Pw3RX^o85fPcku5d>`blGy5eSwCHTHnr{R;~9x_GGmD zBzsm-!zw;Lqa(TFQezOKe3ab|czYt#+^0R`7YVT9-s??b60%vq+@5Fpw;eNNEr9PP zOsS?w0d;pNnTFg*Lmy2f*Vf|OI1@~NyKj2kkSy`fcc%ajd$Yv}d-D$9baaEY^KVCG z=sOW4{<`oIxBI=p1-m&W+Go{^{mxi6|S)+CedI z0}DOzIoMP$YfBeweDWTlV9`EnWCqhAWt%A|ii2j!`{n*q+O@K7I zujTW%%;Fo9BeC^;??geksbcBEGoE!iBa9D)iN>`<`~q+t9BPn>%MqjyU`&bbjkUEF z)1EmXVd_wR!zwcTVoa=c-y9JDW<6b?LmpRwBg2K+G344cHRS?`t=o9}7bNw{#XH8O9lS(-q< z(-u8Q`n|sE^u8NW5KUzO?vX!(U>Emb|)D?O)L!u7`Kv6Y{|2)#sT~Bb^EtknRPhqLJKNplQNno2=~jdEntPeSLE)*a#8r2d zrgtq32Yksr)(T(p$4_>63?c`a6{kPT6#d4_J?%73Y;Ji-h5L24?;@7n zCln}o#10R2%Y6LzOkKbVF4(zTVb_PJ5WW(flAkC0W%Xq>SZ(SzNk+(pLWlXJ*BE6i5#ykSB3R_Z#zs$}!f9e-R6bmxs=EXL-?ub*?vA9!Hg z9y$w8AvO)!q|3CqY+Cj(`C1`w7_R-<|0VqYYT-3T)kH z5tX&7v7DV%dCZrmSUB(d9Hp$3Ox*dD@{MP_tgSY6Ud6^-m62z}cOBbeF2)5)QuUx4 z5VbR7ra=#7p_F`5C4)TguVBcl&M=ZwR7TjI|5YW7o-K{v(rG@juT6E(9?fgjY zS8NS+Q2>4BAw<<|{t6$wRx8bQuB)TVZ0jKj4v$M4^LruNVCWfqb zXf?=)5~9_J6PBgmrTcMD^nfTg?J4~KOq4i%U1qg;;%zT;-#@K8-6lKw#r*61XesOg z{qlOvxA&x)6TqF#wRtw1&0sJ_%S}SN(1P9cW*{nRz)BbNMN>=bL0Q?AO>RX> zfgw=>p8GOMrG4aqeZ$Oc5GnV@SsG@8GhA-dYk$G==Zi-)8D}r5VpfF66!m7<#%<_{ zg@pwe2!p=jMM1-JBfCE>6loqiLF(OUjDSqRa)lMHw3)`Dn~Rk$h4>%SgQ-eXe>v5= zW?XA8VZ0taiNlwbnRR1FVST#Dr84Hl7gvHU2$pfPw)R4V{23v_qvKXq#F?z`t+DX5 zMUv*R8WOqW8ZlXD?T=)N!>h@{5)SE*wjt8)XLtWVb5U1OT`%5Z%m97?_5x-^U^K}+lt86 zNvtC%NyFEF>VE76ulH|t%80tkE>_APpyUVW1BXm@nw{i30vOT~gzwd10e{*218`@T zOrwq5!rnSEHuMph7Ou<+eO?GD>=EZf!aTL$}vgE~f+wiSu zw#tETzgP97*BD)5h!e<$tV&9>bt%D8Cz!Z&1>_;?KE_~qWgqq-j?3!lU=sq?Q20`%Fq6}DZ~ z93B7<^d%=i23ek+iST9AKBJn;MhT#@y^CEQ5Ao#C+N&R5SA|DPOhxOcc^3f* zv!)=+RA9N3_j-ae_5;Z*l;XeG{$hX7ahd#^jD*2)l^ zC^^Id#5kjo+qkX~GJ2SE-xlQZ78}5_ojANj?woJ`%yg^>b{cQ`qDVaekh7V48t;I> zg?=5ji;#-Zf+|-}ol9%Oowp19T{u~%z?^sc6`L#5ph%TuI}i1OyQ0}(jPk=AfX zomGq7V$rxEB`P~chB4%LXVsauny3H->`}~FJeU|Pi7+|I@G~e@YU!j)PJ_sJIf32pa^D&d1t|8;PU&A0G&^^{ym{i b@Wbh|(RP<*h)0CqcM(@-4|u)PnaqC!MDx`t diff --git a/chart/PyAppFramework_files/images/stransfer.jpg b/chart/PyAppFramework_files/images/stransfer.jpg deleted file mode 100644 index f935b0d6049b284a0211e115dc0b5f8e515ab463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1803 zcmchY=T}n)7{((4S|9>P4-^zZz*-B4Qp1oTXc!6xf;S>zIa-334FL=Y3OUG#h@eIp zVTvR-!~xuZhJA_)gCkx>fUp#(m@sl6Y|9@|Tl=LS-f_ha~CXGT14EA3LNS7sg~MO5?R>a3SZfg}-cnS+z9T+A%# zD`51>dh>d1BX+JjryFKpm7sd*CEDr=NczuAC#(ZTUkOsjdt{}jfY@z-LD}C)xmCjK z!_8}wG~1r2q@_=DLP7^lDx0(Di84cbptqH1r`u!Hl0iK=#9kgs-VAJ1XDaG@pt0XC z^zH8y+30r9u1pK28#6Z`<{5O7_m)A`0k#X*9d_3(3j6Te&@`obI(Rm6y3?>G5lXb_ zuZpQWmvr;m^EY;dXi*-Si-TnXbl(W@Iy`sg;u2+{^PaQ?SdLn#g7YHBuB4I}eT?=v z+UTTnSHqW}d)^6kED$jgz$+#Ksg;<~FR%z$(NWG)M^bK0(kcy$z^npD;TK}3k@$lK zY=4qgAG@zlI;3^pnmhlTmR3&m&K7cfUktBQG<1mz>bau$CHpt*~&=h zTdPG@99z{1Lu%V>TjI#-5{_WC-m-`Z!XUO*cl1Nh@4>QSu#N$==*t>>#e(MgB~6Tz z{bmCe%JB&j0>AktJJ*I1La@wcOqhm|UbCi{4Itd|jiQ$8L!g?uIzdY{(G2HASG*0I5YnP<&2!O4{> zrEyEHEPB86daBvNvOL7OD+$PY`rv}}g(VV2JREeWIZ8-^UlhsK`bCsqKWuTr^vM0E z_z$8l9oYEp(&8Y^SiWFdPndRnk7DfaFp^ZV55UgRcR&Zh?AJz?Tjf9}g2N zW}q^(dlM4k0DmmWH(}Cu05$98=)}ZCGWj6c)ZCOwFXZufR4TPJ;W1_1b!l}e=JMss z6aFFo9{k+K#>P_KBZ>pY)q}4F)W{<$|HJx@H7{A1klkr+OB@{tcz9550_bp>6AxY< zYRW+z4Ny?1^}ijY@KycA1KPG$O@8mr9_hSa{tlNjPDb zT4J)J@i|ekCMjiWC=4zVcAnS=HT(J(KAhpsYg1wxtm7}mR|qlSkQE6?Z!d zjOqnMVGEv9d~U;>+aAgyyjDAqzRqYiR(D7dE$1eJDx+yw6Cc-K|+Q{ z1deG17KoUzILPrfNgQHo9E~AaXykC!BmuKVqFjUN(?em6TY*U*!ayKx)aUb?@wOJZ z0f4_h0&vyi<+oRR`v2kEIwp*_+Z&u0FheJ>y*N|&S{Bhqef(ZgoE91}-slViv+RcY z`!GMVraeztygY1QP4Pa|vIiX+?;0l_(j$*>k5qO8}IJQdLqMcTg zoAD4WI^53(q75^~Z@yUsFzFRq*JOIZWQWMYeKi3yzS{LArW>3G z*8-_E#8AD~#{A!hn2Ivx?|sZOD8jNd`wsQ%_SLsPv1v}IwQ%Ea!r>pdF?%@HG;Z%# T>(9pPkV74F#9<#CIg|1irTk)h diff --git a/chart/PyAppFramework_files/images/tarmanager 2.jpg b/chart/PyAppFramework_files/images/tarmanager 2.jpg deleted file mode 100644 index 29dcdb52d1c7d849309bf40f9e60c3cd82eb8095..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1969 zcmbtVYfw`M77p(s4_i?dAp~eu+$(}01p*3$f(k{rKnM>TvD;0NmytL`kWCR-i4=rY zxgeECAOe?%Ag|>Wf+7LE7%H&knFJNDppak!@<>T2KX!jO(;wa4ALpDo^L^*cnKR$a zmkIiv)Z1aa1B1cnd7ttO+^&-CsQW~9J1=9kc407DiQb+BVq%fF*ewQo(uk?J*<@yJ zX3nxc{i%o7!)sZ)4~TEVPDOwU&%*k(dHM}v&BaSMd{Q%Y_E`U2onU@(&aU-VS9h1N zaI&zwxQh`f5ixK-7$t8#8nCClTT_1M}s0yU-0{7-!MOf-Y z&HXI9gDMa~`}ZKv+D+lk2Ci~7(!+CEk=xK0T!MSEl!DX#j88mDJYbxLczT0{2eko% z{RB$+KG-);9m>4LvJ2QnJmB*`f@C12J+adf-HrOJy>U?So#PJx;{M zuE3m?iI?l-Uma$1=`N+YrO;q0*;gQ*^M5ihETX0JnC|>}#^jUop(s3ZMG=PUOzKMr zw;pxUFj;ta`mEb!k{d&Tm%S^K{e&}dWTPd}xUhTgqsn8h3BArfHj1!UPE)ODeikX9 z8Y?*=_~k3quezRn854Ribmw>d6H(c568?GJ$JnEvA1jdzPi?^)7#?4()bH;&hIOxpOAn^+1kKBjo=5jky^pmDIDPP zg^svEiQZIIHqr~+Z9X-I8Cy-YhG`LssOqaOEwP6k=f82{2~>#^FZ5i;r2NaT{ZNs7 zbi%a;l_#G`CZBP`rA|uq+swT*D`=q97obj+K0wIf_0F8={&AN$CQ@Eq+xfiZ{PFtr zD(2{JBgTg+{MhQ1O0Ld)?6EeEt0Azq#~%&ZG5)vPvA5+h5&jBkp5AAN+j?5*L-ijj zz5py6Czt8bsnXgE?CtpDE0#z0jyF<%rUJ3XCs$l8m1~}`@2-kbgOQiXB0~*`dB=ye zwHZEt`U72SyV(PTcp0(nIaj{bC|H zK;!?C>OFAd?&F9`riG_{5Wg=tBUG}qVN@pNCjZiJ|P}}i`0lG&`)7s5U&MiBNkvGi>43mg}!3h5l}444q$@Sva06v zSBK1akDfj@Ui(0^pKdcEU&~Ece-lLC0Fw%?;~=WPewLznnlD*EVW$ZP_xNrayj6yk6;|Inp6EpyK7W?_6*#g%j~>f9YOQ{^ZDjbl{>B+*EB9fd5zM$X!3 zz!-^cA?-6|3=Yd5kws(eXi&%45u5he*u{pLO_?{m2DH^pw~WjEwV*bYOx0Ng#(uxX z?NHE;mE6DI<21y55B>AY-P9OC(>o-j#h!#0hYZApib7wxnG!{sfv}(mg?)6ITjfi( zfMe@IWs_~6@ zWUC`gq$32X!!~d*vSOBB?AL$+CM`sB@HM3k$mjtzF7# zBzZM-qfofvNzFs(t#Y0sFE>h1^Lej}Lj-SHqB&kJTea&eHR$m7n|*mx8yK{6hZqKQ zF5ZbaBusVEgqyZ_$Qw5+0?N?^(E+s0{ky5e;y(?;9I|c@YDJ)geIyQdN*aQ9rx5j1 z5q0R&)$O;c{zqkfIn|p3RGX$PCSC36O5hxKI)3pEg0c8Re)f^o^=`Qa(fPftF&^7i OjPdsJ^Q`wcm-ZV=fxuP( diff --git a/chart/PyAppFramework_files/images/tarmanager.jpg b/chart/PyAppFramework_files/images/tarmanager.jpg deleted file mode 100644 index 29dcdb52d1c7d849309bf40f9e60c3cd82eb8095..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1969 zcmbtVYfw`M77p(s4_i?dAp~eu+$(}01p*3$f(k{rKnM>TvD;0NmytL`kWCR-i4=rY zxgeECAOe?%Ag|>Wf+7LE7%H&knFJNDppak!@<>T2KX!jO(;wa4ALpDo^L^*cnKR$a zmkIiv)Z1aa1B1cnd7ttO+^&-CsQW~9J1=9kc407DiQb+BVq%fF*ewQo(uk?J*<@yJ zX3nxc{i%o7!)sZ)4~TEVPDOwU&%*k(dHM}v&BaSMd{Q%Y_E`U2onU@(&aU-VS9h1N zaI&zwxQh`f5ixK-7$t8#8nCClTT_1M}s0yU-0{7-!MOf-Y z&HXI9gDMa~`}ZKv+D+lk2Ci~7(!+CEk=xK0T!MSEl!DX#j88mDJYbxLczT0{2eko% z{RB$+KG-);9m>4LvJ2QnJmB*`f@C12J+adf-HrOJy>U?So#PJx;{M zuE3m?iI?l-Uma$1=`N+YrO;q0*;gQ*^M5ihETX0JnC|>}#^jUop(s3ZMG=PUOzKMr zw;pxUFj;ta`mEb!k{d&Tm%S^K{e&}dWTPd}xUhTgqsn8h3BArfHj1!UPE)ODeikX9 z8Y?*=_~k3quezRn854Ribmw>d6H(c568?GJ$JnEvA1jdzPi?^)7#?4()bH;&hIOxpOAn^+1kKBjo=5jky^pmDIDPP zg^svEiQZIIHqr~+Z9X-I8Cy-YhG`LssOqaOEwP6k=f82{2~>#^FZ5i;r2NaT{ZNs7 zbi%a;l_#G`CZBP`rA|uq+swT*D`=q97obj+K0wIf_0F8={&AN$CQ@Eq+xfiZ{PFtr zD(2{JBgTg+{MhQ1O0Ld)?6EeEt0Azq#~%&ZG5)vPvA5+h5&jBkp5AAN+j?5*L-ijj zz5py6Czt8bsnXgE?CtpDE0#z0jyF<%rUJ3XCs$l8m1~}`@2-kbgOQiXB0~*`dB=ye zwHZEt`U72SyV(PTcp0(nIaj{bC|H zK;!?C>OFAd?&F9`riG_{5Wg=tBUG}qVN@pNCjZiJ|P}}i`0lG&`)7s5U&MiBNkvGi>43mg}!3h5l}444q$@Sva06v zSBK1akDfj@Ui(0^pKdcEU&~Ece-lLC0Fw%?;~=WPewLznnlD*EVW$ZP_xNrayj6yk6;|Inp6EpyK7W?_6*#g%j~>f9YOQ{^ZDjbl{>B+*EB9fd5zM$X!3 zz!-^cA?-6|3=Yd5kws(eXi&%45u5he*u{pLO_?{m2DH^pw~WjEwV*bYOx0Ng#(uxX z?NHE;mE6DI<21y55B>AY-P9OC(>o-j#h!#0hYZApib7wxnG!{sfv}(mg?)6ITjfi( zfMe@IWs_~6@ zWUC`gq$32X!!~d*vSOBB?AL$+CM`sB@HM3k$mjtzF7# zBzZM-qfofvNzFs(t#Y0sFE>h1^Lej}Lj-SHqB&kJTea&eHR$m7n|*mx8yK{6hZqKQ zF5ZbaBusVEgqyZ_$Qw5+0?N?^(E+s0{ky5e;y(?;9I|c@YDJ)geIyQdN*aQ9rx5j1 z5q0R&)$O;c{zqkfIn|p3RGX$PCSC36O5hxKI)3pEg0c8Re)f^o^=`Qa(fPftF&^7i OjPdsJ^Q`wcm-ZV=fxuP( diff --git a/chart/PyAppFramework_files/images/timer.jpg b/chart/PyAppFramework_files/images/timer.jpg deleted file mode 100644 index cacbdb354c9e1c1525844580471993cbbe8ea45f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2585 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 JpVLc|F}pu@|J-}-d!Kvm`=0xp`@Hu-TQiun zyfg#?fmxWF+Cw1QlEnDMuI=Jc!cA@x0@+<>VQS(SMd4A5gB300?+T8N-1>O~va>_` z%z?2lxCEH?6@7%dgtyX&RB6g(^v(XfCOAUl<+)uuFGgLJkXA%qgD13qZIo2s4TpAz zw?C+*)9CcNi<=QF_KJa!FcNAP8P4qKblhS)J3}BY--2c(ArM^x6><)Rl!oyCDllCe zGG5&h_Tkg)M50Ymf5P=FoW@?#;faVDk6&myyw5`9CeHgZ|k-RG>vDn3RGhHvG z{E-Z%8R7PJ$=8@{sMBRF4M@dPP5U80Pe(CrOt_xgx~w*@5)zgh<|1c@+i!BR_ZXs! zf^nzyvTv-CsQTNWs)RT|V)Aq)5Nik&v|lYLaEPUU2EVL3=55+MtTPb#>N(a;Q{ii~GI8H_;68dUa3SS(p9+siqCazU ztw9nAC!nhDe4xJjs&_hX#UxQ@&9*77eC}B4eF8k(xFh?=sk}z;wUupPA9Yq{s6@L7 z)>A!Fn{xb-s>j`+m=b9KuZy%4i{3Mv_yv#JNOt9!P}i9TGjDr`yp&)Qo554-G2~dQDhG)!p*?oS-WW z!d8_qaeh09`@E_JOWRSUYs2G@m!?jjR^QRueet}XI*%wthX?ro#6o{oOQ4z}SKI&A zxEKgu3$FP|-|>s1_QH=8VEUA2`fqJJAJYwAl79_lhT+HU^wdf%&cZpw`4@2CmUk8*lNa+5O+?IG`Py9-%zpGBN^zU^l?L z^)1arYM#S9!FM$0iZ(YopBO6CojF6GI>|abe`6yjCwC3AL)TsylS84%I?y_EjZ;Q4 z>l;C$w-8~RrfhTzS$8-u%iAyZ#tn4DiKXqpK~nlzKf5joVrwI=h>i*27(^}LW}O=S zK*|J<#|tgNAdy_|`1qZqysn(Df){I-73vT*KT}KKaJUC6&M@Kx?poB+c+2wdo$s$- z&=zylMb3X8cz4dt%}w#pq2v*gTO;T^WFQIC#1$QW4I-tx8$p0TMaw>mrxJGnUK-}# z0Wc}z8}JuNqWnH+B2@(j)jNii22A9ULFQ;#B0(4Z`4^l9R3h-N5TwDv(OZk2#=`V~ zj@P$u=aWsnu*n}44$}HRPADtipOn@6Gh_|bTf}MP>mW(L{x>GtO%H=w!)%_SpscDq zXJB?!i0851Tlx{X<>WI>(+scXVr_sKyA~dhYr`6jUORs|8e3TOHPlUkJ~ek+LVl<$!wGY=Eb9@?}l<1GQay1dJH)^_#BJm z1gKTu@d-XRshs_3=(dtr&8${-=J^A!5--q#n@@=ahi*y;pSBIrTm!-|}^-1-~Fvkg^a6Sm>sJBD>uWU6$Bw2buz-zq)o@Q6yu zapU6#lx$0DwkoCyiwC2-7N3?KOR9B3(255J=9Z3W4?kGVow^7#Ik^r+MygZ=El!T9 zuBnpLNCMaHYFH1wGxfJNkP{lPLKY-BZ+X83 z%bhE^6ScmS{fu?lzToB1L~&^Kgv65P)$Lc>z{MWP2(K|%0h8Pz z-44yicBdtUPkTl(5-U3fd+Xp6DUX}?BIX$i4~IBrg>gVJcRWYFe$20Hq;Qr5hU0nSEJ-)Rk(S^RqO#ZkHhB)0!sR`xZ z6+AUm7m(z*g-t&1*I$N3yJ+W?+$^Yn8-)1)rfU=^hb^EK(%rN|*mI9RxdhMn6q$GO z1B>`2Q(-=E9}T+jq4GtP$Gf@eowY5a6ytApwNaOpkECXWv*3tPiArLYttL~qeW_Nr zdjPey=IM`jhazUg8rOabFS2$2H2OiY6^!3GE)2#lDx6Dg2tf8qF)}H)VeUU*&sK^e z7gq|Kb)7L)gVoe}Nvj75vzFh2L?5Q@LRu=k2Sx`+e%rvr;@x3A{W=y$k4Kc2T-Xs&~|oixKiGzpO4}<~??h(NleHs@aAoQ1_Cn|2?Kv zpkqJUks5;vVO!OluIF_IFMoY^(ZyHV=2d!R4LiJO@=2i5rPR2(mTF$C4?MUi!270x z#;Dv9*fl&G6^qwa5LDPJ3HxIG6U~5`(9!K~)#kOJI diff --git a/chart/PyAppFramework_files/images/widget 2.jpg b/chart/PyAppFramework_files/images/widget 2.jpg deleted file mode 100644 index 21cafb2f9a38b4da677bf77ccf9e75541ff1c8c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3878 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 D2k}WH diff --git a/chart/PyAppFramework_files/images/widget.jpg b/chart/PyAppFramework_files/images/widget.jpg deleted file mode 100644 index 3df6453c6b3a5df191a457d7e3e3fbfb7d839a5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3187 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 mFc}0AF7&&$?!T|*e9?_F#X+ diff --git a/core/__init__.py b/core/__init__.py index f99475d..db1d843 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1 +1 @@ -__all__ = ['timer', 'datatype', 'uimailbox', 'database', 'threading', 'utils'] +__all__ = ['timer', 'datatype', 'database', 'threading', 'utils'] diff --git a/core/database.py b/core/database.py index 42bff6d..f1d16d7 100644 --- a/core/database.py +++ b/core/database.py @@ -175,7 +175,7 @@ def getTableDefault(self, name: str) -> List[Any]: return [table_info.get(n)[self.TBL_DEF] for n in column_names] def getTablePrimaryKey(self, name: str) -> Tuple[int, str, type]: - """Get table primary key column if do not have pk return 0 + """Get table primary key column, don't have pk will return 0 :param name: table name :return: (primary key column, primary key name, primary key data type) @@ -249,7 +249,7 @@ def insertRecord(self, name: str, record: Union[list, tuple]): raise SQLiteDatabaseError(error) def updateRecord(self, name: str, record: Union[list, tuple, dict], condition: Optional[str] = None): - """Update an exist recode + """Update exist recode :param name: table name :param record: recode data could be list or dict (with column name and data) @@ -272,7 +272,7 @@ def updateRecord(self, name: str, record: Union[list, tuple, dict], condition: O if isinstance(record, (list, tuple)) and len(column_names) != len(record): raise ValueError("recode length dis-matched") - # Pre process record + # Pre-process record recode_data = list() blob_records = list() @@ -330,7 +330,7 @@ def selectRecord(self, name: str, columns: Optional[List[str]] = None, condition if not isinstance(condition, str): raise TypeError("conditions require string object") - # Pre process + # Pre-process columns = ", ".join(columns) or "*" # SQL @@ -368,7 +368,7 @@ class SQLiteUserPasswordDatabase(object): CIPHER_LEVEL_KEY = "level" def __init__(self, magic: str = MAGIC_STR, path: str = DEF_PATH, self_check: bool = True): - """SQLite user password database + """SQLite base user password database c1 = c1_encrypt_func(raw_password) c2 = c2_encrypt_func(c1 + magic) c3 = c3_encrypt_func(c1 + c2) @@ -488,7 +488,7 @@ def addUser(self, user: str, password: str, desc: str = ""): self.db.insertRecord(self.CIPHER_TBL, [level2, ""]) self.db.insertRecord(self.CIPHER_TBL, [level3, ""]) - # Finally update user password + # Finally, update user password self.updatePassword(user, password) except SQLiteDatabaseError as error: raise RuntimeError("添加用户「{}」,失败:{}!!!".format(user, error)) @@ -531,7 +531,7 @@ class SQLiteGeneralSettingsItem(DynamicObject): def __init__(self, id_: int, name: str, data: Union[int, float], min_: Union[int, float] = 0, max_: Union[int, float] = 0, precision: int = 0, desc: str = ""): - """SQLite settings item + """SQLite base settings item :param id_: data index corresponding database row id :param name: settings item name @@ -909,7 +909,7 @@ def set_general_table_limit(self, table_name: str, except (TypeError,): raise RuntimeError("Error limit request a tuple list") else: - # Id is column index + # id is column index for column in range(len(limit)): limit[column].id = column diff --git a/core/timer.py b/core/timer.py index 4b77bc3..d419fcd 100644 --- a/core/timer.py +++ b/core/timer.py @@ -215,7 +215,9 @@ def reschedule(self): print("Error: {} is not attached, please add task to tasklet first".format(self)) def is_delayed(self): - """Return true if a task latest running time is out of tasklet schedule time (only works for periodic task)""" + """ + Return true, if a task the latest running time is out of tasklet schedule time (only works for periodic task) + """ if self.periodic and self.is_attached(): return self.runtime.cost > self.runtime.tasklet.tick @@ -242,10 +244,10 @@ def __init__(self, name: str = '', dump: Optional[Callable[[str], None]] = None, err: Callable[[str], None] = print): """Tasklet is sample Round-Robin schedule is base on SwTimer(a threading) Add a Task to tasklet, when task timeout will schedule it once, - if a Task is running, it could be delete or reschedule. + if a Task is running, it could be deleted or reschedule. - A task has an unique id(function name, timeout and periodic params) - at the sametime only one task instance could running in tasklet. + A task has a unique id(function name, timeout and periodic params) + at the sametime only one task instance could be running in tasklet. Add same task to tasklet will cause previous task rescheduled. diff --git a/dashboard/input.py b/dashboard/input.py index cd462bb..d46444d 100644 --- a/dashboard/input.py +++ b/dashboard/input.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- import math -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import QLineEdit, QWidget, QRadioButton, QDialog, QGridLayout, QPushButton, \ + QSizePolicy, QVBoxLayout +from PySide2.QtCore import QPoint, Qt, Signal, QRect, QEvent, QSize, QRectF, QTimerEvent +from PySide2.QtGui import QColor, QFont, QPen, QBrush, QPainter, QIntValidator, QFontMetrics +from PySide2.QtGui import QPaintEvent, QResizeEvent, QMouseEvent from typing import Union, Optional, Tuple from ..core.datatype import * @@ -41,7 +44,7 @@ def __init__(self, diameter: int = 400, numbers: int = 12, def __updatePanelDiameter(self, diameter: int): self.outer_ring_diameter = diameter - self.MARGIN * 2 - self.outer_ring_radius = self.outer_ring_diameter / 2 + self.outer_ring_radius = self.outer_ring_diameter // 2 self.inner_ring_diameter = self.outer_ring_diameter * 0.618 self.inner_ring_radius = self.inner_ring_diameter / 2 @@ -49,8 +52,8 @@ def __updatePanelDiameter(self, diameter: int): self.middle_ring_diameter = self.inner_ring_diameter + (self.outer_ring_diameter - self.inner_ring_diameter) / 2 self.middle_ring_radius = self.middle_ring_diameter / 2 - self.sample_diameter = math.pi * self.middle_ring_diameter / (self.numbers + 2) - self.sample_radius = self.sample_diameter / 2 + self.sample_diameter = int(math.pi * self.middle_ring_diameter / (self.numbers + 2)) + self.sample_radius = int(self.sample_diameter / 2) self.center = QPoint(self.MARGIN + self.outer_ring_radius, self.MARGIN + self.outer_ring_radius) self.update() @@ -97,7 +100,7 @@ def getSelectedNumber(self, point: QRect) -> int: def paintEvent(self, ev: QPaintEvent): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) - font = QFont(self.font_name, self.get_font_size(self.sample_diameter, self.numbers)) + font = QFont(self.font_name, int(self.get_font_size(self.sample_diameter, self.numbers))) # Draw outer ring painter.setPen(QPen(Qt.NoPen)) @@ -113,14 +116,15 @@ def paintEvent(self, ev: QPaintEvent): fm = QFontMetrics(font) painter.setPen(self.bg_color) painter.setFont(font) + # noinspection PyTypeChecker painter.drawText(self.MARGIN + self.outer_ring_diameter / 2 - fm.width(self.state) / 2, self.MARGIN + self.outer_ring_diameter / 2 + fm.height() / 3, self.tr(self.state)) # Draw sample self.sample_poses.clear() - w = self.inner_ring_diameter - s = self.MARGIN + self.sample_diameter + w = int(self.inner_ring_diameter) + s = int(self.MARGIN + self.sample_diameter) self.sample_poses[0] = QRect(s, s, w, w) for idx, angel in enumerate(self.sample_angles): r = self.middle_ring_radius @@ -197,8 +201,8 @@ def sizeHint(self) -> QSize: return QSize(self.__width, self.__height + self.__cap_height * 2) def __updateSize(self, width: int, height: int, cap_height: int): - self.__width = width * self.__scale_x - self.__height = height * self.__scale_y + self.__width = int(width * self.__scale_x) + self.__height = int(height * self.__scale_y) self.__cap_height = cap_height self.__neck_height = self.__cap_height - 5 self.__neck_width = self.__width * 0.618 @@ -216,12 +220,12 @@ def paintEvent(self, ev: QPaintEvent): painter.setPen(QPen(Qt.NoPen)) painter.setBrush(QBrush(bg, Qt.SolidPattern)) painter.drawRoundedRect(0, 0, self.__width, self.__cap_height, 5.0, 5.0) - painter.drawRoundedRect(self.__width / 5, self.__cap_height - 10, - self.__width / 5 * 3, self.__neck_height * 2, 5.0, 5.0) + painter.drawRoundedRect(self.__width // 5, self.__cap_height - 10, + self.__width // 5 * 3, self.__neck_height * 2, 5.0, 5.0) painter.drawRoundedRect(QRectF(0.0, self.__cap_height * 1.5, self.__width, self.__height), 5.0, 5.0) painter.setPen(QPen(QColor(fg))) - painter.setFont(QFont("Times New Roman", self.__width / 3 / self.__scale_factor)) + painter.setFont(QFont("Times New Roman", int(self.__width / 3 / self.__scale_factor))) painter.drawText(self.rect(), Qt.AlignLeft | Qt.AlignVCenter, self.text) def slotChecked(self): @@ -248,7 +252,10 @@ class VirtualNumberInput(QLineEdit): __textColor = QColor(255, 255, 255) __hoverColor = QColor(0x96, 0xf7, 0x51) - def __init__(self, initial_value=0, min_=0, max_=9999, decimals=0, parent=None): + # noinspection PyTypeChecker + def __init__(self, initial_value: Union[int, float] = 0, + min_: Union[int, float] = 0, max_: Union[int, float] = 9999, decimals: int = 0, + parent: Optional[QWidget] = None): super(VirtualNumberInput, self).__init__(parent) self.setReadOnly(True) self.setValidator(QIntValidator(min_, max_)) @@ -304,8 +311,11 @@ def hoverStylesheet(cls): UiColorInput.get_bg_color_stylesheet(cls.color2Tuple(cls.getThemeColor())) def showKeyboard(self): + # noinspection PyTypeChecker input_min = self.property("min") + # noinspection PyTypeChecker input_max = self.property("max") + # noinspection PyTypeChecker input_decimals = self.property("decimals") if not input_decimals: value = VirtualNumberKeyboard.getInt(min_=input_min, max_=input_max, parent=self) @@ -317,6 +327,7 @@ def showKeyboard(self): self.numberChanged.emit(value) def setValue(self, value: Union[int, float]): + # noinspection PyTypeChecker number_decimals = self.property('decimals') self.setText("{0:.{1}f}".format(value, number_decimals) if number_decimals else str(value)) @@ -408,13 +419,16 @@ def __initUi(self): key_layout = QGridLayout() for row, row_keys in enumerate(self.key_map): for column, key in enumerate(row_keys): + # noinspection PyTypeChecker key = { self.OK_KEY: self.tr("OK"), self.CANCEL_KEY: self.tr("Cancel") }.get(key, key) btn = QPushButton(key) btn.clicked.connect(self.slotNumberClicked) + # noinspection PyTypeChecker btn.setProperty("name", key) + # noinspection PyTypeChecker btn.setProperty("value", key) btn.setMinimumHeight(50 * self.__scale_factor) btn.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) @@ -439,7 +453,7 @@ def __initStyle(self): self.ui_display.setMinimumHeight(self.FONT_BASE_SIZE * 4 * self.__scale_factor) self.ui_display.setMaxLength(len("{}".format(self.max_number)) + self.number_decimals + 1) - meter = QFontMetrics(QFont("等线 Light", self.DISPLAY_FONT_SIZE * self.__scale_factor)) + meter = QFontMetrics(QFont("等线 Light", int(self.DISPLAY_FONT_SIZE * self.__scale_factor))) self.ui_display.setMinimumWidth(meter.width("0" * self.ui_display.maxLength() + "-.")) [item.setStyleSheet(self.rg_color) for item in (self.ui_min, self.ui_max)] @@ -453,7 +467,9 @@ def __initStyle(self): self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint) def __initSignalAndSlots(self): + # noinspection PyTypeChecker ok = self.ui_manager.getByValue("name", self.tr(self.OK_KEY), QPushButton) + # noinspection PyTypeChecker cancel = self.ui_manager.getByValue("name", self.tr(self.CANCEL_KEY), QPushButton) ok.clicked.connect(self.accept) cancel.clicked.connect(self.reject) diff --git a/dashboard/monitor.py b/dashboard/monitor.py index 0fa0771..5261599 100644 --- a/dashboard/monitor.py +++ b/dashboard/monitor.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtGui import QColor, QFont, QFontMetrics, QPaintEvent, QPen, QBrush, QPainter +from PySide2.QtWidgets import QLabel, QWidget, QVBoxLayout, QSplitter, QHBoxLayout +from PySide2.QtCore import QSize, Qt, QRectF from typing import Union, Optional from ..gui.widget import BasicWidget @@ -115,8 +116,8 @@ def __getNoneState(self) -> str: def sizeHint(self) -> QSize: meter1 = QFontMetrics(QFont("宋体", self.DEF_FONT_SIZE)) - meter2 = QFontMetrics(QFont(self.DEF_RV_FONT, self.__getFontSize())) - meter3 = QFontMetrics(QFont(self.DEF_RV_FONT, self.__getFontSize() / 2)) + meter2 = QFontMetrics(QFont(self.DEF_RV_FONT, int(self.__getFontSize()))) + meter3 = QFontMetrics(QFont(self.DEF_RV_FONT, int(self.__getFontSize() / 2))) min_height = meter1.height() * len(self._title) * 1.5 * 1.5 min_width = meter1.width("中") + meter2.width(self._max_number * "0") + meter3.width(".00") * 2.5 @@ -141,13 +142,13 @@ def paintEvent(self, ev: QPaintEvent): painter.setPen(QPen(QColor(Qt.white))) # Integer part - painter.setFont(QFont(self.DEF_RV_FONT, self.__getFontSize())) + painter.setFont(QFont(self.DEF_RV_FONT, int(self.__getFontSize()))) current_str = "{}".format(integer if self.getRV() >= 0 else self.__getNoneState()) painter.drawText(location, Qt.AlignCenter, current_str) # Decimal part if self.getRV() >= 0 and self._decimal_display: - decimal_font = QFont(self.DEF_RV_FONT, self.__getFontSize() / 2) + decimal_font = QFont(self.DEF_RV_FONT, int(self.__getFontSize() / 2)) painter.setFont(decimal_font) space = 3 * (self._max_number - len(current_str)) if len(current_str) > 2: diff --git a/dashboard/status.py b/dashboard/status.py index 232c9cc..75b3440 100644 --- a/dashboard/status.py +++ b/dashboard/status.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtGui import QColor, QFont, QFontMetrics, QPainter, QPen, QBrush, QResizeEvent, QMouseEvent, QPaintEvent +from PySide2.QtCore import Qt, Signal, QSize, QEvent, QRectF, QTimer +from PySide2.QtWidgets import * from typing import Union, Optional, Sequence from ..misc.windpi import get_program_scale_factor __all__ = ['DashboardStatusIcon'] @@ -166,7 +167,7 @@ def leaveEvent(self, ev: QEvent): self.update() def resizeEvent(self, ev: QResizeEvent): - self._font = QFont(self.DEF_FONT_NAME, self.__getFontSize()) + self._font = QFont(self.DEF_FONT_NAME, int(self.__getFontSize())) self.update() def mousePressEvent(self, ev: QMouseEvent): diff --git a/demos/binder_demo.py b/demos/binder_demo.py index 0129646..8976906 100644 --- a/demos/binder_demo.py +++ b/demos/binder_demo.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- import sys from ..gui.binder import SpinBoxBinder, ComboBoxBinder -from PySide.QtCore import QTextCodec -from PySide.QtGui import QWidget, QGridLayout, QSpinBox, QDoubleSpinBox, QLabel, QComboBox, QApplication, QLineEdit +from PySide2.QtWidgets import QWidget, QGridLayout, QSpinBox, QDoubleSpinBox, QLabel, QComboBox, QApplication, QLineEdit class Demo(QWidget): @@ -71,7 +70,6 @@ def __init__(self, parent=None): if __name__ == "__main__": app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) demo = Demo() demo.show() sys.exit(app.exec_()) diff --git a/demos/button_demo.py b/demos/button_demo.py index 611d178..301f133 100644 --- a/demos/button_demo.py +++ b/demos/button_demo.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- import sys from .images import ImagesPath -from PySide.QtCore import QTextCodec from ..gui.button import RectButton, RoundButton, IconButton, StateButton, TextButton -from PySide.QtGui import QWidget, QHBoxLayout, QVBoxLayout, QGridLayout, QComboBox, QPushButton, QLabel, \ - QImageReader, QFileDialog, QApplication +from PySide2.QtGui import QImageReader +from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QGridLayout, QComboBox, QPushButton, QLabel, \ + QFileDialog, QApplication class DemoWidget(QWidget): @@ -64,7 +64,6 @@ def slotAddButton(self): if __name__ == '__main__': app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = DemoWidget() widget.show() sys.exit(app.exec_()) diff --git a/demos/checkbox_demo.py b/demos/checkbox_demo.py index 27fd309..2809725 100644 --- a/demos/checkbox_demo.py +++ b/demos/checkbox_demo.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- import sys -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import QPushButton, QLabel, QVBoxLayout, QTextEdit, QHBoxLayout, QColorDialog, QApplication, \ + QDoubleSpinBox +from PySide2.QtCore import Qt +from PySide2.QtGui import QColor from ..gui.checkbox import * from ..core.datatype import * from ..gui.widget import BasicWidget, TableWidget @@ -13,6 +15,7 @@ class CheckboxDemoWidget(BasicWidget): def __init__(self, parent=None): super(CheckboxDemoWidget, self).__init__(parent) + # noinspection PyTypeChecker def _initUi(self): self.def_style = CheckBoxStyleSheet.default() style = DynamicObject(background=(240, 240, 240), font=("宋体", 9)) @@ -116,7 +119,6 @@ def slotCheckboxStyleChanged(self, stylesheet): if __name__ == '__main__': app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = CheckboxDemoWidget() widget.show() sys.exit(app.exec_()) diff --git a/demos/container_demo.py b/demos/container_demo.py index 4850e07..867c4fe 100644 --- a/demos/container_demo.py +++ b/demos/container_demo.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import sys from ..gui.container import ComboBoxGroup -from PySide.QtGui import QWidget, QPushButton, QLabel, QCheckBox, QApplication, QFrame, QComboBox, \ +from PySide2.QtWidgets import QWidget, QPushButton, QLabel, QCheckBox, QApplication, QFrame, QComboBox, \ QVBoxLayout, QGridLayout diff --git a/demos/dashboard_input_test.py b/demos/dashboard_input_test.py index 30b35f5..ca3a83d 100644 --- a/demos/dashboard_input_test.py +++ b/demos/dashboard_input_test.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- import sys import math -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import * from ..gui.widget import BasicWidget from ..gui.container import ComponentManager from ..dashboard.input import VirtualNumberInput @@ -48,6 +47,7 @@ def _initUi(self): self.setLayout(layout) self.ui_manager = ComponentManager(layout) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Dashboard 虚拟键盘输入测试")) def _initData(self): @@ -78,6 +78,7 @@ def _initSignalAndSlots(self): self.ui_theme_color.clicked.connect(self.slotChangeKeyboardThemeColor) self.ui_hover_color.clicked.connect(self.slotChangeKeyboardHoverColor) + # noinspection PyTypeChecker def slotInputRangeChanged(self, value): if self.sender() == self.ui_int_min: self.ui_int_input.setProperty("min", value) @@ -106,7 +107,6 @@ def slotChangeKeyboardThemeColor(self): if __name__ == '__main__': app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = DemoDashboardInput() widget.show() sys.exit(app.exec_()) diff --git a/demos/dialog_demo.py b/demos/dialog_demo.py index 9332ffa..b5fcabc 100644 --- a/demos/dialog_demo.py +++ b/demos/dialog_demo.py @@ -1,12 +1,10 @@ # -*- coding: utf-8 -*- import sys import hashlib -from PySide.QtCore import QTextCodec - from ..gui.dialog import * from ..misc.settings import UiInputSetting from ..gui.container import ComponentManager -from PySide.QtGui import QApplication, QPushButton, QSpinBox, QLabel, QHBoxLayout, QVBoxLayout, QWidget, QLineEdit +from PySide2.QtWidgets import QApplication, QPushButton, QSpinBox, QLabel, QHBoxLayout, QVBoxLayout, QWidget, QLineEdit class DialogTest(QWidget): @@ -17,6 +15,7 @@ def __init__(self, parent=None): self.__initSignalAndSlots() self.__uiManager = ComponentManager(self.layout()) + # noinspection PyTypeChecker def __initUi(self): diff = QHBoxLayout() self.__diff = QPushButton(self.tr("获取颜色(RGB 不同)")) @@ -34,6 +33,7 @@ def __initUi(self): same = QHBoxLayout() self.__sameColor = QLabel() self.__sameColor.setMinimumSize(32, 15) + # noinspection PyTypeChecker self.__same = QPushButton(self.tr("获取颜色(RGB 相同)")) color = QSpinBox() color.setRange(0, 7) @@ -160,7 +160,6 @@ def __slotSelectSameColor(self): if __name__ == "__main__": app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) window = DialogTest() window.show() sys.exit(app.exec_()) diff --git a/demos/event_filter_test.py b/demos/event_filter_test.py index 37c0919..cda8ccc 100644 --- a/demos/event_filter_test.py +++ b/demos/event_filter_test.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- import sys -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import * +from PySide2.QtCore import QEvent + from ..gui.msgbox import * from ..gui.widget import BasicWidget from ..gui.container import ComponentManager @@ -13,10 +14,9 @@ def __init__(self, parent=None): super(DemoEventFilter, self).__init__(parent) self.disable_event_handle = CustomEventFilterHandler( - (QRadioButton, QCheckBox, QSpinBox, QDoubleSpinBox, QPushButton, QLineEdit), (QEvent.MouseButtonRelease, QEvent.MouseButtonPress, QEvent.MouseButtonDblClick, - QEvent.KeyPress, QEvent.KeyRelease), + QEvent.KeyPress, QEvent.KeyRelease, QEvent.Wheel), self, ) @@ -71,7 +71,6 @@ def slotDisableEdit(self): if __name__ == '__main__': app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = DemoEventFilter() widget.show() sys.exit(app.exec_()) diff --git a/demos/monitor_demo.py b/demos/monitor_demo.py index 4c2dc29..ef89938 100644 --- a/demos/monitor_demo.py +++ b/demos/monitor_demo.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- import sys import random -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import * from ..dashboard.monitor import * from ..gui.widget import BasicWidget from ..gui.container import ComponentManager @@ -51,7 +50,6 @@ def timerEvent(self, ev): if __name__ == '__main__': app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = DemoWidget() widget.show() sys.exit(app.exec_()) diff --git a/demos/msgbox_demo.py b/demos/msgbox_demo.py index 2aee947..971a77f 100644 --- a/demos/msgbox_demo.py +++ b/demos/msgbox_demo.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import sys from ..gui.msgbox import showMessageBox, MB_TYPES -from PySide.QtGui import QWidget, QLabel, QLineEdit, QPushButton, QHBoxLayout, QApplication, QComboBox +from PySide2.QtWidgets import QWidget, QLabel, QLineEdit, QPushButton, QHBoxLayout, QApplication, QComboBox class DemoWidget(QWidget): @@ -29,7 +29,7 @@ def __init__(self, parent=None): self.setWindowTitle("MessageBox Demo") def slotShowMessageBox(self): - showMessageBox(self.messageType.currentText(), self.contextEdit.text(), self.titleEdit.text()) + showMessageBox(self, self.messageType.currentText(), self.contextEdit.text(), self.titleEdit.text()) if __name__ == "__main__": diff --git a/demos/serial_transfer_test.py b/demos/serial_transfer_test.py index 657bd71..3575074 100644 --- a/demos/serial_transfer_test.py +++ b/demos/serial_transfer_test.py @@ -1,12 +1,11 @@ # -*- coding: utf-8 -*- - import sys import argparse from ..protocol.serialport import SerialTransferProtocol, SerialPort, SerialTransferError if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("-p", "--port", help="Serial port name", default="COM17") + parser.add_argument("-p", "--port", help="Serial port name", default="COM65") parser.add_argument("-t", "--timeout", help="Serial port timeout", default=1) parser.add_argument("-b", "--baudrate", help="Serial port baudrate", default=38400) args = vars(parser.parse_args()) diff --git a/demos/setup_test.py b/demos/setup_test.py index 9180ac4..2eb3380 100644 --- a/demos/setup_test.py +++ b/demos/setup_test.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - from ..misc.setup import get_git_commit_count, get_git_release_hash, get_git_release_date diff --git a/demos/status_demo.py b/demos/status_demo.py index ea208ce..45c9871 100644 --- a/demos/status_demo.py +++ b/demos/status_demo.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- import sys import random -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import * +from PySide2.QtGui import QColor from ..gui.widget import BasicWidget from ..gui.container import ComponentManager from ..dashboard.status import DashboardStatusIcon @@ -12,6 +12,7 @@ class DemoDashboardStatus(BasicWidget): def __init__(self, parent=None): super(DemoDashboardStatus, self).__init__(parent) + # noinspection PyTypeChecker def _initUi(self): layout = QHBoxLayout() @@ -83,7 +84,6 @@ def timerEvent(self, ev): if __name__ == '__main__': app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = DemoDashboardStatus() widget.show() sys.exit(app.exec_()) diff --git a/demos/tabbar_demo.py b/demos/tabbar_demo.py index 14b9562..30f061c 100644 --- a/demos/tabbar_demo.py +++ b/demos/tabbar_demo.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import sys -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import * from ..gui.misc import TabBar from ..gui.container import ComponentManager @@ -10,6 +9,7 @@ class TabBarDemo(QWidget): PositionText = ["East", "West", "South", "North"] Positions = [QTabWidget.East, QTabWidget.West, QTabWidget.South, QTabWidget.North] + # noinspection PyTypeChecker def __init__(self, parent=None): super(TabBarDemo, self).__init__(parent) @@ -54,7 +54,6 @@ def slotCreateTabWidget(self): if __name__ == "__main__": app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) widget = TabBarDemo() widget.show() sys.exit(app.exec_()) diff --git a/demos/tarmanager_test.py b/demos/tarmanager_test.py index 208515b..624b314 100644 --- a/demos/tarmanager_test.py +++ b/demos/tarmanager_test.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- - import os import sys import getopt diff --git a/demos/widget_demo.py b/demos/widget_demo.py index 062eb91..9886723 100644 --- a/demos/widget_demo.py +++ b/demos/widget_demo.py @@ -2,8 +2,9 @@ import os import sys import datetime -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtWidgets import * +from PySide2.QtCore import Qt, QDir, Signal +from PySide2.QtGui import QColor, QImageReader from ..gui.widget import * from ..misc.settings import * @@ -12,6 +13,8 @@ from ..gui.dialog import showFileImportDialog from ..gui.widget import SerialPortSettingWidget from ..gui.misc import NavigationItem, NavigationBar +from ..misc.crypto import RSAPrivateKeyHandle +from ..gui.srm import SoftwareRegistrationMachineWidget class NavigationWidget(QMainWindow): @@ -250,7 +253,7 @@ def __get_text(self, title, lable): return text if ok else "Header" def __get_number(self, title, label, default, min_value, max_value): - i, ok = QInputDialog.getInteger(self, title, label, default, min_value, max_value, 1) + i, ok = QInputDialog.getInt(self, title, label, default, min_value, max_value, 1) return i def __slotCreateTable(self): @@ -366,6 +369,7 @@ def __init__(self, parent=None): super(SerialSettingWidgetTest, self).__init__(parent) self.__text = QTextEdit() self.__setting = SerialPortSettingWidget() + # noinspection PyTypeChecker get_setting = QPushButton(self.tr("获取串口设置")) get_setting.clicked.connect(self.slotGetSetting) @@ -375,6 +379,7 @@ def __init__(self, parent=None): layout.addWidget(self.__text) self.setLayout(layout) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("串口设置对话框")) def slotGetSetting(self): @@ -388,6 +393,7 @@ def __init__(self, parent=None): layout = QVBoxLayout() self.widget = JsonSettingWidget(UiInputSetting.getDemoSettings()) self.widget.settingChanged.connect(self.slotShowData) + # noinspection PyTypeChecker self.ui_button = QPushButton(self.tr("Get settings")) self.ui_button.clicked.connect(self.slotShowData) self.ui_data = QTextEdit() @@ -438,8 +444,10 @@ def __init__(self, parent=None): self.widget = MultiJsonSettingsWidget(MultiJsonSetting.default(), data) self.widget.settingChanged.connect(self.slotShowData) + # noinspection PyTypeChecker self.ui_get = QPushButton(self.tr("Get settings")) self.ui_get.clicked.connect(self.slotShowData) + # noinspection PyTypeChecker self.ui_reset = QPushButton(self.tr("Reset data")) self.ui_reset.clicked.connect(self.slotResetData) self.ui_data = QTextEdit() @@ -640,7 +648,7 @@ def showImage(self): data = fp.read() image = QImageReader(file) - self.drawFromMem.emit(data, str(image.format())) + self.drawFromMem.emit(data, bytes(image.format()).decode()) # self.imageWidget.drawFromMem(data, str(image.format())) self.imageWidget.setHidden(False) elif self.sender() == self.imageTextButton: @@ -665,7 +673,6 @@ def setCursor(self, x, y, colorMode): if __name__ == "__main__": app = QApplication(sys.argv) - QTextCodec.setCodecForTr(QTextCodec.codecForName("UTF-8")) window = Demo() window.show() sys.exit(app.exec_()) diff --git a/gui/__init__.py b/gui/__init__.py index 564b2c3..47deab5 100644 --- a/gui/__init__.py +++ b/gui/__init__.py @@ -1 +1 @@ -__all__ = ['button', 'msgbox', 'widget', 'container', 'binder', 'dialog', 'icon', 'misc', 'checkbox'] \ No newline at end of file +__all__ = ['button', 'msgbox', 'mailbox', 'widget', 'container', 'binder', 'dialog', 'icon', 'misc', 'checkbox'] diff --git a/gui/binder.py b/gui/binder.py index 05deb3a..6c4c58d 100644 --- a/gui/binder.py +++ b/gui/binder.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -from PySide.QtCore import QObject +from PySide2.QtCore import QObject from typing import Optional, Union, Callable, Sequence, Tuple -from PySide.QtGui import QSpinBox, QDoubleSpinBox, QLabel, QComboBox, QWidget, QLineEdit +from PySide2.QtWidgets import QSpinBox, QDoubleSpinBox, QLabel, QComboBox, QWidget, QLineEdit __all__ = ['SpinBoxBinder', 'ComboBoxBinder'] @@ -78,6 +78,7 @@ def eventProcess(self, value: Union[int, float]): receiver.setValue(self.__remap(factor, value)) # QLabel or QLineEdit elif isinstance(receiver, (QLabel, QLineEdit)): + # noinspection PyTypeChecker fmt = receiver.property('format') fmt = fmt if isinstance(fmt, str) else "{}" receiver.setText(fmt.format(self.__remap(factor, value))) diff --git a/gui/button.py b/gui/button.py index 4ac763a..1c3e32c 100644 --- a/gui/button.py +++ b/gui/button.py @@ -12,11 +12,9 @@ """ import os.path from typing import Optional, Union, Tuple, Sequence -from PySide.QtCore import Signal, Qt, QSize, QRect -from PySide.QtGui import QPushButton, QKeySequence, QImageReader, QPixmap, QPainter, QFont, QColor, QBrush, QPen, \ - QWidget, QPaintEvent - - +from PySide2.QtWidgets import QPushButton, QWidget +from PySide2.QtCore import Signal, Qt, QSize, QRect +from PySide2.QtGui import QKeySequence, QImageReader, QPixmap, QPainter, QFont, QColor, QBrush, QPen, QPaintEvent __all__ = ['TextButton', 'IconButton', 'RectButton', 'RoundButton', 'StateButton'] @@ -25,6 +23,7 @@ def __init__(self, width: int = 0, height: int = 0, shortCut: str = "", styleSheet: str = "", tips: str = "", parent: Optional[QWidget] = None): super(BaseButton, self).__init__(parent) if isinstance(shortCut, str) and len(shortCut): + # noinspection PyTypeChecker self.setShortcut(QKeySequence(self.tr(shortCut))) if isinstance(styleSheet, str) and len(styleSheet): @@ -59,6 +58,7 @@ def __init__(self, width: int = 0, height: int = 0, text: Tuple[str, str] = ("", self.text = ("", "") if isinstance(text, (tuple, list)) and len(text) == 2: self.text = text + # noinspection PyTypeChecker self.setText(self.tr(text[0])) def slotChangeView(self, ck: bool): @@ -109,6 +109,7 @@ def paintEvent(self, ev: QPaintEvent): idx = self.isChecked() if self.iconSize != QSize(-1, -1): + # noinspection PyTypeChecker pixmap.loadFromData(self.iconData[idx]) painter.drawPixmap(self.rect(), pixmap) diff --git a/gui/checkbox.py b/gui/checkbox.py index 9f7973a..938d4b8 100644 --- a/gui/checkbox.py +++ b/gui/checkbox.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- import json -from PySide.QtGui import * -from PySide.QtCore import * from typing import Optional, Union + +from PySide2.QtWidgets import * +from PySide2.QtCore import Qt, Signal, Slot, QSize, QPointF, QEvent, QModelIndex, QAbstractItemModel +from PySide2.QtGui import QFont, QColor, QPen, QBrush, QPainter, QMouseEvent, QPaintEvent, QFontMetrics, QPolygonF + from ..core.datatype import DynamicObject, DynamicObjectEncodeError, str2number __all__ = ['CheckBox', 'CheckBoxStyleSheet', 'CheckBoxDelegate'] @@ -24,7 +27,7 @@ def getFont(self) -> QFont: try: return QFont(*self.font) except TypeError: - return QFont(("等线 Light", 11)) + return QFont("等线 Light", 11) def getBoxColor(self) -> QColor: try: diff --git a/gui/container.py b/gui/container.py index e9e944e..7734e3a 100644 --- a/gui/container.py +++ b/gui/container.py @@ -3,8 +3,8 @@ Provide UI elements container """ -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtCore import * +from PySide2.QtWidgets import * from typing import Union, Optional, List, Any, Sequence from .binder import * @@ -275,12 +275,14 @@ def getComponentData(component: QWidget) -> Any: elif isinstance(component, NetworkInterfaceSelector): return component.currentSelect() elif isinstance(component, QComboBox): + # noinspection PyTypeChecker return component.currentText() if component.property("format") == "text" else component.currentIndex() elif isinstance(component, QCheckBox): return component.isChecked() elif isinstance(component, QRadioButton): return component.isChecked() elif isinstance(component, QLineEdit): + # noinspection PyTypeChecker return { "int": str2number(component.text()), "float": str2float(component.text()) @@ -296,6 +298,7 @@ def getComponentData(component: QWidget) -> Any: elif isinstance(component, QLCDNumber): return component.value() elif isinstance(component, QPushButton): + # noinspection PyTypeChecker return component.property(ComponentManager.QPushButtonPrivateDataKey) else: return "" @@ -339,6 +342,7 @@ def setComponentData(component: QWidget, data: Any): elif isinstance(component, QLCDNumber): component.display(str2float(data)) elif isinstance(component, QPushButton): + # noinspection PyTypeChecker component.setProperty(ComponentManager.QPushButtonPrivateDataKey, data) @staticmethod @@ -401,10 +405,10 @@ def getAllComponents(obj: QWidget) -> List[QWidget]: components.extend(ComponentManager.getAllComponents(widget)) continue - sublayout = item.layout() + sub_layout = item.layout() # Is a QLayout - if isinstance(sublayout, QLayout): - components.extend(ComponentManager.getAllComponents(sublayout)) + if isinstance(sub_layout, QLayout): + components.extend(ComponentManager.getAllComponents(sub_layout)) return components @@ -514,6 +518,7 @@ def getByValue(self, key: str, value: Any, # Search by property for component in self.__getComponentsWithType(componentType): + # noinspection PyTypeChecker if component.property(key) == value: return component @@ -533,6 +538,7 @@ def findKey(self, key: str, componentType: Optional[QWidget.__class__] = None) - lst = list() for component in self.__getComponentsWithType(componentType): + # noinspection PyTypeChecker if component.property(key) is not None: lst.append(component) @@ -548,6 +554,7 @@ def findValue(self, key: str, searchValue: Any, componentType: Optional[QWidget. """ lst = list() for component in self.findKey(key, componentType): + # noinspection PyTypeChecker value = component.property(key) if isinstance(value, str) and searchValue in value or value == searchValue: lst.append(component) @@ -569,6 +576,7 @@ def getData(self, key: str, components = self.findKey(key, componentTypes) for component in components: + # noinspection PyTypeChecker value = component.property(key) if value in exclude: @@ -583,6 +591,7 @@ def setData(self, key: str, data: Union[str, dict]) -> bool: return False for component in self.getAll(): + # noinspection PyTypeChecker property_key = component.property(key) value = data.get(property_key) diff --git a/gui/dialog.py b/gui/dialog.py index c31c45d..07e5f92 100644 --- a/gui/dialog.py +++ b/gui/dialog.py @@ -2,8 +2,9 @@ import os import sys import hashlib -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtCore import * +from PySide2.QtWidgets import * +from PySide2.QtGui import QColor, QCloseEvent, QShowEvent from typing import Optional, Union, Sequence, Callable, Any from .msgbox import * @@ -77,6 +78,7 @@ def __initUi(self, without_buttons: bool): self.__depth.setTickInterval(10) self.__depth.setTickPosition(QSlider.TicksBelow) self.__depth.valueChanged.connect(self.slotChangeDepth) + # noinspection PyTypeChecker depthLayout.addWidget(QLabel(self.tr("Luminance"))) depthLayout.addWidget(self.__depth) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) @@ -89,6 +91,7 @@ def __initUi(self, without_buttons: bool): self.__green = QSpinBox() self.__blue = QSpinBox() valueLayout = QHBoxLayout() + # noinspection PyTypeChecker for text, spinbox in ( (self.tr("Red"), self.__red), (self.tr("Green"), self.__green), (self.tr("Blue"), self.__blue) ): @@ -114,6 +117,7 @@ def __initUi(self, without_buttons: bool): layout.addWidget(button) self.setLayout(layout) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Please select color")) def __getColor(self) -> Color: @@ -165,9 +169,9 @@ def __updateColor(self, color: QColor): # Basic mode if self.__basic: r, g, b = self.__getColor() - self.__red.setEnabled(r) - self.__blue.setEnabled(b) - self.__green.setEnabled(g) + self.__red.setEnabled(bool(r)) + self.__blue.setEnabled(bool(b)) + self.__green.setEnabled(bool(g)) def slotChangeColor(self): btn = self.sender() @@ -259,6 +263,7 @@ def __init__(self, timeout: float = 0.04, parent: Optional[QWidget] = None): layout.addWidget(button) self.setLayout(layout) self.setFixedSize(self.sizeHint()) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Please select serial port")) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) @@ -294,6 +299,7 @@ def __init__(self, settings: dict = SerialPortSettingWidget.DEFAULTS, parent: Op self.setLayout(layout) self.setFixedSize(self.sizeHint()) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Serial Configuration Dialog")) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) @@ -325,6 +331,7 @@ def __init__(self, port: int, timeout: float = 0.04, network: str = '', parent: layout.addWidget(button) self.setLayout(layout) self.setFixedSize(self.sizeHint()) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Please select address")) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) @@ -361,6 +368,7 @@ def __init__(self, name: str = "", address: str = "", network: str = "", layout.addWidget(button) self.setLayout(layout) self.setFixedSize(self.sizeHint()) + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Please Select Network Interface")) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) @@ -404,7 +412,8 @@ def getInterfaceNetwork(cls, name: str = "", class ProgressDialog(QProgressDialog): progressCanceled = Signal(bool) - DEF_TITLE = QApplication.translate("ProgressDialog", "Operation progress", None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + DEF_TITLE = QApplication.translate("ProgressDialog", "Operation progress", None) def __init__(self, parent: QWidget, title: str = DEF_TITLE, max_width: int = 350, cancel_button: Optional[str] = None, closeable: bool = True, cancelable: bool = False): @@ -415,11 +424,14 @@ def __init__(self, parent: QWidget, title: str = DEF_TITLE, max_width: int = 350 self.__cancelable = cancelable self.setFixedWidth(max_width) self.setWindowModality(Qt.WindowModal) + # noinspection PyTypeChecker self.setWindowTitle(self.tr(title)) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) if cancel_button is None: + # noinspection PyTypeChecker self.setCancelButton(None) else: + # noinspection PyTypeChecker self.setCancelButtonText(self.tr(cancel_button)) def closeEvent(self, ev: QCloseEvent): @@ -427,7 +439,9 @@ def closeEvent(self, ev: QCloseEvent): ev.ignore() if self.__cancelable: + # noinspection PyTypeChecker if showQuestionBox(self, self.tr("Cancel") + " " + self.windowTitle() + " ?"): + # noinspection PyTypeChecker self.setLabelText(self.tr("Canceling please wait...")) self.setCancelState(True) @@ -439,7 +453,6 @@ def showEvent(self, ev: QShowEvent): y = self.parent().geometry().y() + self.parent().height() / 2 - self.height() / 2 self.move(QPoint(x, y)) - @Slot() def slotHidden(self): self.setProgress(self.maximum()) self.setHidden(True) @@ -464,7 +477,6 @@ def setLabelText(self, text: str): self.setWhatsThis(text) super(ProgressDialog, self).setLabelText(text) - @Slot(int) def setProgress(self, value: int): self.setValue(value) if value != self.maximum(): @@ -508,6 +520,7 @@ def __init__(self, widget_cls: Union[BasicJsonSettingWidget.__class__, MultiTabJ try: title = settings.layout.get_name() if isinstance(settings.layout, UiLayout) else settings.layout.get("name") except AttributeError: + # noinspection PyTypeChecker title = self.tr("Configuration Dialog") self.setLayout(layout) @@ -515,7 +528,8 @@ def __init__(self, widget_cls: Union[BasicJsonSettingWidget.__class__, MultiTabJ self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) def tr(self, text: str) -> str: - return QApplication.translate("BasicJsonSettingDialog", text, None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + return QApplication.translate("BasicJsonSettingDialog", text, None) def getJsonData(self) -> Optional[dict]: if not self.result(): @@ -596,7 +610,7 @@ def __init__(self, settings: DynamicObject, data: Optional[dict] = None, super(MultiTabJsonSettingsDialog, self).__init__(MultiTabJsonSettingsWidget, settings, data, reset, apply, parent) scale_x, _ = get_program_scale_factor() - self.setMinimumWidth(len(settings.layout.layout) * 120 * scale_x) + self.setMinimumWidth(int(len(settings.layout.layout) * 120 * scale_x)) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) def getJsonSettings(self) -> Optional[DynamicObject]: @@ -617,15 +631,11 @@ def getSettings(cls, settings: DynamicObject, data: Optional[dict] = None, class PasswordDialog(QDialog): - @staticmethod - def defaultHashFunction(data: Union[bytes, bytearray, memoryview]) -> str: - return hashlib.md5(data).hexdigest() - def __init__(self, password: Optional[str] = None, - hash_function: PasswordHashFunction = defaultHashFunction, + hash_function: PasswordHashFunction = lambda x: hashlib.md5(x).hexdigest(), style: str = 'font: 75 16pt "Arial"', parent: Optional[QWidget] = None): super(PasswordDialog, self).__init__(parent) - if not hasattr(hash_function, "__call__"): + if not callable(hash_function): raise TypeError("hash_function must be a callable object}") self.__new_password = "" @@ -640,16 +650,20 @@ def __init__(self, password: Optional[str] = None, def __initUi(self): # Ui elements self.ui_old_password = QLineEdit() + # noinspection PyTypeChecker self.ui_old_password.setPlaceholderText(self.tr("Please input old password")) self.ui_new_password = QLineEdit() + # noinspection PyTypeChecker self.ui_new_password.setPlaceholderText(self.tr("Please input new password")) self.ui_show_password = QCheckBox() self.ui_confirm_password = QLineEdit() + # noinspection PyTypeChecker self.ui_confirm_password.setPlaceholderText(self.tr("Confirm new password")) + # noinspection PyTypeChecker self.ui_old_password_label = QLabel(self.tr("Old password")) self.ui_buttons = QDialogButtonBox(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) @@ -658,15 +672,18 @@ def __initUi(self): item_layout.addWidget(self.ui_old_password_label, 0, 0) item_layout.addWidget(self.ui_old_password, 0, 1) + # noinspection PyTypeChecker item_layout.addWidget(QLabel(self.tr("New password")), 1, 0) item_layout.addWidget(self.ui_new_password, 1, 1) + # noinspection PyTypeChecker item_layout.addWidget(QLabel(self.tr("Confirm new password")), 2, 0) item_layout.addWidget(self.ui_confirm_password, 2, 1) sub_layout = QHBoxLayout() sub_layout.addWidget(self.ui_show_password) self.ui_show_password.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) + # noinspection PyTypeChecker sub_layout.addWidget(QLabel(self.tr("Show password"))) item_layout.addLayout(sub_layout, 3, 1) @@ -678,8 +695,10 @@ def __initUi(self): # Mode switch if self.__password: + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Change password")) else: + # noinspection PyTypeChecker self.setWindowTitle(self.tr("Reset password")) self.ui_old_password.setHidden(True) self.ui_old_password_label.setHidden(True) @@ -708,12 +727,15 @@ def accept(self, *args, **kwargs): confirm = self.__hash_function(self.ui_confirm_password.text().encode()) if self.__password and old != self.__password: + # noinspection PyTypeChecker return showMessageBox(self, MB_TYPE_ERR, self.tr("Old password error, please retry")) if new != confirm: + # noinspection PyTypeChecker return showMessageBox(self, MB_TYPE_ERR, self.tr("New password mismatch, please retry")) if len(self.ui_new_password.text()) == 0 or len(self.ui_confirm_password.text()) == 0: + # noinspection PyTypeChecker return showMessageBox(self, MB_TYPE_ERR, self.tr("Password can't be empty, please retry!")) self.__new_password = new @@ -725,14 +747,15 @@ def getNewPassword(self) -> str: return self.__new_password @staticmethod - def resetPassword(hash_function: PasswordHashFunction = defaultHashFunction, + def resetPassword(hash_function: PasswordHashFunction = lambda x: hashlib.md5(x).hexdigest(), style: str = '', parent: Optional[QWidget] = None) -> str: dialog = PasswordDialog(hash_function=hash_function, style=style, parent=parent) dialog.exec_() return dialog.getNewPassword() @staticmethod - def changePassword(password: Optional[str] = None, hash_function: PasswordHashFunction = defaultHashFunction, + def changePassword(password: Optional[str] = None, + hash_function: PasswordHashFunction = lambda x: hashlib.md5(x).hexdigest(), style: str = '', parent: Optional[QWidget] = None) -> str: dialog = PasswordDialog(password, hash_function, style, parent) dialog.exec_() @@ -740,7 +763,8 @@ def changePassword(password: Optional[str] = None, hash_function: PasswordHashFu class OptionDialog(QDialog): - DEF_TITLE = QApplication.translate("OptionDialog", "Please select", None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + DEF_TITLE = QApplication.translate("OptionDialog", "Please select", None) def __init__(self, options: Sequence[str], title: str = DEF_TITLE, parent: Optional[QWidget] = None): super(OptionDialog, self).__init__(parent) @@ -754,6 +778,7 @@ def __init__(self, options: Sequence[str], title: str = DEF_TITLE, parent: Optio layout.addWidget(btn) btn.clicked.connect(self.slotSelected) + # noinspection PyTypeChecker cancel = QPushButton(self.tr("Cancel")) cancel.clicked.connect(self.reject) layout.addWidget(cancel) @@ -792,10 +817,11 @@ def getOptionIndex(cls, options: Sequence[str], title: str = DEF_TITLE, parent: return dialog.getSelectionIndex() +# noinspection PyTypeChecker def showFileExportDialog(parent: QWidget, fmt: str, name: str = "", title: str = QApplication.translate("dialog", "Please select export file save path", - None, QApplication.UnicodeUTF8)) -> str: + None)) -> str: path, ret = QFileDialog.getSaveFileName(parent, parent.tr(title), name, parent.tr(fmt)) if not ret or len(path) == 0: return "" @@ -803,10 +829,11 @@ def showFileExportDialog(parent: QWidget, fmt: str, name: str = "", return path +# noinspection PyTypeChecker def showFileImportDialog(parent: QWidget, fmt: str, path: str = "", title: str = QApplication.translate("dialog", "Please select import file", - None, QApplication.UnicodeUTF8)) -> str: + None)) -> str: # If not specified path load recently used path path = __showFileImportDialogRecentPathDict.get(title, "") if not path else path diff --git a/gui/icon.py b/gui/icon.py index 4b340df..90f0a55 100644 --- a/gui/icon.py +++ b/gui/icon.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- from typing import Sequence, Dict -from PySide.QtGui import QLabel, QPixmap -from PySide.QtCore import QSize, QTimerEvent +from PySide2.QtGui import QPixmap +from PySide2.QtWidgets import QLabel +from PySide2.QtCore import QSize, QTimerEvent from ..core.threading import ThreadLockAndDataWrap __all__ = ['StatusIcon', 'MultiStatusIcon', 'DynamicStatusIcon', 'MultiStatusNamedIcon'] diff --git a/core/uimailbox.py b/gui/mailbox.py similarity index 93% rename from core/uimailbox.py rename to gui/mailbox.py index 42e884d..c384913 100644 --- a/core/uimailbox.py +++ b/gui/mailbox.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- from typing import Callable, Optional, Union -from PySide.QtCore import Qt, Signal, Slot, QObject, QTimer -from PySide.QtGui import QColor, QWidget, QStatusBar, QLabel +from PySide2.QtGui import QColor +from PySide2.QtWidgets import QWidget, QStatusBar, QLabel +from PySide2.QtCore import Qt, Signal, Slot, QObject, QTimer -from .timer import Task, Tasklet -from .threading import ThreadConditionWrap +from ..core.timer import Task, Tasklet +from ..core.threading import ThreadConditionWrap -from ..gui.dialog import ProgressDialog -from ..gui.msgbox import MB_TYPES, showMessageBox, showQuestionBox +from .dialog import ProgressDialog +from .msgbox import MB_TYPES, showMessageBox, showQuestionBox __all__ = ['UiMailBox', 'StatusBarMail', 'MessageBoxMail', 'QuestionBoxMail', 'WindowsTitleMail', 'CallbackFuncMail', 'ProgressBarMail'] @@ -79,7 +80,7 @@ def title(self) -> str or None: class WindowsTitleMail(BaseUiMail): def __init__(self, content: str): - """Show a message on windows title with #content + """Show a message on window title with #content :param content: message content :return: @@ -133,7 +134,7 @@ def __init__(self, content: str, title: str, condition: ThreadConditionWrap): :param content: QMessageBox.Question content :param title: QMessageBox.Question title - :param condition: sync user click result ThreadConditionWrap.wait + :param condition: sync user click result ThreadConditionWrap::wait """ super(QuestionBoxMail, self).__init__(content) if not isinstance(title, str): @@ -189,7 +190,7 @@ class UiMailBox(QObject): hasNewMail = Signal(object) def __init__(self, parent: QWidget): - """UI mail box using send and receive ui display message in thread + """UiMail box using send and receive ui display message in thread :return: """ @@ -239,6 +240,7 @@ def mailProcess(self, mail: BaseUiMail) -> bool: color = "rgb({0:d},{1:d},{2:d})".format(mail.color.red(), mail.color.green(), mail.color.blue()) # Main windows has status bar if isinstance(self.__parent.ui.statusbar, QStatusBar): + # noinspection PyTypeChecker self.__parent.ui.statusbar.showMessage(self.tr(mail.content), mail.timeout) self.__parent.ui.statusbar.setStyleSheet( "QStatusBar{" @@ -248,6 +250,7 @@ def mailProcess(self, mail: BaseUiMail) -> bool: "font-weight:bold;}" % color) # Widget has label named as statusbar elif isinstance(self.__parent.ui.statusbar, QLabel): + # noinspection PyTypeChecker self.__parent.ui.statusbar.setText(self.tr(mail.content)) self.__parent.ui.statusbar.setStyleSheet( "color:{0:s};padding-top:8px;font-weight:bold;".format(color) @@ -282,8 +285,9 @@ def mailProcess(self, mail: BaseUiMail) -> bool: self.__progress.slotHidden() self.__progress.setCloseable(True) - # Appended a message on windows title + # Appended a message on window title elif isinstance(mail, WindowsTitleMail): + # noinspection PyTypeChecker self.__parent.setWindowTitle(self.__parent.windowTitle() + self.tr(" {0:s}".format(mail.content))) # Callback function diff --git a/gui/misc.py b/gui/misc.py index ab642c3..0ab0728 100644 --- a/gui/misc.py +++ b/gui/misc.py @@ -2,8 +2,11 @@ import glob import platform import websocket -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtCore import QSize, Signal, QEvent, QObject, SLOT, Qt +from PySide2.QtGui import QIcon, QMouseEvent, QColor, QPixmap, QFont, QFontMetrics, QKeySequence, QImage, QPaintEvent, \ + QMoveEvent, QPen, QContextMenuEvent, qRgba, qAlpha, QPainter +from PySide2.QtWidgets import QComboBox, QApplication, QWidget, QTabBar, QStyleOptionTab, QStylePainter, QStyle, \ + QMenu, QAction, QActionGroup, QSizePolicy, QToolBar, QTextEdit, QShortcut, QToolButton import serial.tools.list_ports from raspi_io.utility import scan_server from raspi_io import Query, RaspiSocketError @@ -25,7 +28,8 @@ class SerialPortSelector(QComboBox): """ # When port selected this signal will emit portSelected = Signal(object) - TIPS = QApplication.translate("SerialPortSelector", "Please select serial port", None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + TIPS = QApplication.translate("SerialPortSelector", "Please select serial port", None) def __init__(self, text: Optional[str] = TIPS, one_shot: bool = False, parent: Optional[QWidget] = None): """Select serial port @@ -40,6 +44,7 @@ def __init__(self, text: Optional[str] = TIPS, one_shot: bool = False, parent: O self.__text = text self.__one_shot = one_shot self.__system = platform.system().lower() + # noinspection PyTypeChecker self.setToolTip(self.tr("Right click reset and refresh serial port")) # Flush current serial port list @@ -72,6 +77,7 @@ def flushSerialPort(self, timeout: float = 0.04): self.setEnabled(True) if self.__text: + # noinspection PyTypeChecker self.addItem(self.tr(self.__text)) # Scan local system serial port @@ -81,7 +87,7 @@ def flushSerialPort(self, timeout: float = 0.04): self.setItemData(self.count() - 1, port) else: for index, port in enumerate(list(serial.tools.list_ports.comports())): - # Windows serial port is a object linux is a tuple + # Windows serial port is an object linux is a tuple device = port.device desc = "{0:s}".format(device).split(" - ")[-1] self.addItem("{0:s}".format(desc)) @@ -115,8 +121,8 @@ class NetworkInterfaceSelector(QComboBox): addressChanged = Signal(object) """List current system exist network interface""" - TIPS = QApplication.translate("NetworkInterfaceSelector", "Please select network interface", - None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + TIPS = QApplication.translate("NetworkInterfaceSelector", "Please select network interface", None) def __init__(self, text: Optional[str] = TIPS, one_short: bool = False, ignore_loopback: bool = True, network_mode: bool = False, parent: Optional[QWidget] = None): @@ -125,6 +131,7 @@ def __init__(self, text: Optional[str] = TIPS, one_short: bool = False, self._text = text self._one_short = one_short self._ignore_loopback = ignore_loopback + # noinspection PyTypeChecker self.setToolTip(self.tr("Right click reset and refresh network interface")) self.flushNic() @@ -142,12 +149,15 @@ def flushNic(self): self.addItem("{}: {}".format(nic_name, nic_attr.ip), nic_attr.network) def isNetworkMode(self) -> bool: + # noinspection PyTypeChecker return self.property("format") == "network" def setNetworkMode(self): + # noinspection PyTypeChecker self.setProperty("format", "network") def setAddressMode(self): + # noinspection PyTypeChecker self.setProperty("format", "address") def slotNicSelected(self, idx: int) -> bool: @@ -204,7 +214,7 @@ def mousePressEvent(self, ev: QMouseEvent): class TabBar(QTabBar): def __init__(self, *args, **kwargs): - self.tabSize = QSize(kwargs.pop('width'), kwargs.pop('height')) + self.tabSize = QSize(int(kwargs.pop('width')), int(kwargs.pop('height'))) super(TabBar, self).__init__(*args, **kwargs) def updateTabSize(self, size: QSize): @@ -557,13 +567,14 @@ def paintEvent(self, ev: QPaintEvent): painter.setFont(self.font()) painter.setPen(QPen(self._color)) + # noinspection PyTypeChecker painter.drawText(self.rect(), self._align, self._text) def sizeHint(self) -> QSize: metrics = QFontMetrics(self.font()) min_height = metrics.height() min_width = metrics.width(self._text) * 1.3 - return QSize(min_width, min_height) + return QSize(int(min_width), int(min_height)) class HyperlinkLabel(ThreadSafeLabel): @@ -645,9 +656,9 @@ def contextMenuEvent(self, event: QContextMenuEvent): menu = self.createStandardContextMenu(event.pos()) # Standard clear and save action menu.addSeparator() - menu.addAction('Clear All', self, SLOT('clear()'), self.__clear_ks) + menu.addAction('Clear All', self, SLOT(b'clear()'), self.__clear_ks) if self.__save_as_title: - menu.addAction('Save As File', self, SLOT('slotSaveAs()'), self.__save_ks) + menu.addAction('Save As File', self, SLOT(b'slotSaveAs()'), self.__save_ks) # Customize actions menu.addSeparator() @@ -658,7 +669,6 @@ def contextMenuEvent(self, event: QContextMenuEvent): menu.exec_(event.globalPos()) - @Slot() def slotSaveAs(self): if not self.__save_as_title: return @@ -672,4 +682,4 @@ def slotSaveAs(self): with open(path, 'w', encoding='utf-8') as fp: fp.write(self.toPlainText()) - return showMessageBox(self, MB_TYPE_INFO, self.tr('Save success') + f'\n{path}', title=self.tr('Save File')) + return showMessageBox(self, MB_TYPE_INFO, self.tr(b'Save success') + f'\n{path}', title=self.tr(b'Save File')) diff --git a/gui/msgbox.py b/gui/msgbox.py index fddd631..1d3be02 100644 --- a/gui/msgbox.py +++ b/gui/msgbox.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from PySide.QtGui import QMessageBox, QApplication, QWidget +from PySide2.QtWidgets import QMessageBox, QApplication, QWidget __all__ = ['showQuestionBox', 'showMessageBox', 'MB_TYPES', 'MB_TYPE_ERR', 'MB_TYPE_INFO', 'MB_TYPE_WARN', 'MB_TYPE_QUESTION'] @@ -33,18 +33,12 @@ def showMessageBox(parent: QWidget, msg_type: str, content: str, title: str = '' :param title: Message title :return: result """ + # noinspection PyTypeChecker attributes = { - MB_TYPE_ERR: (QMessageBox.Critical, QApplication.translate("msgbox", "Error", - None, QApplication.UnicodeUTF8)), - - MB_TYPE_WARN: (QMessageBox.Warning, QApplication.translate("msgbox", "Warning", - None, QApplication.UnicodeUTF8)), - - MB_TYPE_INFO: (QMessageBox.Information, QApplication.translate("msgbox", "Info", - None, QApplication.UnicodeUTF8)), - - MB_TYPE_QUESTION: (QMessageBox.Question, QApplication.translate("msgbox", "Confirm", - None, QApplication.UnicodeUTF8)) + MB_TYPE_ERR: (QMessageBox.Critical, QApplication.translate("msgbox", "Error", None)), + MB_TYPE_WARN: (QMessageBox.Warning, QApplication.translate("msgbox", "Warning", None)), + MB_TYPE_INFO: (QMessageBox.Information, QApplication.translate("msgbox", "Info", None)), + MB_TYPE_QUESTION: (QMessageBox.Question, QApplication.translate("msgbox", "Confirm", None)) } try: @@ -57,5 +51,6 @@ def showMessageBox(parent: QWidget, msg_type: str, content: str, title: str = '' else: msg.exec_() return True if msg_type == MB_TYPE_INFO else False - except TypeError: + except TypeError as e: + print(f'showMessageBox:{e}') return False diff --git a/gui/srm.py b/gui/srm.py index 764affc..ab637da 100644 --- a/gui/srm.py +++ b/gui/srm.py @@ -2,8 +2,10 @@ import os import time import threading -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtGui import * +from PySide2.QtCore import * +from PySide2.QtWidgets import QWidget, QApplication, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QSplitter, \ + QDialog, QDialogButtonBox from typing import Optional, Callable, Dict from .msgbox import * @@ -47,7 +49,8 @@ def __getRawRSAPrivateKey(self, key: bytes) -> str: return self.__decrypt(key) if hasattr(self.__decrypt, '__call__') else key.decode() def tr(self, text: str) -> str: - return QApplication.translate("SoftwareRegistrationMachineWidget", text, None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + return QApplication.translate("SoftwareRegistrationMachineWidget", text, None) def _initUi(self): style = dict(background=(240, 240, 240), withBox=False) @@ -229,6 +232,7 @@ def __init__(self, rsa_public_key: str, register_file: str, self.__initData() self.__initSignalAndSlot() + # noinspection PyTypeChecker def __initUi(self): self.ui_save_mc = QPushButton(self.tr("Save Machine Code")) self.ui_load_rc = QPushButton(self.tr("Load Registration Code")) @@ -260,7 +264,9 @@ def __initData(self): self.ui_save_mc.setHidden(True) self.ui_load_rc.setHidden(True) self.ui_backup_rc.setHidden(True) + # noinspection PyTypeChecker self.ui_mc_image.drawFromText(self.tr("Generating please wait...")) + # noinspection PyTypeChecker self.ui_rc_image.drawFromText(self.tr("Please Load Registration Code")) # Display machine code @@ -288,6 +294,7 @@ def isRegistered(self) -> bool: return self.__registered.data def slotSaveMachineCode(self): + # noinspection PyTypeChecker path = showFileExportDialog(self, fmt=self.QR_CODE_FS_FMT, name="machine_code.png", title=self.tr("Please select machine code save path")) if not path: @@ -297,25 +304,31 @@ def slotSaveMachineCode(self): with open(path, 'wb') as fp: fp.write(self.__mc_qr_image) + # noinspection PyTypeChecker self.signalMsgBox.emit(MB_TYPE_INFO, self.tr("Machine code save success") + "\n{!r}".format(path)) except OSError as e: + # noinspection PyTypeChecker showMessageBox(self, MB_TYPE_ERR, self.tr("Save machine code error") + ": {}".format(e)) def slotLoadRegistrationCode(self): if self.__registered: + # noinspection PyTypeChecker return showMessageBox(self, MB_TYPE_INFO, self.tr("Software registered")) + # noinspection PyTypeChecker path = showFileImportDialog(self, fmt=self.QR_CODE_FS_FMT, title=self.tr("Please select registration code")) if not os.path.isfile(path): return + # noinspection PyTypeChecker self.ui_rc_image.drawFromText(self.tr("Verifying, please wait...")) th = threading.Thread(target=self.threadVerifyRegistrationCode, args=(path,)) th.setDaemon(True) th.start() def slotBackupRegistrationCode(self): + # noinspection PyTypeChecker path = showFileExportDialog(self, fmt=self.QR_CODE_FS_FMT, name="registration_code.png", title=self.tr("Please select registration code backup path")) if not path: @@ -325,9 +338,11 @@ def slotBackupRegistrationCode(self): with open(path, "wb") as fp: fp.write(self.__rc_qr_image) + # noinspection PyTypeChecker self.signalMsgBox.emit(MB_TYPE_INFO, self.tr("Software registration code backup success") + "\n{!r}".format(path)) except OSError as e: + # noinspection PyTypeChecker self.signalMsgBox.emit(MB_TYPE_ERR, self.tr("Software registration code backup failed") + ": {}".format(e)) def slotShowMachineCode(self, image: bytes): @@ -342,19 +357,23 @@ def slotShowRegistrationCode(self, verify: bool): self.__registered.data = verify if not verify: + # noinspection PyTypeChecker return showMessageBox(self, MB_TYPE_ERR, self.tr("Invalid software registration code")) self.__rc_qr_image = qrcode_generate(self.__machine.get_registration_code(), fmt=self.QR_CODE_FORMAT) self.ui_rc_image.drawFromMem(self.__rc_qr_image, self.QR_CODE_FORMAT) self.ui_backup_rc.setVisible(True) + # noinspection PyTypeChecker self.ui_load_rc.setText(self.tr("Software registered")) + # noinspection PyTypeChecker showMessageBox(self, MB_TYPE_INFO, self.tr("Software registered")) def threadGenerateMachineCode(self): try: self.signalMachineCodeGenerated.emit(qrcode_generate(self.__machine.get_machine_code())) except Exception as e: + # noinspection PyTypeChecker self.signalMsgBox.emit(MB_TYPE_ERR, self.tr("Generate machine code error") + ": {}".format(e)) def threadVerifyRegistrationCode(self, path: str): @@ -368,6 +387,7 @@ def threadCheckAndLoadRegistrationState(self): self.signalVerifyRegistrationCode.emit(True) else: time.sleep(3) + # noinspection PyTypeChecker self.signalMsgBox.emit(MB_TYPE_WARN, self.tr("Please click 'Load Registration Code' register software")) @staticmethod diff --git a/gui/view.py b/gui/view.py index 5c0a111..9730f59 100644 --- a/gui/view.py +++ b/gui/view.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtGui import * +from PySide2.QtCore import * +from PySide2.QtWidgets import QTableView, QMenu, QWidget, QAction, QTableWidgetItem, QHeaderView, QAbstractItemView, \ + QComboBox, QCheckBox, QSpinBox, QDoubleSpinBox, QLineEdit, QPushButton, QRadioButton, QItemDelegate, QDial, \ + QStyleOptionViewItem, QTextEdit, QPlainTextEdit, QDateTimeEdit from typing import List, Any, Dict, Optional, Union, Sequence from ..misc.settings import * @@ -27,6 +30,7 @@ def __init__(self, parent: Optional[QWidget] = None): self.__columnStretchFactor = list() self.__scale_x, self.__scale_y = get_program_scale_factor() + # noinspection PyTypeChecker for group, actions in { self.COMM_ACTION: [ (QAction(self.tr("Clear All"), self), lambda: self.model().setRowCount(0)), @@ -42,6 +46,7 @@ def __init__(self, parent: Optional[QWidget] = None): }.items(): for action, slot in actions: action.triggered.connect(slot) + # noinspection PyTypeChecker action.setProperty("group", group) self.__contentMenu.addAction(action) @@ -96,6 +101,7 @@ def setCustomContentMenu(self, menu: List[QAction]): if not isinstance(action, QAction): continue + # noinspection PyTypeChecker action.setProperty("group", self.CUSTOM_ACTION) self.__contentMenu.addAction(action) @@ -129,7 +135,7 @@ def getVerticalHeaderHeight(self): def setVerticalHeaderHeight(self, height: int): vertical_header = self.verticalHeader() - vertical_header.setResizeMode(QHeaderView.Fixed) + vertical_header.setSectionResizeMode(QHeaderView.Fixed) vertical_header.setDefaultSectionSize(height) self.setVerticalHeader(vertical_header) @@ -139,7 +145,7 @@ def getHorizontalHeaderWidth(self): def setHorizontalHeaderWidth(self, width: int): horizontal_header = self.horizontalHeader() - horizontal_header.setResizeMode(QHeaderView.Fixed) + horizontal_header.setSectionResizeMode(QHeaderView.Fixed) horizontal_header.setDefaultSectionSize(width) self.setHorizontalHeader(horizontal_header) @@ -256,7 +262,7 @@ def resizeEvent(self, ev: QResizeEvent): header = self.horizontalHeader() header.setStretchLastSection(True) for column, factor in enumerate(self.__columnStretchFactor): - header.setResizeMode(column, QHeaderView.Fixed) + header.setSectionResizeMode(column, QHeaderView.Fixed) self.setColumnWidth(column, width * factor) def getCurrentRow(self) -> int: @@ -278,6 +284,7 @@ def setCurrentRow(self, row: int) -> bool: if not isinstance(model, QAbstractItemModel): return False + # noinspection PyTypeChecker return self.setCurrentIndex(model.index(row, 0, QModelIndex())) def setRowCount(self, count: int): @@ -298,6 +305,7 @@ def setTableData(self, data: List[Any], role: Qt.ItemDataRole = Qt.EditRole): if not isinstance(data, list) or len(data) != model.rowCount(): return False + # noinspection PyTypeChecker return sum([self.setRowData(row, data[row], role) for row in range(model.rowCount())]) == len(data) def getRowData(self, row: int, role: Qt.ItemDataRole = Qt.DisplayRole): @@ -352,6 +360,7 @@ def setItemData(self, row: int, column: int, data: Any, role: Qt.ItemDataRole = if not isinstance(model, QAbstractItemModel): return False + # noinspection PyTypeChecker return model.setData(model.index(row, column, QModelIndex()), data, role) def frozenItem(self, row: int, column: int, frozen: bool) -> bool: @@ -373,6 +382,7 @@ def frozenItem(self, row: int, column: int, frozen: bool) -> bool: widget.setCheckable(not frozen) if isinstance(widget, QCheckBox) else widget.setDisabled(frozen) if isinstance(self.itemDelegate(), QItemDelegate): + # noinspection PyTypeChecker self.itemDelegate().setProperty(str(DynamicObject(row=row, column=column)), frozen) return True @@ -526,6 +536,7 @@ def updateColumnDelegate(self, column: int, filter_: UiInputSetting): def isFrozen(self, index: QStyleOptionViewItem) -> bool: row = index.row() column = index.column() + # noinspection PyTypeChecker return self.property(str(DynamicObject(row=row, column=column))) def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): @@ -542,7 +553,9 @@ def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QMo return checkbox elif isinstance(settings, UiPushButtonInput): button = QPushButton(settings.get_name(), parent=parent) + # noinspection PyTypeChecker button.setProperty('private', index.data()) + # noinspection PyTypeChecker button.setProperty('index', index) button.clicked.connect(settings.get_default()) return button diff --git a/gui/widget.py b/gui/widget.py index 6574928..dccbc28 100644 --- a/gui/widget.py +++ b/gui/widget.py @@ -31,8 +31,14 @@ import collections from serial import Serial -from PySide.QtGui import * -from PySide.QtCore import * +from PySide2.QtGui import QColor, QPixmap, QPainter, QFont, QPen, QBrush, QImage, QImageReader, QTextCursor,\ + QMouseEvent, QHideEvent, QPaintEvent, QContextMenuEvent, QResizeEvent, QRegExpValidator +from PySide2.QtCore import Qt, Signal, Slot, QPoint, QSize, QDate, QDateTime, QRegExp, QTime +from PySide2.QtWidgets import QWidget, QApplication, QLayout, QHBoxLayout, QVBoxLayout, QGridLayout, QButtonGroup, \ + QSpinBox, QDoubleSpinBox, QTableWidget, QHeaderView, QSplitter, QLabel, QMenu, QAction, QRadioButton, \ + QCheckBox, QPushButton, QLineEdit, QProgressBar, QDateTimeEdit, QAbstractItemView, QTableWidgetItem, \ + QComboBox, QTreeWidget, QListWidget, QSizePolicy, QTreeWidgetItem, QFileDialog, QColorDialog, QFontDialog, \ + QListWidgetItem, QGroupBox, QTabWidget, QTextEdit from datetime import datetime from typing import Optional, Union, List, Any, Sequence, Tuple, Iterable, Dict @@ -87,6 +93,7 @@ def createInputWithLabel(label: str, key: str, input_cls: QWidget.__class__) -> input_ = input_cls() label = QLabel(label) input_.setProperty("name", key) + # noinspection PyTypeChecker label.setProperty("name", "{}_label".format(key)) return label, input_ @@ -98,6 +105,7 @@ def createMultiInputWithLabel(texts: Iterable[Tuple[str, str]], input_cls: QWidg text = input_cls() label = QLabel(label) text.setProperty("name", key) + # noinspection PyTypeChecker label.setProperty("name", "{}_label".format(key)) layout.addWidget(label, row, 0) layout.addWidget(text, row, 1) @@ -115,9 +123,11 @@ def createButtonGroup(key: str, names: Iterable[str], title: str) -> Tuple[QLabe label = QLabel(title) group = QButtonGroup() layout = QHBoxLayout() + # noinspection PyTypeChecker group.setProperty("name", key) for bid, name in enumerate(names): button = QRadioButton(name) + # noinspection PyTypeChecker button.setProperty("name", name) group.addButton(button) group.setId(button, bid) @@ -179,7 +189,7 @@ def getDynamicTextPos(self, fontSize: int, textSize: int) -> QPoint: :return:QPoint """ if not isinstance(fontSize, int) or not isinstance(textSize, int): - return QPoint(self.width() / 2, self.height() / 2) + return QPoint(self.width() // 2, self.height() // 2) # Get mouse position x, y = self.getCursorPos() @@ -329,7 +339,7 @@ def adjustColorBrightness(color: Union[QColor, Qt.GlobalColor], brightness: int) :param color: QColor :param brightness: brightness value (0 - 255) - :return:success return after just color, else Qt.back + :return:success return after just color, else black """ if not PaintWidget.isColor(color) or not PaintWidget.isNumber(brightness): @@ -473,7 +483,7 @@ def __init__(self, font: QFont = QFont("Times New Roman", 10), parent: Optional[ :param font: Color r, g, b value display font :param parent: - :return:None double click mouse right button will exit + :return: None, double click mouse right button will exit """ super(ColorWidget, self).__init__(parent) # Enter full screen mode @@ -500,7 +510,7 @@ def getColor(self) -> Tuple[Qt.GlobalColor, Qt.GlobalColor]: def addColor(self, color: Sequence[Union[QColor, Qt.GlobalColor]]) -> bool: """Add color to color group - :param color:(QColor, QColor) + :param color: (QColor, QColor) :return: """ if not isinstance(color, (tuple, list)) or len(color) != 2: @@ -565,7 +575,8 @@ def __init__(self, font: QFont = QFont("Times New Roman", 10), parent: Optional[ """Cursor grab widget, double click mouse left button change color, mouse moved change cursor position CursorWidget provide two signal 'cursorChanged' and 'cursorStopChange', when mouse moved, the cursor position - will changed, the 'cursorChanged' signal will send. 'cursorStopChange' signal will send when the mouse is stop . + will be changed, the 'cursorChanged' signal will send. + 'cursorStopChange' signal will send when the mouse is stop. Signal: cursorChanged(int x, int y, int backgroundColor) Signal: cursorStopChange(int x, int y, int backgroundColor) @@ -636,7 +647,7 @@ class RgbWidget(PaintWidget): rgbChanged = Signal(bool, bool, bool) def __init__(self, parent: Optional[QWidget] = None): - """ RGB color control widget, double click the color zone will turn of or turn off this color. + """ RGB color control widget, double-click the color zone will turn of or turn off this color. When color states changed will send 'rgbChanged' signal @@ -709,7 +720,7 @@ def __init__(self, font: QFont = QFont("Times New Roman", 10), parent: Optional[ Press mouse right button, then move mouse will change the high luminance LumWidget provide 2 signal 'lumChanged' and 'lumStopChange', when mouse moved, the windows Luminance - will changed, the 'lumChanged' signal will send. 'lumStopChange' signal will send when the mouse is stop . + will be changed, the 'lumChanged' signal will send. 'lumStopChange' signal will send when the mouse is stop . Signal: lumChanged(int hi, int low, int mode) Signal: lumStopChange(int hi, int low, int mode) @@ -785,21 +796,21 @@ def paintEvent(self, ev: QPaintEvent): self.lumChanged.emit(self.lum[1], self.lum[0], self.lumMode) if self.lumMode == self.CE1_MODE: - self.drawCenterSquare(painter, self.getHighLum(), self.height() / 2) + self.drawCenterSquare(painter, self.getHighLum(), self.height() // 2) elif self.lumMode == self.CE2_MODE: - self.drawCenterRect(painter, self.getHighLum(), self.width() / 2, self.height() / 2) + self.drawCenterRect(painter, self.getHighLum(), self.width() // 2, self.height() // 2) elif self.lumMode == self.LF_MODE: - self.drawRectangle(painter, self.getHighLum(), QPoint(0, 0), self.width() / 2, self.height()) + self.drawRectangle(painter, self.getHighLum(), QPoint(0, 0), self.width() // 2, self.height()) elif self.lumMode == self.UD_MODE: - self.drawRectangle(painter, self.getHighLum(), QPoint(0, 0), self.width(), self.height() / 2) + self.drawRectangle(painter, self.getHighLum(), QPoint(0, 0), self.width(), self.height() // 2) elif self.lumMode == self.CT_MODE: - side = self.height() / 7 + side = self.height() // 7 self.drawBackground(painter, QColor(127, 127, 127)) self.drawCenterSquare(painter, self.getHighLum(), side) - self.drawSquare(painter, self.getLowLum(), QPoint(self.width() / 2 - side / 2, side), side) - self.drawSquare(painter, self.getLowLum(), QPoint(self.width() / 2 - side / 2, side * 5), side) - self.drawSquare(painter, self.getLowLum(), QPoint(self.width() / 2 - side * 2.5, side * 3), side) - self.drawSquare(painter, self.getLowLum(), QPoint(self.width() / 2 + side * 1.5, side * 3), side) + self.drawSquare(painter, self.getLowLum(), QPoint(self.width() // 2 - side // 2, side), side) + self.drawSquare(painter, self.getLowLum(), QPoint(self.width() // 2 - side // 2, side * 5), side) + self.drawSquare(painter, self.getLowLum(), QPoint(int(self.width() / 2 - side * 2.5), side * 3), side) + self.drawSquare(painter, self.getLowLum(), QPoint(int(self.width() / 2 + side * 1.5), side * 3), side) self.drawDynamicText(painter, self.font, textColor, text) @@ -807,11 +818,11 @@ def paintEvent(self, ev: QPaintEvent): class ImageWidget(PaintWidget): def __init__(self, width: int = 0, height: int = 0, zoomInRatio: int = 0, zoomInArea: int = 20, parent: Optional[QWidget] = None): - """ImageWidget provide 3 method to draw a image + """ImageWidget provide 3 method to draw an image - drawFromFs : load a image from filesystem and show it - drawFromMem : load a image form memory data and show it - drawFromText: Dynamic draw a image with text + drawFromFs : load an image from filesystem and show it + drawFromMem : load an image form memory data and show it + drawFromText: Dynamic draw an image with text :param width: widget fixed width :param height:widget fixed height @@ -827,7 +838,7 @@ def __init__(self, width: int = 0, height: int = 0, self.text = "" self.textColor = Qt.black self.bgColor = Qt.lightGray - self.textFont = QFont("Times New Roman", width / 16) + self.textFont = QFont("Times New Roman", width // 16) # Draw image using self.image = QImage() @@ -844,7 +855,7 @@ def __init__(self, width: int = 0, height: int = 0, @Slot(str) def drawFromFs(self, filePath: str) -> bool: - """Load a image from filesystem, then display it + """Load an image from filesystem, then display it :param filePath: Image file path :return: @@ -864,7 +875,7 @@ def drawFromFs(self, filePath: str) -> bool: return True @Slot(object, object) - def drawFromMem(self, data: bytes, imageFormat: str = "bmp") -> bool: + def drawFromMem(self, data: bytes, imageFormat: str = str(b"bmp")) -> bool: """Load image form memory :param data: Image data @@ -875,12 +886,14 @@ def drawFromMem(self, data: bytes, imageFormat: str = "bmp") -> bool: print("Invalid image data:{}".format(type(data))) return False + imageFormat = str(imageFormat.encode()) if not isinstance(imageFormat, str) or imageFormat not in self.supportFormats: print("Invalid image format:{}".format(imageFormat)) return False # Clear loadImageFromFs data # QImage fromData(const uchar * data, int size, const char * format = 0) + # noinspection PyTypeChecker self.image = QImage.fromData(data, imageFormat) self.update() return True @@ -919,6 +932,7 @@ def drawFromText(self, text: str, textColor: Union[QColor, Qt.GlobalColor] = Qt. if self.textFont.pointSize() > fontMaxWidth: self.textFont.setPointSize(fontMaxWidth) + # noinspection PyTypeChecker self.text = self.tr(text) self.image = QImage() self.update() @@ -1024,6 +1038,7 @@ def __init__(self, max_column: int, hide_header: bool = False, }.items(): for action, slot in actions: action.triggered.connect(slot) + # noinspection PyTypeChecker action.setProperty("group", group) self.__contentMenu.addAction(action) @@ -1035,7 +1050,8 @@ def __init__(self, max_column: int, hide_header: bool = False, self.setVerticalHeaderHeight(int(self.getVerticalHeaderHeight() * self.__scale_y)) def tr(self, text: str) -> str: - return QApplication.translate("TableWidget", text, None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + return QApplication.translate("TableWidget", text, None) def __checkRow(self, row: int) -> bool: if not isinstance(row, int): @@ -1107,8 +1123,10 @@ def __copyWidget(widget: QWidget) -> QWidget: # Copy widget property for key in widget.dynamicPropertyNames(): key = str(key) + # noinspection PyTypeChecker temp.setProperty(key, widget.property(key)) if key == "clicked" and isinstance(widget, QPushButton): + # noinspection PyTypeChecker temp.clicked.connect(widget.property(key)) return temp @@ -1154,6 +1172,7 @@ def setCustomContentMenu(self, menu: List[QAction]): if not isinstance(action, QAction): continue + # noinspection PyTypeChecker action.setProperty("group", self.ACTION.CUSTOM) self.__contentMenu.addAction(action) @@ -1162,7 +1181,7 @@ def setCustomContentMenu(self, menu: List[QAction]): def resizeColumnWidthFitContents(self): header = self.horizontalHeader() for column in range(self.columnCount()): - header.setResizeMode(column, QHeaderView.ResizeToContents) + header.setSectionResizeMode(column, QHeaderView.ResizeToContents) def setColumnMaxWidth(self, column: int, max_width: int): if not self.__checkColumn(column): @@ -1225,7 +1244,7 @@ def getVerticalHeaderHeight(self) -> int: def setVerticalHeaderHeight(self, height: int): vertical_header = self.verticalHeader() - vertical_header.setResizeMode(QHeaderView.Fixed) + vertical_header.setSectionResizeMode(QHeaderView.Fixed) vertical_header.setDefaultSectionSize(height) self.setVerticalHeader(vertical_header) @@ -1235,7 +1254,7 @@ def getHorizontalHeaderWidth(self) -> int: def setHorizontalHeaderWidth(self, width: int): horizontal_header = self.horizontalHeader() - horizontal_header.setResizeMode(QHeaderView.Fixed) + horizontal_header.setSectionResizeMode(QHeaderView.Fixed) horizontal_header.setDefaultSectionSize(width) self.setHorizontalHeader(horizontal_header) @@ -1447,7 +1466,7 @@ def swapColumn(self, src: int, dst: int): def addRow(self, data: Sequence[Any], property_: Optional[Sequence[Any]] = None): """Add a row and set row property data - :param data: row data should be a iterable object + :param data: row data should be an iterable object :param property_: row hidden property data :return: """ @@ -1617,6 +1636,7 @@ def setItemData(self, row: int, column: int, data: Any, property_: Optional[Any] self.removeCellWidget(row, column) self.setCellWidget(row, column, widget) elif isinstance(widget, QPushButton) and isinstance(data, object): + # noinspection PyTypeChecker widget.setProperty("private", data) self.removeCellWidget(row, column) self.setCellWidget(row, column, widget) @@ -1690,6 +1710,7 @@ def setItemDataFilter(self, row: int, column: int, filters: TableDataFilter) -> widget = QDateTimeEdit(dt) widget.setCalendarPopup(True) + # noinspection PyTypeChecker widget.setProperty("format", filters[2]) widget.dateTimeChanged.connect(self.__slotWidgetDataChanged) self.takeItem(row, column) @@ -1698,8 +1719,11 @@ def setItemDataFilter(self, row: int, column: int, filters: TableDataFilter) -> elif len(filters) == 3 and isinstance(filters[0], str) and hasattr(filters[1], "__call__"): button = QPushButton(self.tr(filters[0])) button.clicked.connect(filters[1]) + # noinspection PyTypeChecker button.setProperty("clicked", filters[1]) + # noinspection PyTypeChecker button.setProperty("private", filters[2]) + # noinspection PyTypeChecker button.setProperty("dataChanged", self.__slotWidgetDataChanged) self.takeItem(row, column) self.setCellWidget(row, column, button) @@ -1728,6 +1752,7 @@ def setItemDataFilter(self, row: int, column: int, filters: TableDataFilter) -> value = int(value) except ValueError: value = filters.index(value) if value in filters else 0 + # noinspection PyTypeChecker widget.setProperty("format", "text") widget.setCurrentIndex(value) widget.currentIndexChanged.connect(self.__slotWidgetDataChanged) @@ -1807,10 +1832,13 @@ def getItemData(self, row: int, column: int) -> Any: elif isinstance(widget, QCheckBox): return widget.isChecked() elif isinstance(widget, QComboBox): + # noinspection PyTypeChecker return widget.currentText() if widget.property("format") else widget.currentIndex() elif isinstance(widget, QDateTimeEdit): + # noinspection PyTypeChecker return widget.dateTime().toString(widget.property("format")) elif isinstance(widget, QPushButton): + # noinspection PyTypeChecker return widget.property("private") elif isinstance(widget, QProgressBar): return widget.value() @@ -1860,7 +1888,7 @@ def resizeEvent(self, ev: QResizeEvent): header = self.horizontalHeader() header.setStretchLastSection(True) for column, factor in enumerate(self.__columnStretchFactor): - header.setResizeMode(column, self.__columnStretchMode) + header.setSectionResizeMode(column, self.__columnStretchMode) self.setColumnWidth(column, width * factor) # Apply max width after resize @@ -1877,7 +1905,9 @@ def __init__(self, parent: Optional[QWidget] = None): self.__columnStretchFactor = list() self.ui_context_menu = QMenu(self) + # noinspection PyTypeChecker self.ui_expand_all = QAction(self.tr("Expand All"), self) + # noinspection PyTypeChecker self.ui_collapse_all = QAction(self.tr("Collapse All"), self) self.ui_context_menu.addAction(self.ui_expand_all) @@ -1960,7 +1990,7 @@ def resizeEvent(self, ev: QResizeEvent): header = self.header() header.setStretchLastSection(True) for column, factor in enumerate(self.__columnStretchFactor): - header.setResizeMode(column, QHeaderView.Fixed) + header.setSectionResizeMode(column, QHeaderView.Fixed) header.resizeSection(column, width * factor) def contextMenuEvent(self, ev: QContextMenuEvent): @@ -2100,11 +2130,16 @@ def getItemsData(self) -> List[Any]: class SerialPortSettingWidget(QWidget): - PARITIES_STR = QApplication.translate("SerialPortSettingWidget", "Parity", None, QApplication.UnicodeUTF8) - DATABITS_STR = QApplication.translate("SerialPortSettingWidget", "DataBits", None, QApplication.UnicodeUTF8) - STOPBITS_STR = QApplication.translate("SerialPortSettingWidget", "StopBits", None, QApplication.UnicodeUTF8) - BAUDRATE_STR = QApplication.translate("SerialPortSettingWidget", "BaudRate", None, QApplication.UnicodeUTF8) - TIMEOUT_STR = QApplication.translate("SerialPortSettingWidget", "Timeout (ms)", None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + PARITIES_STR = QApplication.translate("SerialPortSettingWidget", "Parity", None) + # noinspection PyTypeChecker + DATABITS_STR = QApplication.translate("SerialPortSettingWidget", "DataBits", None) + # noinspection PyTypeChecker + STOPBITS_STR = QApplication.translate("SerialPortSettingWidget", "StopBits", None) + # noinspection PyTypeChecker + BAUDRATE_STR = QApplication.translate("SerialPortSettingWidget", "BaudRate", None) + # noinspection PyTypeChecker + TIMEOUT_STR = QApplication.translate("SerialPortSettingWidget", "Timeout (ms)", None) # Options OPTIONS = { @@ -2150,12 +2185,14 @@ def __init__(self, settings: Optional[dict] = None, parent: Optional[QWidget] = # If specified port select it port = SerialPortSelector() + # noinspection PyTypeChecker port.setProperty("name", "port") select_port = settings.get("port") if select_port is not None: port.setSelectedPort(select_port) # Add port to dialog + # noinspection PyTypeChecker layout.addWidget(QLabel(self.tr("PortName")), 0, 0) layout.addWidget(port, 0, 1) @@ -2182,7 +2219,9 @@ def __init__(self, settings: Optional[dict] = None, parent: Optional[QWidget] = element.setValue(value) # Set option property + # noinspection PyTypeChecker label = QLabel(self.tr(text)) + # noinspection PyTypeChecker element.setProperty("name", option) # Layout direction setting @@ -2196,12 +2235,14 @@ def getSetting(self) -> Dict[str, Any]: settings = dict() for item in self.__uiManager.findKey("name"): if isinstance(item, QComboBox): + # noinspection PyTypeChecker value = item.property("name") if value == "port" and item.currentIndex() == 0: settings[value] = "" else: settings[value] = item.itemData(item.currentIndex()) elif isinstance(item, QSpinBox): + # noinspection PyTypeChecker settings[item.property("name")] = item.value() return settings @@ -2298,6 +2339,7 @@ def __initUi(self): if not isinstance(widget, VirtualNumberInput): widget.textChanged.connect(self.slotSettingChanged) + # noinspection PyTypeChecker widget.textChanged.connect( lambda x: self.settingChangedDetail.emit(widget.property("data"), x) ) @@ -2317,7 +2359,7 @@ def __initUi(self): layout.addLayout(widget, row, column) column += 1 - # This is necessary otherwise buttonClicked won't be emit + # This is necessary otherwise buttonClicked won't be emitted self.__groups.append(btn_group) # Text mode @@ -2372,7 +2414,8 @@ def __initSignalAndSlots(self): preview.textChanged.connect(self.slotPreviewColor) def tr(self, text: str) -> str: - return QApplication.translate("JsonSettingWidget", text, None, QApplication.UnicodeUTF8) + # noinspection PyTypeChecker + return QApplication.translate("JsonSettingWidget", text, None) def getSettings(self) -> DynamicObject: data = self.getData() @@ -2402,14 +2445,17 @@ def setData(self, data: dict): if isinstance(button, QPushButton): preview = self.ui_manager.getPrevSibling(button) if isinstance(preview, QLineEdit) and data: + # noinspection PyTypeChecker button.setProperty("private", "{}".format(data.get(preview.property("data")))) for button in file_inputs: if isinstance(button, QPushButton): preview = self.ui_manager.getPrevSibling(button) enabled = self.ui_manager.getPrevSibling(preview) + # noinspection PyTypeChecker if isinstance(enabled, QCheckBox) and isinstance(preview, QLineEdit) and \ data and preview.property("data"): + # noinspection PyTypeChecker file_name = preview.property("data") try: enabled, path = data.get(file_name) @@ -2459,7 +2505,9 @@ def slotSelectFont(self): sender = self.sender() if not isinstance(sender, QPushButton): return + # noinspection PyTypeChecker title = self.tr("Please select") + " {}".format(sender.property("title")) + # noinspection PyTypeChecker font_name, point_size, weight = UiFontInput.get_font(sender.property("private")) font, selected = QFontDialog.getFont(QFont(font_name, point_size, weight), self, title) if not selected or not isinstance(font, QFont): @@ -2468,6 +2516,7 @@ def slotSelectFont(self): font_edit = self.ui_manager.getPrevSibling(sender) if isinstance(font_edit, QLineEdit): font_setting = font.rawName(), font.pointSize(), font.weight() + # noinspection PyTypeChecker sender.setProperty("private", "{}".format(font_setting)) font_edit.setText("{}".format(font_setting)) @@ -2507,6 +2556,7 @@ def slotSettingChanged(self): sender = self.sender() # Line edit text content check if isinstance(sender, QLineEdit): + # noinspection PyTypeChecker filters = sender.property("filter") if not filters: return @@ -2536,6 +2586,7 @@ def createInputWidget(setting: UiInputSetting, widget = VirtualNumberInput(parent=parent, initial_value=setting.get_data(), min_=setting.get_check()[UiIntegerInput.CHECK.MIN], max_=setting.get_check()[UiIntegerInput.CHECK.MAX]) + # noinspection PyTypeChecker widget.setProperty("format", "int") else: widget = QSpinBox(parent) @@ -2557,6 +2608,7 @@ def createInputWidget(setting: UiInputSetting, widget.setEchoMode(QLineEdit.Password) # Set regular expression and max length + # noinspection PyTypeChecker widget.setProperty("filter", setting.check[UiTextInput.CHECK.REGEXP]) widget.setValidator(QRegExpValidator(QRegExp(setting.check[UiTextInput.CHECK.REGEXP]))) widget.setMaxLength(setting.check[UiTextInput.CHECK.LENGTH]) @@ -2567,6 +2619,7 @@ def createInputWidget(setting: UiInputSetting, min_=setting.get_check()[UiDoubleInput.CHECK.MIN], max_=setting.get_check()[UiDoubleInput.CHECK.MAX], decimals=setting.get_check()[UiDoubleInput.CHECK.DECIMALS]) + # noinspection PyTypeChecker widget.setProperty("format", "float") else: widget = QDoubleSpinBox(parent) @@ -2581,6 +2634,7 @@ def createInputWidget(setting: UiInputSetting, widget.addItems(setting.get_check()) # Data is text, using text format set and get if isinstance(setting.get_data(), str) and setting.get_data() in setting.get_check(): + # noinspection PyTypeChecker widget.setProperty("format", "text") widget.setCurrentIndex(setting.get_check().index(setting.get_data())) # Data is number, using index format set and get @@ -2594,6 +2648,7 @@ def createInputWidget(setting: UiInputSetting, for id_, text in enumerate(setting.get_check()): btn = QRadioButton(text, parent=parent) + # noinspection PyTypeChecker btn.setProperty("id", id_) group.addButton(btn, id_) layout.addWidget(btn) @@ -2602,10 +2657,12 @@ def createInputWidget(setting: UiInputSetting, text_input = QLineEdit(parent=parent) text_input.setReadOnly(True) text_input.setVisible(False) + # noinspection PyTypeChecker text_input.setProperty("data", name) number_input = QSpinBox(parent=parent) number_input.setVisible(False) + # noinspection PyTypeChecker number_input.setProperty("data", name) # Default select the first item @@ -2629,6 +2686,7 @@ def createInputWidget(setting: UiInputSetting, return layout, group, number_input elif setting.is_serial_type(): widget = SerialPortSelector(parent=parent) + # noinspection PyTypeChecker widget.setProperty("format", "text") widget.setCurrentIndex([widget.itemText(i) for i in range(widget.count())].index(setting.get_data())) elif setting.is_network_type(): @@ -2639,21 +2697,25 @@ def createInputWidget(setting: UiInputSetting, widget.setCurrentAddress(setting.get_data()) elif setting.is_file_type(): widget = QLineEdit(parent) + # noinspection PyTypeChecker widget.setProperty("data", name) widget.setText(setting.get_data()) widget.setReadOnly(not UiFileInput.isEditable(setting.get_check())) - enable = QCheckBox(QApplication.translate("JsonSettingWidget", - "Enable", None, - QApplication.UnicodeUTF8), parent=parent) + # noinspection PyTypeChecker + enable = QCheckBox(QApplication.translate("JsonSettingWidget", "Enable", None), parent=parent) + # noinspection PyTypeChecker enable.setProperty("data", JsonSettingWidget.get_file_input_enable_key(name)) enable.setVisible(UiFileInput.isSelectable(setting.get_check())) - + # noinspection PyTypeChecker button = QPushButton(QApplication.translate("JsonSettingWidget", "Please Select File", - None, QApplication.UnicodeUTF8), parent=parent) + None), parent=parent) + # noinspection PyTypeChecker button.setProperty("clicked", "file") + # noinspection PyTypeChecker button.setProperty("title", setting.get_name()) + # noinspection PyTypeChecker button.setProperty("private", setting.get_check()[:UiFileInput.CHECK_SELECTABLE]) layout = QHBoxLayout() @@ -2664,14 +2726,18 @@ def createInputWidget(setting: UiInputSetting, elif setting.is_folder_type(): widget = QLineEdit(parent) widget.setReadOnly(True) + # noinspection PyTypeChecker widget.setProperty("data", name) widget.setText(setting.get_data()) - + # noinspection PyTypeChecker button = QPushButton(QApplication.translate("JsonSettingWidget", "Please Select Directory", - None, QApplication.UnicodeUTF8), parent=parent) + None), parent=parent) + # noinspection PyTypeChecker button.setProperty("clicked", "folder") + # noinspection PyTypeChecker button.setProperty("title", setting.get_name()) + # noinspection PyTypeChecker button.setProperty("private", setting.get_check()) layout = QHBoxLayout() @@ -2681,15 +2747,20 @@ def createInputWidget(setting: UiInputSetting, elif setting.is_font_type(): widget = QLineEdit(parent) widget.setReadOnly(True) + # noinspection PyTypeChecker widget.setProperty("data", name) widget.setText(setting.get_data()) widget.setStyleSheet(UiFontInput.get_stylesheet(setting.get_data())) + # noinspection PyTypeChecker button = QPushButton(QApplication.translate("JsonSettingWidget", "Please Select Font", - None, QApplication.UnicodeUTF8), parent=parent) + None), parent=parent) + # noinspection PyTypeChecker button.setProperty("clicked", "font") + # noinspection PyTypeChecker button.setProperty("title", setting.get_name()) + # noinspection PyTypeChecker button.setProperty("private", setting.get_data()) layout = QHBoxLayout() @@ -2700,15 +2771,20 @@ def createInputWidget(setting: UiInputSetting, color = setting.get_data() widget = QLineEdit(parent) widget.setReadOnly(True) + # noinspection PyTypeChecker widget.setProperty("data", name) widget.setText("{}".format(setting.get_data())) widget.setStyleSheet("background-color: rgb{}; color: rgb{};".format(color, color)) + # noinspection PyTypeChecker button = QPushButton(QApplication.translate("JsonSettingWidget", "Please Select Color", - None, QApplication.UnicodeUTF8), parent=parent) + None), parent=parent) + # noinspection PyTypeChecker button.setProperty("clicked", "color") + # noinspection PyTypeChecker button.setProperty("title", setting.get_name()) + # noinspection PyTypeChecker button.setProperty("private", setting.get_data()) layout = QHBoxLayout() @@ -2720,6 +2796,7 @@ def createInputWidget(setting: UiInputSetting, # Set property for ComponentManager get data if isinstance(name, str) and isinstance(widget, QWidget): + # noinspection PyTypeChecker widget.setProperty("data", name) # Set readonly option @@ -2774,9 +2851,11 @@ def __initUi(self): elif ui_input.is_select_type(): table_filters[column] = ui_input.get_check() elif ui_input.is_file_type(): + # noinspection PyTypeChecker text = self.tr("Please Select File") table_filters[column] = (text, self.slotSelectFile, ui_input.get_check()) elif ui_input.is_folder_type(): + # noinspection PyTypeChecker text = self.tr("Please Select Directory") table_filters[column] = (text, self.slotSelectFolder, ui_input.get_check()) @@ -2826,6 +2905,7 @@ def slotSelectFile(self): file_format = "*" sender = self.sender() from .dialog import showFileImportDialog + # noinspection PyTypeChecker path = showFileImportDialog(parent=self, title=self.tr("Please Select File"), fmt=self.tr(file_format)) if not os.path.isfile(path): return @@ -2834,6 +2914,7 @@ def slotSelectFile(self): def slotSelectFolder(self): sender = self.sender() + # noinspection PyTypeChecker path = QFileDialog.getExistingDirectory(self, self.tr("Please Select Directory"), "") if not os.path.isdir(path): return @@ -2846,6 +2927,7 @@ def slotSettingChanged(self): sender = self.sender() # Line edit text content check if isinstance(sender, QLineEdit): + # noinspection PyTypeChecker filters = sender.property("filter") try: re.search(filters, sender.text(), re.S).group(0) @@ -2900,6 +2982,7 @@ def __initUi(self): settings[item_name] = self.settings.get(item_name) box_widget = JsonSettingWidget(DynamicObject(**settings)) + # noinspection PyTypeChecker box_widget.setProperty("name", group_settings.get_name()) group_layout.addWidget(box_widget) box.setLayout(group_layout) @@ -3011,6 +3094,7 @@ def __initUi(self): settings[item] = self.settings.get(item) widget = MultiGroupJsonSettingsWidget(DynamicObject(**settings), dict()) + # noinspection PyTypeChecker widget.setProperty('name', tab_setting.name) self.widget_list.append(widget) @@ -3129,9 +3213,13 @@ def __init__(self, filename: str, log_format: str = "%(asctime)s %(levelname)s % # Context menu self.ui_context_menu = QMenu(self) + # noinspection PyTypeChecker self.ui_show_info = QAction(self.tr("Show Info"), self) + # noinspection PyTypeChecker self.ui_show_debug = QAction(self.tr("Show Debug"), self) + # noinspection PyTypeChecker self.ui_show_error = QAction(self.tr("Show Error"), self) + # noinspection PyTypeChecker self.ui_clean_action = QAction(self.tr("Clear All"), self) self.ui_context_menu.addAction(self.ui_clean_action) diff --git a/media/image.py b/media/image.py index 93120f5..4c3a335 100644 --- a/media/image.py +++ b/media/image.py @@ -114,7 +114,7 @@ def bmp_to_16bpp(im: Image.Image, for h in h_list: # Already handle the width can't divisible by 4 issue offset = (height - v - 1) * width * 3 + h * 3 - bpp16.append(pixel_process(original[offset: offset + 3])) + bpp16.append(pixel_process(*original[offset: offset + 3])) header = file_header.raw + info_header.raw if with_header else bytes() return header + struct.pack("<{}H".format(width * height), *tuple(bpp16)) @@ -312,7 +312,7 @@ def createScrollTextGifAnimation(self, text: str, path: str, :param text: text to stroll display :param path: gif file save path :param char_count_per_frame: how many chars will display on each frame(screen) - :param move_pixel_per_frame: how many pixels will moved on each frame + :param move_pixel_per_frame: how many pixels will move on each frame :param duration: gif duration :param wait_frame_count: how many frames it will wait at then end :param blank_frame_count: how many blank frames it will display at the end diff --git a/misc/__init__.py b/misc/__init__.py index 179824e..904f161 100644 --- a/misc/__init__.py +++ b/misc/__init__.py @@ -1 +1 @@ -__all__ = ['tarmanager', 'setup', 'process', 'settings', 'windpi', 'crypto', 'mrc', 'parallel', 'debug'] \ No newline at end of file +__all__ = ['tarmanager', 'setup', 'process', 'settings', 'windpi', 'crypto', 'mrc', 'parallel', 'debug'] diff --git a/misc/crypto.py b/misc/crypto.py index 953239a..db2b1c9 100644 --- a/misc/crypto.py +++ b/misc/crypto.py @@ -78,7 +78,7 @@ def generate_key_pair(bits: int = 2048) -> RSAKeyPair: return RSAKeyPair(public_key=public_key.decode(), private_key=private_key.decode()) @staticmethod - def generate_key_pair_and_save(path: str = "", binary: bool = False, bits: int = 2048) ->bool: + def generate_key_pair_and_save(path: str = "", binary: bool = False, bits: int = 2048) -> bool: key = RSAKeyHandle.generate_key_pair(bits) if not isinstance(key, RSAKeyPair): return False diff --git a/misc/process.py b/misc/process.py index 8dc3098..2852600 100644 --- a/misc/process.py +++ b/misc/process.py @@ -8,7 +8,7 @@ import platform import threading import subprocess -from typing import List, Type +from typing import List __all__ = ['ProcessManager', 'SubprocessWithTimeoutRead', 'subprocess_startup_info_without_console'] diff --git a/misc/settings.py b/misc/settings.py index aa95754..54d1dd7 100644 --- a/misc/settings.py +++ b/misc/settings.py @@ -128,8 +128,8 @@ class UiInputSetting(DynamicObject): SELECT_TYPE_CHECK_DEMO = ("A", "B", "C") # Regular expression, max length - TEXT_TYPE_CHECK_DEMO = ("^(\d+)\.(\d+)\.(\d+)\.(\d+)$", 16, False) - PASSWORD_TYPE_CHECK_DEMO = ("[\s\S]*", 16, True) + TEXT_TYPE_CHECK_DEMO = (r"^(\d+)\.(\d+)\.(\d+)\.(\d+)$", 16, False) + PASSWORD_TYPE_CHECK_DEMO = (r"[\s\S]*", 16, True) def __init__(self, **kwargs): kwargs.setdefault('readonly', False) @@ -146,7 +146,7 @@ def __init__(self, **kwargs): except TypeError: raise ValueError("type ValueError is must be one of theme:{!r}".format(self.INPUT_TYPES)) - # Check check type + # Check type if not isinstance(self.check, check_type): raise TypeError("check type error, it require {!r}".format(data_type)) @@ -347,7 +347,7 @@ class UiTextInput(UiInputSetting): CHECK = collections.namedtuple('UiTextInputCheck', ['REGEXP', 'LENGTH'])(*range(2)) def __init__(self, name: str, length: int, default: str = "", - password: bool = False, re_: str = "[\s\S]*", readonly: bool = False): + password: bool = False, re_: str = r"[\s\S]*", readonly: bool = False): super(UiTextInput, self).__init__(name=name, data=default, default=default, check=(re_, length, password), readonly=readonly, type="TEXT") @@ -362,7 +362,7 @@ def __init__(self, name: str, default: str = "00:00:00", else: h = str(hour_number) length = 6 + hour_number - re_ = Template("^(\d{0,$h}):([0-5]{1})([0-9]{1}):([0-5]{1})([0-9]{1})$$") + re_ = Template(r"^(\d{0,$h}):([0-5]{1})([0-9]{1}):([0-5]{1})([0-9]{1})$$") super(UiTimeInput, self).__init__(name, length, default=default, re_=re_.substitute(h=h), readonly=readonly) @staticmethod @@ -409,7 +409,7 @@ def __init__(self, name: str, default: str = "000.000.000.000", readonly: bool = class UiHexByteInput(UiTextInput): - RegExp = Template("^([0-9a-fA-F]{2}\ ?){0,$len}") + RegExp = Template(r"^([0-9a-fA-F]{2}\ ?){0,$len}") def __init__(self, name: str, length: int, default: str = "00 01 02 03 04 05 06", readonly: bool = False): re_ = self.RegExp.substitute(len=length) diff --git a/misc/tarmanager.py b/misc/tarmanager.py index 4134e5b..77555d2 100644 --- a/misc/tarmanager.py +++ b/misc/tarmanager.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Tar package file manager, support package file/directory to tar, gz, bz2 or unpackage file +Tar package file manager, support package file/directory to tar, gz, bz2 or un-package file """ import os import shutil @@ -300,7 +300,7 @@ def pack(path: str, name: str, fmt: Optional[str] = None, :param name: package name :param fmt: package formats :param extensions: if set only pack those extension names - :param filters: if set when filter is true will packed + :param filters: if set when filter is true will be packed :param verbose: show verbose message :param simulate: set simulate means not real pack only run process to get how many files it;s need to pack :param callback: before pack every file will call this callback function @@ -359,7 +359,7 @@ def pack(path: str, name: str, fmt: Optional[str] = None, if len(extensions) or filters: continue - # Do not has extension and filters pack all + # Do not have extension and filters pack all compress.pack(tar_file, full_path) # Close tarFile diff --git a/misc/windpi.py b/misc/windpi.py index 44b6883..7e0b89f 100644 --- a/misc/windpi.py +++ b/misc/windpi.py @@ -9,19 +9,19 @@ def get_win_dpi() -> DPI: - """ this function get the dpi on X and Y axis of default windows desktop. + """ this function get the dpi on X and Y axis of default Windows desktop. In: none Out: - x_dpi: dpi on x axis. [int] - y_dpi: dpi on y axis. [int] + x_dpi: dpi on x-axis. [int] + y_dpi: dpi on y-axis. [int] """ - para_x = 88 # magic number of windows API for x axis - para_y = 90 # magic number of windows API for y axis + para_x = 88 # magic number of Windows API for x-axis + para_y = 90 # magic number of Windows API for y-axis if platform.system().lower() == "windows": try: @@ -45,13 +45,13 @@ def get_program_scale_factor() -> ScaleFactor: none Out: - scale_x: scale factor on x axis. [float] - scale_y: scale factor on y axis. [float] + scale_x: scale factor on x-axis. [float] + scale_y: scale factor on y-axis. [float] """ - default_dpi_x = 96.0 # default x axis dpi setting for windows - default_dpi_y = 96.0 # default y axis dpi setting for windows + default_dpi_x = 96.0 # default x-axis dpi setting for windows + default_dpi_y = 96.0 # default y-axis dpi setting for windows current_dpi_x, current_dpi_y = get_win_dpi() current_dpi_x = float(current_dpi_x) diff --git a/network/gogs_request.py b/network/gogs_request.py index 41dea09..e2e5a41 100644 --- a/network/gogs_request.py +++ b/network/gogs_request.py @@ -120,10 +120,10 @@ def download_package(self, package: dict, path: str, max_workers: int = 4, ignore_error: bool = True, callback: Optional[Callable[[str, float], bool]] = None) -> Dict[str, bool]: """ - Download an a pack of file + Download a pack of file :param package: Package to download, package is dict include multi-files name is key url is value :param path: Download path, path should be a directory - :param parallel: Thread pool parallel download parallel download + :param parallel: Thread pool parallel download :param max_workers: Thread pool max workers :param timeout: Download timeout for single file :param ignore_error: If set ignore error, when error occurred will ignore error continue download diff --git a/network/netsh.py b/network/netsh.py index 57b00fe..e43400f 100644 --- a/network/netsh.py +++ b/network/netsh.py @@ -318,7 +318,7 @@ def connect(self, ssid: str, auth: str = "", password: str = "", encryption: str class LinuxWirelessNetworkShell: def __init__(self, interface: str = 'wlan0'): self._interface = interface - self._iw_config= f'iwconfig {self._interface}' + self._iw_config = f'iwconfig {self._interface}' def __repr__(self): return f'{self.attr.dict}' diff --git a/network/utility.py b/network/utility.py index bdd90ce..b0d939e 100644 --- a/network/utility.py +++ b/network/utility.py @@ -133,7 +133,7 @@ def set_keepalive(sock: socket.socket, after_idle_sec: int = 1, interval_sec: in :param sock: opened tcp socket :param after_idle_sec: after #after_idle_sec idleness then send keepalive ping :param interval_sec: send keepalive ping every #interval_sec - :param max_fails: after #max_fails times indicate the connection is lose + :param max_fails: after #max_fails times indicate the connection is lost :return: """ _system = platform.system().lower() diff --git a/protocol/__init__.py b/protocol/__init__.py index 992729f..d37a4d3 100644 --- a/protocol/__init__.py +++ b/protocol/__init__.py @@ -1 +1 @@ -__all__ = ['ftp', 'crc16', 'serialport', 'upgrade', 'rmi_shell'] \ No newline at end of file +__all__ = ['ftp', 'crc16', 'serialport', 'upgrade', 'rmi_shell'] diff --git a/protocol/ftp.py b/protocol/ftp.py index 62e889f..1147252 100644 --- a/protocol/ftp.py +++ b/protocol/ftp.py @@ -84,10 +84,10 @@ def is_dir(self, name: str) -> bool: try: cwd = self.ftp.pwd() - # Try enter directory + # Try to enter directory self.ftp.cwd(name) - # Success enter, then return back + # Success, entered, then return self.ftp.cwd(cwd) return True @@ -108,7 +108,7 @@ def is_file(self, name: str) -> bool: return not self.is_dir(name) def is_exist(self, path: str) -> bool: - """Check if path is exist + """Check if path is existed :param path: absolute path :return: True if path exist False not exist @@ -193,7 +193,7 @@ def download_dir(self, remote_dir: str, local_dir: str, pwd = "" exclude = exclude if isinstance(exclude, (list, tuple)) else list() - extensions = [x[2:] for x in [name for name in exclude if re.search("\*.(.*?)", name, re.S)]] + extensions = [x[2:] for x in [name for name in exclude if re.search(r"\*.(.*?)", name, re.S)]] try: # If local dir is not exist create it @@ -281,7 +281,7 @@ def upload_dir(self, local_dir: str, remote_dir: str, pwd = "" exclude = exclude if isinstance(exclude, (list, tuple)) else list() - extensions = [x[2:] for x in [name for name in exclude if re.search("\*.(.*?)", name, re.S)]] + extensions = [x[2:] for x in [name for name in exclude if re.search(r"\*.(.*?)", name, re.S)]] try: @@ -374,7 +374,7 @@ def remove_files(self, remote_dir: str, remove_files: List[str], if not self.is_dir(remote_dir): raise FTPClientError("Remove files error, remote dir:{} is not exist".format(remote_dir)) - # Automatic ignore extx filesystem recovery dir + # Automatic ignore extX filesystem recovery dir if self.EXTx_FS_RECOVERY_DIR in remove_files: remove_files.remove(self.EXTx_FS_RECOVERY_DIR) @@ -428,7 +428,7 @@ def remove_dir(self, remote_dir: str): def force_remove_dir(self, remote_dir: str): try: - # Try remove the whole dir + # Try to remove the whole dir self.remove_dir(remote_dir) except FTPClientError: try: diff --git a/protocol/protobuf.py b/protocol/protobuf.py index 6e7724b..d54522a 100644 --- a/protocol/protobuf.py +++ b/protocol/protobuf.py @@ -82,7 +82,7 @@ def __init__(self, transmit: Transmit, max_msg_length: int, event_callback: Call Init a protocol buffers sdk :param transmit: Data transmit (TCPTransmit or UDPTransmit or self-defined TCPTransmit) :param max_msg_length: protocol buffers maximum message length - :param event_callback: when sdk has event will callback this + :param event_callback: when sdk has event will call back this """ if not isinstance(transmit, Transmit): raise TypeError('{!r} required {!r}'.format('transmit', Transmit.__name__)) @@ -151,7 +151,7 @@ def sendRequestToQueue(self, :param msg: request message :param callback: after receive response will call this callback :param priority: message priority if set as None using it as normal queue - :param periodic: it this message is periodic request(do not need retry if send failed) + :param periodic: it this message is periodic request(do not need to retry if send failed) :return: """ try: diff --git a/protocol/rmi_shell.py b/protocol/rmi_shell.py index 465224e..416bb26 100644 --- a/protocol/rmi_shell.py +++ b/protocol/rmi_shell.py @@ -203,7 +203,7 @@ def tftp_upload_file(self, local_file: str, remote_path: str = "/tmp", remote_na network: Optional[ipaddress.IPv4Network] = None, random_port: bool = True, verbose: bool = False, verify_by_md5: bool = True, timeout: int = 60) -> bool: """ - Uoload a local_file from local to remote + Upload a local_file from local to remote :param local_file: file to upload :param remote_path: file upload to remote path :param remote_name: if is not empty will rename to this name diff --git a/protocol/serialport.py b/protocol/serialport.py index 798d39d..ffede3e 100644 --- a/protocol/serialport.py +++ b/protocol/serialport.py @@ -187,7 +187,7 @@ class SerialTransferProtocol(object): PAYLOAD_SIZE = 128 def __init__(self, send: SerialSendCallback, recv: SerialRecvCallback): - """"Init a serial port transfer protocol object + """Init a serial port transfer protocol object :param send: serial port send function :param recv: serial port receive function @@ -307,7 +307,7 @@ def __r_data(self, package_index: int) -> bytes: return ack.get_data_payload() def __w_init(self, package_size: int, global_data: bytes) -> WriteAckMsg: - """Launch a write transfer section + """Launch a write transport section :param package_size: will write total package size :param global_data: global data @@ -440,7 +440,7 @@ def get_serial_list(timeout: float = 0.04) -> List[str]: port_list.append("{}".format(port)) else: for index, port in enumerate(list(serial.tools.list_ports.comports())): - # Windows serial port is a object linux is a tuple + # Windows serial port is an object linux is a tuple device = port.device desc = "{0:s}".format(device).split(" - ")[-1] port_list.append("{0:s}".format(desc)) diff --git a/protocol/upgrade.py b/protocol/upgrade.py index 1774ffa..c3c4c22 100644 --- a/protocol/upgrade.py +++ b/protocol/upgrade.py @@ -22,13 +22,13 @@ class UpgradeClient(object): - def __init__(self, name, addr, port, timeout=3): + def __init__(self, name, host, port, timeout=3): timeout = timeout if isinstance(timeout, int) else 3 if not isinstance(name, str): raise TypeError("name require {!r} not {!r}".format(str.__name__, name.__class__.__name__)) self.__key = name - self.__addr = addr + self.__host = host self.__port = port self.__connected = False @@ -38,14 +38,14 @@ def __init__(self, name, addr, port, timeout=3): try: # Connect upgrade server self.sock.settimeout(timeout) - self.sock.connect((self.__addr, self.__port)) + self.sock.connect((self.__host, self.__port)) # Mark connect success self.__connected = True except (TypeError, socket.error) as e: self.__connected = False - print("Connect server:{}:{} error:{}".format(self.__addr, self.__port, e)) + print("Connect server:{}:{} error:{}".format(self.__host, self.__port, e)) def __del__(self): if self.__connected: @@ -238,10 +238,10 @@ def get_file_server_address(self): return self.__file_server def get_newest_version(self, software): - """Get newest software version + """Get the newest software version :param software: software name - :return: software newest version + :return: the newest version """ package_dir = software @@ -260,7 +260,7 @@ def get_newest_version(self, software): return 0.0 def get_newest_version_durl(self, software): - """Get newest software download address + """Get the newest software download address :param software: software name :return: software info and download url @@ -276,7 +276,7 @@ def get_newest_version_durl(self, software): if version == 0.0: return "No new version to download" - # Get newest version download path + # Get the newest version download path for name in [x for x in os.listdir(software) if self.UPGRADE_PACKAGE_SUFFIX in x]: if str2float(os.path.splitext(name)[0]) == version: file_name = name diff --git a/requments.txt b/requments.txt new file mode 100644 index 0000000..30a9594 --- /dev/null +++ b/requments.txt @@ -0,0 +1,25 @@ +PySide2 + +wmi +pytest +win32gui +pyserial + +lz4 +qrcode +pyzbar +psutil + +tftpy +ping3 +ifaddr +pyquery +paramiko +protobuf +websocket +requests_toolbelt + +pyDes +pycryptodome +pycrypto +pycrypto \ No newline at end of file diff --git a/tests/crypto_test.py b/tests/crypto_test.py index 2ffc448..908ee7d 100644 --- a/tests/crypto_test.py +++ b/tests/crypto_test.py @@ -15,7 +15,7 @@ def setUp(self) -> None: def testAES(self): with self.assertRaises(TypeError): - AESCrypto(key=b'amaork') + AESCrypto(key='amaork') with self.assertRaises(ValueError): AESCrypto(key='amaork', mode="cbc")