├── Esp.py ├── Preferences.py ├── README.md ├── SourceCodePro.py ├── SourceCodePro.ttf ├── check.py ├── ctrl.py ├── graphicsInterface.py ├── images ├── clear.png ├── downloadandrun.png ├── fileopen.png ├── ic.png ├── logo.ico ├── logo.png ├── newfile.png ├── pc.png ├── redo.png ├── save.png ├── serialClose.png ├── serialConnect.png ├── stop.png ├── syntaxCheck.png ├── tabClose.png ├── tabCloseHover.png ├── treeBranchClose.png ├── treeBranchOpen.png ├── treeFileOpen.png ├── treeMenuClosed.png └── undo.png ├── mainComponents.py ├── microbit_api.py ├── pack.py ├── pyflakesChange └── api.py ├── qrc_resources.py ├── readWriteUart.py ├── resources.qrc ├── threadDownloadFirmware.py ├── uPyCraft.py └── updateNewFirmware.py /Preferences.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | import sys 3 | import time 4 | import serial 5 | import serial.tools.list_ports 6 | 7 | from PyQt4.QtCore import * 8 | from PyQt4.QtGui import * 9 | 10 | class SerialWidget(QWidget): 11 | def __init__(self,parent=None): 12 | super(SerialWidget,self).__init__(parent) 13 | 14 | serialBaund=QLabel("baud") 15 | self.baundComboBox=QComboBox() 16 | self.baundComboBox.addItems(['100','300','600','1200','2400','4800','9600','14400','19200','38400','56000','57600','115200','128000','256000']) 17 | self.baundComboBox.setCurrentIndex(12) 18 | 19 | serialBytesize=QLabel("bytesize") 20 | self.bytesizeComboBox=QComboBox() 21 | self.bytesizeComboBox.addItems(['5','6','7','8']) 22 | self.bytesizeComboBox.setCurrentIndex(3) 23 | 24 | serialParity=QLabel("parity") 25 | self.parityComboBox=QComboBox() 26 | self.parityComboBox.addItems(['NONE','EVEN','ODD','MARK','SPACE']) 27 | self.parityComboBox.setCurrentIndex(0) 28 | 29 | #serialTimeout 30 | 31 | serialStopbits=QLabel("stopbits") 32 | self.stopbitsComboBox=QComboBox() 33 | self.stopbitsComboBox.addItems(['1','1.5','2']) 34 | self.stopbitsComboBox.setCurrentIndex(0) 35 | 36 | self.okButton=QPushButton(self.tr("ok")) 37 | self.cancelButton=QPushButton(self.tr("cancel")) 38 | 39 | self.detailWidget=QWidget() 40 | detailLayout=QGridLayout(self.detailWidget) 41 | detailLayout.addWidget(serialBaund,0,0) 42 | detailLayout.addWidget(self.baundComboBox,0,1) 43 | detailLayout.addWidget(serialBytesize,1,0) 44 | detailLayout.addWidget(self.bytesizeComboBox,1,1) 45 | 46 | detailLayout.addWidget(serialStopbits,2,0) 47 | detailLayout.addWidget(self.stopbitsComboBox,2,1) 48 | 49 | detailLayout.addWidget(serialParity,3,0) 50 | detailLayout.addWidget(self.parityComboBox,3,1) 51 | 52 | #self.detailWidget.hide() 53 | detailLayout.addItem(QSpacerItem(200,200),4,0) 54 | self.setLayout(detailLayout) 55 | 56 | self.ser=serial.Serial() 57 | def Port_List(self): 58 | Com_List=[] 59 | port_list = list(serial.tools.list_ports.comports()) 60 | for port in port_list: 61 | Com_List.append(port[0]) 62 | return Com_List 63 | def comChooseOk(self,com): 64 | self.ser.port=com 65 | self.ser.baudrate = self.baundComboBox.currentText() 66 | self.ser.bytesize = int(self.bytesizeComboBox.currentText()) 67 | 68 | ParityValue = self.parityComboBox.currentText() 69 | self.ser.parity = ParityValue[0] 70 | self.ser.stopbits = int(self.stopbitsComboBox.currentText()) 71 | self.ser.timeout=0.001 72 | self.ser.flow="N" 73 | self.ser.open() 74 | 75 | class LanLocWidget(QWidget): 76 | def __init__(self,parent=None): 77 | super(LanLocWidget,self).__init__(parent) 78 | 79 | languageLabel=QLabel(self.tr("Language")) 80 | self.languageComBox=QComboBox() 81 | self.languageComBox.addItems(['English']) 82 | self.languageComBox.setCurrentIndex(0) 83 | 84 | locationLabel=QLabel(self.tr("Location")) 85 | self.locationComboBox=QComboBox() 86 | self.locationComboBox.addItems(['China Mainland','Others']) 87 | self.locationComboBox.setCurrentIndex(1) 88 | 89 | self.detailWidget=QWidget() 90 | detailLayout=QGridLayout(self.detailWidget) 91 | #detailLayout.addWidget(serialPort,0,0) 92 | #detailLayout.addWidget(self.portComboBox,0,1) 93 | detailLayout.addWidget(languageLabel,0,0) 94 | detailLayout.addWidget(self.languageComBox,0,1) 95 | detailLayout.addWidget(locationLabel,1,0) 96 | detailLayout.addWidget(self.locationComboBox,1,1) 97 | #self.detailWidget.hide() 98 | detailLayout.addItem(QSpacerItem(200,200),2,0) 99 | self.setLayout(detailLayout) 100 | 101 | class updateConfig(QWidget): 102 | def __init__(self,parent=None): 103 | super(updateConfig,self).__init__(parent) 104 | 105 | checkFirmware=QLabel(self.tr("CheckFirmware")) 106 | self.checkBinComBox=QComboBox() 107 | self.checkBinComBox.addItems(['check update','no check']) 108 | self.checkBinComBox.setCurrentIndex(0) 109 | 110 | self.detailWidget=QWidget() 111 | detailLayout=QGridLayout(self.detailWidget) 112 | detailLayout.addWidget(checkFirmware,0,0) 113 | detailLayout.addWidget(self.checkBinComBox,0,1) 114 | 115 | detailLayout.addItem(QSpacerItem(200,200),1,0) 116 | self.setLayout(detailLayout) 117 | 118 | class Preferences(QDialog): 119 | def __init__(self,parent=None): 120 | super(Preferences,self).__init__(parent) 121 | self.widget=QWidget() 122 | layout=QGridLayout(self.widget) 123 | 124 | self.landlocation=LanLocWidget(self) 125 | self.configUpdate=updateConfig() 126 | 127 | tabWidget=QTabWidget() 128 | tabWidget.setTabPosition(QTabWidget.West); 129 | tabWidget.addTab(SerialWidget(self),"Serial") 130 | tabWidget.addTab(self.landlocation,"Languare Location") 131 | tabWidget.addTab(self.configUpdate,"config") 132 | layout.addWidget(tabWidget,1,0) 133 | self.setLayout(layout) 134 | self.resize(300,200) 135 | self.setWindowTitle("Preferences") 136 | self.setWindowIcon(QIcon(':/logo.png')) 137 | 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uPyCraft_src 2 | #### uPyCraft is an IDE designed for micropython that supports Windows 7, Windows 8, Windows 10, Linux, MAC OSX 10.11, and above.To make it easier for users to use, uPyCraft is released in green in all systems, no need to install. 3 | 4 | # Windows 5 | ## Installation 6 | This requires you to have python3.4, pyqt4, py2exe, qsci, pyserial and pyflakes installed. 7 | 8 | 1. python3.4:
9 | 10 |    download address:https://www.python.org/downloads/windows/
11 |        add python to the windows environment variable when installed.
12 | 13 | update pip: python -m pip install -U pip 14 | add pip to the windows environment variable, such as C:/Python34/Scripts 15 | 16 | pyserial:pip install pyserial 17 | 18 | py2exe :pip install py2exe 19 | Python34/Lib/site-packages/py2exe/icons.py Modify lines89:if iconheader.idCount>10 -> if iconheader.idCount>20 20 | 21 | pyflakes:pip install pyflakes 22 | find api.py and replace with pyflakesChange/api.py 23 | 24 | 2. pyqt4:
25 | 26 | sip:
27 | download address:https://www.riverbankcomputing.com/software/sip/download
28 | 29 | unpack the directory and open 30 | exec: 31 | python configure.py 32 | 33 | enter Visual Studio command prompt, changedir to sip installed path 34 | nmake 35 | nmake install 36 | 37 | PyQt4:
38 | download address:https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/
39 | follow "next" to install.
40 | 41 | ## Running 42 | Open uPyCraft.py with python3.4 IDE, click the run module button/F5 to run. 43 | 44 | ## Package uPyCraft 45 | uPyCraft.exe will be created in directory dist/ . 46 | 47 | 48 | 49 | # Linux 50 | ## Environment 51 | ubuntu16.04 LTS Python3.5 PyQt4 52 | ## Install 53 | ### SIP
54 | Download SIP from https://riverbankcomputing.com/software/sip/download
55 | 56 | tar zxvf sip-4.19.tar.gz -C /home/PyQt 57 | sudo python configure.py 58 | sudo make install 59 | ### QT support library
60 | 61 | sudo apt-get install qt4-dev-tools qt4-doc qt4-qtconfig qt4-demos qt4-designer 62 | sudo apt-get install libqwt5-qt4 libqwt5-qt4-dev 63 | ### PyQt4
64 | Download PyQt4_gpl_x11-4.12 from https://sourceforge.net/projects/pyqt/files/PyQt4/
65 | 66 | tar zxvf PyQt4_gpl_x11-4.12.tar.gz -C /home/PyQt 67 | cd /home/PyQt/PyQt4_gpl_x11-4.12 68 | sudo python configure.py 69 | sudo make 70 | sudo make install 71 | ### QScintilla 72 | Download QScintilla from https://sourceforge.net/projects/pyqt/files/QScintilla2/QScintilla-2.9.1/
73 | 74 | tar zxvf QScintilla-2.9.1.tar.gz 75 | cd QScintilla-2.9.1 76 | #Qt4Qt5 77 | cd Qt4Qt5 78 | qmake 79 | sudo make 80 | sudo make install 81 | #Python 82 | cd ../Python 83 | python3 configure.py 84 | sudo make 85 | sudo make install 86 | #designer-Qt4Qt5 87 | cd ../designer-Qt4Qt5 88 | qmake designer.pro 89 | sudo make 90 | sudo make install 91 | ### Package uPyCraft
92 | pip install pyinstaller 93 | pyinstaller -F uPyCraft.py 94 | 95 | 96 | 97 | # Mac 98 | ## Environment 99 | os 10.11 Python3.5 PyQt4 100 | ## Install 101 | ### qt4.8.7
102 | Download qt4.8.7 from http://mirrors.ustc.edu.cn/qtproject/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.tar.gz
103 | 104 | cd Desktop 105 | tar vxf qt-everywhere-opensource-src-4.8.7.tar.gz 106 | In qt-everywhere-opensource-src-4.8.7/src/gui/painting/qpaintengine_mac.cpp
107 | insted: 108 | 109 | CGColorSpaceRef colorSpace = 0; 110 | CMProfileRef displayProfile = 0; 111 | CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile); 112 | if (err == noErr) { 113 | colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile); 114 | CMCloseProfile(displayProfile); 115 | } 116 | to: 117 | 118 | CGColorSpaceRef colorSpace = CGDisplayCopyColorSpace(displayID); 119 | 120 | install: 121 | 122 | cd qt-everywhere-opensource-src-4.8.7 123 | ./configure 124 | make #2-4h 125 | sudo make install 126 | 127 | configure environment: 128 | 129 | cd 130 | vim .bash_profile 131 | 132 | PATH=/usr/local/Trolltech/Qt-4.8.7/bin:$PATH 133 | export PATH 134 | 135 | source ~/.bash_profile 136 | 137 | qmake: 138 | 139 | qmake -v 140 | QMake version 2.01a 141 | Using Qt version 4.8.7 in /usr/local/Trolltech/Qt-4.8.7/lib 142 | 143 | ### SIP 144 | Download SIP from https://sourceforge.net/projects/pyqt/files/sip/sip-4.19.8/sip-4.19.8.tar.gz/download
145 | 146 | cd Desktop 147 | tar vxf sip-4.19.8.tar.gz 148 | cd sip-4.19.8 149 | sudo python3 configure.py 150 | sudo make install 151 | 152 | ### PyQt4 153 | Download PyQt4 from https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.12.1/PyQt4_gpl_mac-4.12.1.tar.gz/download
154 | 155 | cd Desktop 156 | tar vxf PyQt4_gpl_mac-4.12.1.tar.gz 157 | cd PyQt4_gpl_mac_4.12.1 158 | sudo python3 configure.py 159 | sudo make #20min 160 | sudo make install 161 | 162 | ### QScintilla 163 | Download QScintilla from https://sourceforge.net/projects/pyqt/files/QScintilla2/QScintilla-2.9.1/QScintilla-gpl-2.9.1.tar.gz/download
164 | 165 | cd Desktop 166 | tar vxf QScintilla-gpl-2.9.1.tar.gz 167 | cd QScintilla-gpl-2.9.1 168 | #Qt4Qt5 169 | cd Qt4Qt5 170 | qmake 171 | sudo make 172 | sudo make install 173 | #Python 174 | cd ../Python 175 | python3 configure.py 176 | sudo make 177 | sudo make install 178 | #designer-Qt4Qt5 179 | cd ../designer-Qt4Qt5 180 | qmake designer.pro 181 | sudo make 182 | sudo make install 183 | 184 | ### Package uPyCraft
185 | 186 | pip install pyinstaller 187 | pyinstaller -F uPyCraft.py 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /SourceCodePro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/SourceCodePro.ttf -------------------------------------------------------------------------------- /check.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | import sys 3 | import threading 4 | import time 5 | import os 6 | import json 7 | from urllib import request 8 | import platform 9 | import socket 10 | import zipfile 11 | 12 | 13 | from PyQt4.QtCore import * 14 | from PyQt4.QtGui import * 15 | 16 | nowIDEVersion ="1.1" 17 | nowExamplesVersion="v0.0" 18 | rootDirectoryPath =os.path.expanduser("~") 19 | rootDirectoryPath =rootDirectoryPath.replace("\\","/") 20 | 21 | class checkVersionExampleFire(QThread): 22 | def __init__(self,parent): 23 | super(checkVersionExampleFire,self).__init__(parent) 24 | self.ui=parent 25 | 26 | self.updateSize=0 27 | 28 | self.per=0 29 | self.runStep="" 30 | self.url="" 31 | self.downpath="" 32 | self.isDownload=False 33 | self.nowDownload="" 34 | self.reDownloadNum=0 35 | self.downloadOk=False 36 | self.status=404 37 | 38 | self.connect(self.ui,SIGNAL("exitCheckThread"),self.exitCheckThread) 39 | 40 | def run(self): 41 | global nowExamplesVersion 42 | 43 | if os.path.exists("%s/AppData/Local/uPyCraft/examples/info.json"%rootDirectoryPath)==True: 44 | myfile=open("%s/AppData/Local/uPyCraft/examples/info.json"%rootDirectoryPath,"r") 45 | jsonMsg=myfile.read() 46 | myfile.close() 47 | jsonMsg=json.loads(jsonMsg) 48 | nowExamplesVersion=jsonMsg["version"] 49 | 50 | checkUpdateUrl="" 51 | if os.path.exists("%s/AppData/Local/uPyCraft/config.json"%rootDirectoryPath)==True: 52 | myfile=open("%s/AppData/Local/uPyCraft/config.json"%rootDirectoryPath,'r') 53 | jsonMsg=myfile.read() 54 | myfile.close() 55 | jsonDict=eval(jsonMsg) 56 | 57 | checkUpdateUrl=jsonDict['updateURL'] 58 | 59 | page="" 60 | if checkUpdateUrl=="": 61 | self.exit() 62 | return 63 | 64 | try: 65 | self.status=request.urlopen(checkUpdateUrl).code 66 | except: 67 | self.status=404 68 | print(self.status) 69 | if self.status==404: 70 | self.exit() 71 | return 72 | else: 73 | res=request.urlopen(checkUpdateUrl) 74 | page=res.read().decode() 75 | print(page) 76 | myfile = open("%s/AppData/Local/uPyCraft/update.json"%rootDirectoryPath,"w") 77 | myfile.write(page) 78 | myfile.close() 79 | 80 | self.emit(SIGNAL("changeIsCheckFirmware"),True) 81 | 82 | self.system = platform.system()#system check 83 | 84 | print(self.system) 85 | print(nowIDEVersion) 86 | print(nowExamplesVersion) 87 | 88 | if page=="": 89 | self.exit() 90 | return 91 | jsonmsg=json.loads(page) 92 | 93 | self.ideList = jsonmsg['IDE'] 94 | self.firmwareList = jsonmsg['firmware'] 95 | self.examplesList = jsonmsg['examples'] 96 | 97 | self.emit(SIGNAL("changeUpdateFirmwareList"),self.firmwareList) 98 | 99 | self.connect(self.ui,SIGNAL("confirmUpdata"),self.confirmUpdata) 100 | 101 | #IDE 102 | if self.ideList[0]["version"]>nowIDEVersion: 103 | print("ide has new version") 104 | self.isDownload=True 105 | self.emit(SIGNAL("updateThing"),"update uPyCraft IDE","There is a new version available for uPyCraft, would you like to upgrade now?") 106 | else: 107 | #examples 108 | if self.examplesList[0]["version"]>nowExamplesVersion: 109 | print("examples has new version") 110 | self.isDownload=True 111 | self.emit(SIGNAL("updateThing"),"update uPyCraft Examples","There is a new version available for EXAMPLES, would you like to upgrade now?") 112 | while 1: 113 | if self.isDownload==True: 114 | if self.nowDownload=="": 115 | time.sleep(0.1) 116 | elif self.nowDownload == "IDE": 117 | self.nowDownload="" 118 | self.reDownloadNum=0 119 | self.reDownload() 120 | if self.downloadOk==False: 121 | self.isDownload=False 122 | break 123 | 124 | #QMessageBox.information(self.ui,self.tr("attention"),self.tr("Please delete the old edition and use the updated one."),QMessageBox.Ok) 125 | 126 | if self.examplesList[0]["version"]>nowExamplesVersion: 127 | print("examples has new version") 128 | self.emit(SIGNAL("updateThing"),"update uPyCraft Examples","There is a new version available for EXAMPLES, would you like to upgrade now?") 129 | else: 130 | self.isDownload=False 131 | elif self.nowDownload == "Examples": 132 | self.nowDownload="" 133 | self.reDownloadNum=0 134 | self.reDownload() 135 | if self.downloadOk==False: 136 | self.isDownload=False 137 | break 138 | if self.per==100: 139 | f=zipfile.ZipFile(self.downpath,"r") 140 | for afile in f.namelist(): 141 | f.extract(afile,"%s/AppData/Local/uPyCraft"%rootDirectoryPath) 142 | f.close() 143 | self.emit(SIGNAL("reflushExamples")) 144 | self.isDownload=False 145 | else: 146 | break 147 | self.exit() 148 | 149 | def exitCheckThread(self): 150 | self.exit() 151 | 152 | def reDownload(self): 153 | if self.reDownloadNum==3: 154 | self.downloadOk=False 155 | self.emit(SIGNAL("updatePer"),-1) 156 | return 157 | try: 158 | socket.setdefaulttimeout(3) 159 | request.urlretrieve(self.url,self.downpath,self.cbkUpdate) 160 | self.downloadOk=True 161 | return 162 | except: 163 | print("urllib err :%s"%self.url) 164 | self.reDownloadNum+=1 165 | self.reDownload() 166 | 167 | 168 | def confirmUpdata(self,gotoUpdata): 169 | if gotoUpdata=="IDE": 170 | self.idenameList = str(self.ideList[0][self.system]["url"]).split("/") 171 | self.updateSize=self.ideList[0][self.system]["size"] 172 | self.url=self.ideList[0][self.system]["url"] 173 | self.downpath=self.idenameList[-1] 174 | self.nowDownload="IDE" 175 | elif gotoUpdata=="IDEcancel": 176 | if self.examplesList[0]["version"]>nowExamplesVersion: 177 | print("examples has new version") 178 | self.emit(SIGNAL("updateThing"),"update uPyCraft Examples","There is a new version available for EXAMPLES, would you like to upgrade now?") 179 | else: 180 | self.isDownload=False 181 | elif gotoUpdata=="Examples": 182 | self.url = self.examplesList[0]["url"] 183 | examplesNameList = str(self.url).split("/") 184 | self.updateSize=self.examplesList[0]["size"] 185 | self.downpath="%s/AppData/Local/uPyCraft/download/%s"%(rootDirectoryPath,examplesNameList[-1]) 186 | self.nowDownload="Examples" 187 | elif gotoUpdata=="Examplescancel": 188 | self.isDownload=False 189 | 190 | 191 | def cbkUpdate(self,blocknum,blocksize,totalsize): 192 | self.per=100.0*blocknum*blocksize/self.updateSize 193 | if self.per>=100: 194 | self.per=100 195 | self.emit(SIGNAL("updatePer"),self.per) 196 | return 197 | 198 | self.emit(SIGNAL("updatePer"),self.per) 199 | 200 | class attentionUpdata(QDialog): 201 | def __init__(self,title,labelmsg,parent=None): 202 | super(attentionUpdata,self).__init__(parent) 203 | self.setWindowTitle(title) 204 | 205 | self.setWindowIcon(QIcon(':/logo.png')) 206 | 207 | self.okButton=QPushButton(self.tr("ok")) 208 | self.cancelButton=QPushButton(self.tr("cancel")) 209 | 210 | self.label=QLabel(self.tr(labelmsg)) 211 | #self.label.setFixedSize(400, 80) 212 | self.label.setWordWrap(True) 213 | self.label.adjustSize() 214 | 215 | self.detailWidget=QWidget() 216 | layout = QGridLayout(self.detailWidget) 217 | layout.addWidget(self.label,0,0,1,3) 218 | layout.addWidget(self.okButton,1,0) 219 | layout.addWidget(self.cancelButton,1,3) 220 | 221 | self.setLayout(layout) 222 | self.setFixedSize(500, 100) 223 | self.connect(self.okButton,SIGNAL("clicked()"),self.chooseOk) 224 | self.connect(self.cancelButton,SIGNAL("clicked()"),self.chooseCancel) 225 | 226 | def chooseOk(self): 227 | self.close() 228 | 229 | def chooseCancel(self): 230 | self.close() 231 | 232 | 233 | class ProgressIDEorExampleBar(QDialog): 234 | def __init__(self, windowname,parent=None): 235 | super(ProgressIDEorExampleBar,self).__init__(parent) 236 | self.pbar = QProgressBar(self) 237 | detailLayout=QGridLayout() 238 | detailLayout.addWidget(self.pbar) 239 | self.setLayout(detailLayout) 240 | self.setWindowTitle(windowname) 241 | self.setWindowIcon(QIcon(':/logo.png')) 242 | self.resize(300,150) 243 | 244 | def timerEvent(self, per): 245 | if per >= 100: 246 | return 247 | self.pbar.setValue(per) 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /graphicsInterface.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | from PyQt4.QtCore import * 3 | from PyQt4.QtGui import * 4 | 5 | import sys 6 | import time 7 | import serial 8 | import serial.tools.list_ports 9 | 10 | if sys.platform=="darwin": 11 | pass 12 | else: 13 | QTextCodec.setCodecForTr(QTextCodec.codecForName("utf8")) 14 | 15 | class findReplaceText(QDialog): 16 | def __init__(self,parent=None): 17 | super(findReplaceText,self).__init__(parent) 18 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 19 | self.setWindowTitle("Find&Replace") 20 | self.setWindowIcon(QIcon(':/logo.png')) 21 | self.setStyleSheet("""QDialog{background-color: rgb(236, 236, 236);color:black;} 22 | QPushButton{background-color:rgb(253,97,72);color:white;} 23 | QPushButton:hover{background-color:rgb(212,212,212);color:black;} 24 | """) 25 | self.findedit=QLineEdit() 26 | self.findButton=QPushButton(self.tr("find")) 27 | self.replaceStartEdit=QLineEdit() 28 | self.replaceToEdit=QLineEdit() 29 | self.replaceButton=QPushButton(self.tr("replace")) 30 | self.msg=QLabel(self.tr("To")) 31 | 32 | self.layout=QGridLayout() 33 | self.layout.addWidget(self.findedit,0,0,1,3) 34 | self.layout.addWidget(self.findButton,0,3) 35 | self.layout.addWidget(self.replaceStartEdit,1,0) 36 | self.layout.addWidget(self.msg,1,1) 37 | self.layout.addWidget(self.replaceToEdit,1,2) 38 | self.layout.addWidget(self.replaceButton,1,3) 39 | 40 | self.setLayout(self.layout) 41 | 42 | class saveUntitled(QDialog): 43 | def __init__(self,parent=None): 44 | super(saveUntitled,self).__init__(parent) 45 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 46 | self.setWindowTitle("save at your workSpace") 47 | self.resize(400,80) 48 | self.setWindowIcon(QIcon(':/logo.png')) 49 | 50 | self.setStyleSheet("""QDialog{background-color: rgb(236, 236, 236);color:black;} 51 | QPushButton{background-color:rgb(253,97,72);color:white;} 52 | """) 53 | 54 | self.saveFileLabel=QLabel(self.tr("Input file name")) 55 | self.saveFileTextedit=QLineEdit() 56 | 57 | self.saveFileWidget=QWidget() 58 | 59 | self.okButton=QPushButton(self.tr("ok")) 60 | self.cancelButton=QPushButton(self.tr("cancel")) 61 | 62 | saveFileLayout=QGridLayout(self.saveFileWidget) 63 | 64 | saveFileLayout.addWidget(self.saveFileLabel,0,0) 65 | saveFileLayout.addWidget(self.saveFileTextedit,0,1) 66 | saveFileLayout.addWidget(self.okButton,1,0) 67 | saveFileLayout.addWidget(self.cancelButton,1,1) 68 | self.saveFileWidget.hide() 69 | self.setLayout(saveFileLayout) 70 | 71 | self.connect(self.okButton,SIGNAL("clicked()"),self.saveFileEditOk) 72 | self.connect(self.cancelButton,SIGNAL("clicked()"),self.saveFileEditCancle) 73 | 74 | def saveFileEditOk(self): 75 | self.close() 76 | 77 | def saveFileEditCancle(self): 78 | self.close() 79 | 80 | class treeRightClickRename(QDialog): 81 | def __init__(self,parent=None): 82 | super(treeRightClickRename,self).__init__(parent) 83 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 84 | self.setWindowTitle("Rename as") 85 | self.setWindowIcon(QIcon(':/logo.png')) 86 | self.setStyleSheet("""QDialog{background-color: rgb(236, 236, 236);color:black;} 87 | QPushButton{background-color:rgb(253,97,72);color:white;} 88 | """) 89 | 90 | self.nameLabel=QLabel(self.tr("new name:")) 91 | self.nameLineEdit=QLineEdit() 92 | 93 | self.okButton=QPushButton(self.tr("ok")) 94 | self.cancelButton=QPushButton(self.tr("cancel")) 95 | 96 | 97 | self.connect(self.okButton,SIGNAL("clicked()"),self.renameOk) 98 | self.connect(self.cancelButton,SIGNAL("clicked()"),self.renameCancel) 99 | 100 | layout=QGridLayout() 101 | layout.addWidget(self.nameLabel,0,0) 102 | layout.addWidget(self.nameLineEdit,0,1) 103 | layout.addWidget(self.okButton,1,0) 104 | layout.addWidget(self.cancelButton,1,1) 105 | self.setLayout(layout) 106 | 107 | 108 | def renameOk(self): 109 | self.close() 110 | def renameCancel(self): 111 | self.close() 112 | 113 | class createBoardNewDirName(QDialog): 114 | def __init__(self,parent=None): 115 | super(createBoardNewDirName,self).__init__(parent) 116 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 117 | self.setWindowTitle("boardDirName") 118 | self.setWindowIcon(QIcon(':/logo.png')) 119 | self.setStyleSheet("""QDialog{background-color: rgb(236, 236, 236);color:black;} 120 | QPushButton{background-color:rgb(253,97,72);color:white;} 121 | """) 122 | self.resize(200,80) 123 | self.nameLabel=QLabel(self.tr("Input Dir Name")) 124 | self.nameLineEdit=QLineEdit() 125 | 126 | self.nameWidget=QWidget() 127 | self.okButton=QPushButton(self.tr("ok")) 128 | self.cancelButton=QPushButton(self.tr("cancel")) 129 | 130 | layout=QGridLayout(self.nameWidget) 131 | layout.addWidget(self.nameLabel,0,0) 132 | layout.addWidget(self.nameLineEdit,0,1) 133 | layout.addWidget(self.okButton,1,0) 134 | layout.addWidget(self.cancelButton,1,1) 135 | self.nameWidget.hide() 136 | self.setLayout(layout) 137 | 138 | self.connect(self.okButton,SIGNAL("clicked()"),self.nameEditOk) 139 | self.connect(self.cancelButton,SIGNAL("clicked()"),self.nameEditCancel) 140 | 141 | def nameEditOk(self): 142 | self.close() 143 | def nameEditCancel(self): 144 | self.close() 145 | 146 | 147 | class SerialWidget(QWidget): 148 | def __init__(self,parent=None): 149 | super(SerialWidget,self).__init__(parent) 150 | 151 | serialBaund=QLabel("baud") 152 | self.baundComboBox=QComboBox() 153 | self.baundComboBox.addItems(['100','300','600','1200','2400','4800','9600','14400','19200','38400','56000','57600','115200','128000','256000']) 154 | self.baundComboBox.setCurrentIndex(12) 155 | 156 | serialBytesize=QLabel("bytesize") 157 | self.bytesizeComboBox=QComboBox() 158 | self.bytesizeComboBox.addItems(['5','6','7','8']) 159 | self.bytesizeComboBox.setCurrentIndex(3) 160 | 161 | serialParity=QLabel("parity") 162 | self.parityComboBox=QComboBox() 163 | self.parityComboBox.addItems(['NONE','EVEN','ODD','MARK','SPACE']) 164 | self.parityComboBox.setCurrentIndex(0) 165 | 166 | #serialTimeout 167 | 168 | serialStopbits=QLabel("stopbits") 169 | self.stopbitsComboBox=QComboBox() 170 | self.stopbitsComboBox.addItems(['1','1.5','2']) 171 | self.stopbitsComboBox.setCurrentIndex(0) 172 | 173 | self.okButton=QPushButton(self.tr("ok")) 174 | self.cancelButton=QPushButton(self.tr("cancel")) 175 | 176 | self.detailWidget=QWidget() 177 | detailLayout=QGridLayout(self.detailWidget) 178 | detailLayout.addWidget(serialBaund,0,0) 179 | detailLayout.addWidget(self.baundComboBox,0,1) 180 | detailLayout.addWidget(serialBytesize,1,0) 181 | detailLayout.addWidget(self.bytesizeComboBox,1,1) 182 | 183 | detailLayout.addWidget(serialStopbits,2,0) 184 | detailLayout.addWidget(self.stopbitsComboBox,2,1) 185 | 186 | detailLayout.addWidget(serialParity,3,0) 187 | detailLayout.addWidget(self.parityComboBox,3,1) 188 | 189 | detailLayout.addItem(QSpacerItem(200,200),4,0) 190 | self.setLayout(detailLayout) 191 | 192 | self.ser=serial.Serial() 193 | def Port_List(self): 194 | Com_List=[] 195 | port_list = list(serial.tools.list_ports.comports()) 196 | for port in port_list: 197 | Com_List.append(port[0]) 198 | return Com_List 199 | def comChooseOk(self,com): 200 | self.ser.port=com 201 | self.ser.baudrate = self.baundComboBox.currentText() 202 | self.ser.bytesize = int(self.bytesizeComboBox.currentText()) 203 | 204 | ParityValue = self.parityComboBox.currentText() 205 | self.ser.parity = ParityValue[0] 206 | self.ser.stopbits = int(self.stopbitsComboBox.currentText()) 207 | self.ser.timeout=0.001 208 | self.ser.flow="N" 209 | self.ser.open() 210 | 211 | class LanLocWidget(QWidget): 212 | def __init__(self,parent=None): 213 | super(LanLocWidget,self).__init__(parent) 214 | 215 | languageLabel=QLabel(self.tr("Language")) 216 | self.languageComBox=QComboBox() 217 | self.languageComBox.addItems(['English']) 218 | self.languageComBox.setCurrentIndex(0) 219 | 220 | locationLabel=QLabel(self.tr("Location")) 221 | self.locationComboBox=QComboBox() 222 | self.locationComboBox.addItems(['China Mainland','Others']) 223 | self.locationComboBox.setCurrentIndex(0) 224 | 225 | self.detailWidget=QWidget() 226 | detailLayout=QGridLayout(self.detailWidget) 227 | detailLayout.addWidget(languageLabel,0,0) 228 | detailLayout.addWidget(self.languageComBox,0,1) 229 | detailLayout.addWidget(locationLabel,1,0) 230 | detailLayout.addWidget(self.locationComboBox,1,1) 231 | detailLayout.addItem(QSpacerItem(200,200),2,0) 232 | self.setLayout(detailLayout) 233 | 234 | class updateConfig(QWidget): 235 | def __init__(self,parent=None): 236 | super(updateConfig,self).__init__(parent) 237 | 238 | checkFirmware=QLabel(self.tr("CheckFirmware")) 239 | self.checkBinComBox=QComboBox() 240 | self.checkBinComBox.addItems(['check update','no check']) 241 | self.checkBinComBox.setCurrentIndex(0) 242 | 243 | self.detailWidget=QWidget() 244 | detailLayout=QGridLayout(self.detailWidget) 245 | detailLayout.addWidget(checkFirmware,0,0) 246 | detailLayout.addWidget(self.checkBinComBox,0,1) 247 | 248 | detailLayout.addItem(QSpacerItem(200,200),1,0) 249 | self.setLayout(detailLayout) 250 | 251 | class Preferences(QDialog): 252 | def __init__(self,parent=None): 253 | super(Preferences,self).__init__(parent) 254 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 255 | self.setStyleSheet("""QDialog{background-color: rgb(236, 236, 236);color:black;} 256 | """) 257 | self.widget=QWidget() 258 | layout=QGridLayout(self.widget) 259 | 260 | self.landlocation=LanLocWidget(self) 261 | self.configUpdate=updateConfig() 262 | 263 | tabWidget=QTabWidget() 264 | tabWidget.setTabPosition(QTabWidget.North); 265 | tabWidget.addTab(self.configUpdate,"config") 266 | tabWidget.addTab(self.landlocation,"Languare Location") 267 | tabWidget.addTab(SerialWidget(self),"Serial") 268 | 269 | layout.addWidget(tabWidget,1,0) 270 | self.setLayout(layout) 271 | self.resize(300,200) 272 | self.setWindowTitle("Preferences") 273 | self.setWindowIcon(QIcon(':/logo.png')) 274 | -------------------------------------------------------------------------------- /images/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/clear.png -------------------------------------------------------------------------------- /images/downloadandrun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/downloadandrun.png -------------------------------------------------------------------------------- /images/fileopen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/fileopen.png -------------------------------------------------------------------------------- /images/ic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/ic.png -------------------------------------------------------------------------------- /images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/logo.ico -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/logo.png -------------------------------------------------------------------------------- /images/newfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/newfile.png -------------------------------------------------------------------------------- /images/pc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/pc.png -------------------------------------------------------------------------------- /images/redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/redo.png -------------------------------------------------------------------------------- /images/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/save.png -------------------------------------------------------------------------------- /images/serialClose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/serialClose.png -------------------------------------------------------------------------------- /images/serialConnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/serialConnect.png -------------------------------------------------------------------------------- /images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/stop.png -------------------------------------------------------------------------------- /images/syntaxCheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/syntaxCheck.png -------------------------------------------------------------------------------- /images/tabClose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/tabClose.png -------------------------------------------------------------------------------- /images/tabCloseHover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/tabCloseHover.png -------------------------------------------------------------------------------- /images/treeBranchClose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/treeBranchClose.png -------------------------------------------------------------------------------- /images/treeBranchOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/treeBranchOpen.png -------------------------------------------------------------------------------- /images/treeFileOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/treeFileOpen.png -------------------------------------------------------------------------------- /images/treeMenuClosed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/treeMenuClosed.png -------------------------------------------------------------------------------- /images/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/uPyCraft_src/68dfc449ee1af7f4bdb0ba8a9a127ec890935d3b/images/undo.png -------------------------------------------------------------------------------- /mainComponents.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import shutil 4 | import time 5 | 6 | from PyQt4.QtGui import * 7 | from PyQt4.QtCore import * 8 | from PyQt4.Qsci import QsciScintilla, QsciScintillaBase, QsciLexerPython 9 | 10 | 11 | rootDirectoryPath =os.path.expanduser("~") 12 | rootDirectoryPath =rootDirectoryPath.replace("\\","/") 13 | currentExamplesPath="%s/AppData/Local/uPyCraft/examples"%rootDirectoryPath 14 | 15 | class myTerminal(QTextEdit): 16 | def __init__(self,queue,parent): 17 | super(myTerminal,self).__init__(parent) 18 | self.eventFilterEnable=False 19 | self.setStyleSheet("""QTextEdit{background-color: qlineargradient(x1: 0, x2: 1, stop: 0 #262D34, stop: 1 #222529); 20 | border-style:none; 21 | color:white;} 22 | QScrollBar:vertical{background-color:rgb(94,98,102); 23 | border:0px; 24 | width: 15px; 25 | margin:0px 0px 0px 0px; 26 | } 27 | QScrollBar::add-page:vertical{background-color:rgb(61,62,64); 28 | width: 15px; 29 | margin:0px 0px 0px 0px; 30 | } 31 | QScrollBar::sub-page:vertical{background-color:rgb(61,62,64); 32 | width: 15px; 33 | margin:0px 0px 0px 0px; 34 | } 35 | """) 36 | #self.setReadOnly(False) 37 | self.installEventFilter(self) 38 | self.setTextInteractionFlags(Qt.TextSelectableByMouse) 39 | 40 | p=QPalette() 41 | p.setColor(QPalette.Inactive,QPalette.Highlight,QColor(102,184,255)) 42 | self.setPalette(p) 43 | 44 | self.setAcceptDrops(False) 45 | 46 | self.terminalRightMenu=None 47 | self.createTerminalRightMenu() 48 | 49 | self.ui=parent 50 | self.queue=queue 51 | self.currentBoard="esp32" 52 | self.connect(self.ui,SIGNAL("changeCurrentBoard"),self.changeBoard) 53 | self.connect(self.ui,SIGNAL("initRecvdata"),self.initRecvdata) 54 | self.connect(self.ui,SIGNAL("initMessycode"),self.initMessycode) 55 | 56 | self.keyPressMsg="" 57 | self.recvdata="" 58 | self.messycode=b'' 59 | self.isChinese=0 60 | 61 | self.cursor=None 62 | self.startPosition=0 63 | 64 | self.terminalSelect=False 65 | 66 | def createTerminalRightMenu(self): 67 | self.setContextMenuPolicy(Qt.CustomContextMenu) 68 | self.connect(self,SIGNAL("customContextMenuRequested(const QPoint&)"),self.slotTerminalRightClickMenu) 69 | self.terminalRightMenu=QMenu(self) 70 | self.terminalRightMenu.setStyleSheet( 71 | """QMenu{background-color:rgb(67,67,67); 72 | color:white;} 73 | QMenu::item{padding:4px 16px;} 74 | QMenu::item::selected{background-color:rgb(124,124,124);}""" 75 | ) 76 | 77 | terminalCopy=QAction(QIcon(":/copy.png"),self.tr("copy"),self) 78 | self.connect(terminalCopy,SIGNAL("triggered()"),self.slotCopy) 79 | 80 | terminalPaste=QAction(QIcon(":/copy.png"),self.tr("paste"),self) 81 | self.connect(terminalPaste,SIGNAL("triggered()"),self.slotPaste) 82 | 83 | self.terminalRightMenu.addAction(terminalCopy) 84 | self.terminalRightMenu.addAction(terminalPaste) 85 | def slotTerminalRightClickMenu(self,point): 86 | self.terminalRightMenu.exec_(self.mapToGlobal(point)) 87 | 88 | def slotCopy(self): 89 | self.copy() 90 | self.ui.cutCopyPasteMsg = QApplication.clipboard().setText(QApplication.clipboard().text()) 91 | self.terminalSelect=False 92 | 93 | def slotPaste(self): 94 | if not self.ui.myserial.ser.isOpen(): 95 | return 96 | self.keyPressMsg="" 97 | for i in str(QApplication.clipboard().text()): 98 | if i=="\x0a": 99 | i="\x0d\x0a" 100 | self.ui.readwriteQueue.put("uitouart:::%s"%i) 101 | 102 | 103 | def setEventFilterEnable(self,enable): 104 | self.eventFilterEnable=enable 105 | 106 | def eventFilter(self,watch,event): 107 | if not self.eventFilterEnable: 108 | return QMainWindow.eventFilter(self,watch,event) 109 | if event.type()==QEvent.KeyPress: 110 | #print ("event.text:%s"%(event.text())) 111 | #print ("evevt.type:%d"%event.type()) 112 | #print (event.key()) 113 | self.keyPress(event) 114 | return True 115 | elif event.type()==QEvent.InputMethod: 116 | print ("event.text0") 117 | e=QInputMethodEvent(event) 118 | print(e.commitString()) 119 | self.queue.put("uitouart:::%s"%e.commitString()) 120 | return True 121 | else: 122 | return QMainWindow.eventFilter(self,watch,event) 123 | 124 | def changeBoard(self,board): 125 | #print("changeBoard") 126 | self.currentBoard=board 127 | 128 | def initRecvdata(self): 129 | print("initRecvdata") 130 | self.recvdata="" 131 | def initMessycode(self): 132 | print("initMessycode") 133 | self.messycode=b"" 134 | 135 | def keyPress(self,event): 136 | print("keypress") 137 | if self.terminalSelect: 138 | self.terminalSelect=False 139 | self.setTextCursor(self.ui.cursor) 140 | 141 | self.messycode=b'' 142 | if event.key()==Qt.Key_Backspace: 143 | self.keyPressMsg="\x08" 144 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 145 | elif event.key()==Qt.Key_Left: 146 | self.keyPressMsg='\x1b\x5b\x44' 147 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 148 | elif event.key()==Qt.Key_Right: 149 | self.keyPressMsg='\x1b\x5b\x43' 150 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 151 | elif event.key()==Qt.Key_Delete: 152 | self.keyPressMsg="\x1b\x5b\x33\x7e" 153 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 154 | elif event.key()==Qt.Key_Up: 155 | self.keyPressMsg="\x1b\x5b\x41" 156 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 157 | elif event.key()==Qt.Key_Down: 158 | self.keyPressMsg="\x1b\x5b\x42" 159 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 160 | elif event.key()==Qt.Key_Tab: 161 | self.keyPressMsg="\x09" 162 | self.queue.put("uitouart:::%s"%self.keyPressMsg) 163 | elif event.text()=="": 164 | self.keyPressMsg="else" 165 | return 166 | else: 167 | self.keyPressMsg="else" 168 | if event.key()==Qt.Key_Return or event.key()==Qt.Key_Enter: 169 | self.ui.cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor) 170 | self.moveCursor(QTextCursor.End) 171 | self.queue.put("uitouart:::%s"%str(event.text())) 172 | 173 | def uiRecvFromUart(self,data): 174 | if data=="" or data==b'': 175 | return 176 | 177 | if (type(data) is bytes) and (str(data).find("b'\\xe")>=0): 178 | self.keyPressMsg="else" 179 | self.messycode=b'' 180 | self.isChinese=1 181 | if self.isChinese==1: 182 | if type(data) is bytes: 183 | try: 184 | self.messycode+=data 185 | except: 186 | self.messycode+=data.decode("utf-8") 187 | 188 | if len(self.messycode)<3: 189 | return 190 | else: 191 | try: 192 | self.insertPlainText(self.messycode.decode("utf-8")) 193 | except Exception as e: 194 | print(e) 195 | self.isChinese=0 196 | return 197 | else: 198 | self.isChinese=0 199 | self.messycode=b'' 200 | 201 | if self.keyPressMsg=="\x08" and self.ui.cursor.atEnd()==True:#Backspace 202 | mycursor=self.textCursor() 203 | self.recvdata+=data 204 | if self.currentBoard=="microbit": 205 | if self.recvdata=="\x08\x20\x08": 206 | mycursor.deletePreviousChar() 207 | self.recvdata="" 208 | elif self.recvdata=="\x08\x08\x08\x08\x20\x20\x20\x20\x08\x08\x08\x08": 209 | for i in range(0,4): 210 | mycursor.deletePreviousChar() 211 | self.recvdata="" 212 | else: 213 | if self.recvdata.find("\x08\x1b\x5b\x4b")==0: 214 | mycursor.deletePreviousChar() 215 | self.recvdata="" 216 | elif self.recvdata.find("\x08\x1b\x5b\x4b")>0: 217 | for i in range(self.recvdata.find("\x08\x1b\x5b\x4b")+1): 218 | if self.recvdata[i]=="\x08": 219 | mycursor.deletePreviousChar() 220 | self.recvdata="" 221 | elif self.keyPressMsg=="\x08" and not self.ui.cursor.atEnd():#Backspace 222 | mycursor=self.textCursor() 223 | self.recvdata+=data 224 | if self.currentBoard=="microbit": 225 | if len(self.recvdata)>5: 226 | if self.recvdata[-2:]=="\x08\x08": 227 | pass 228 | elif self.recvdata[-1]=="\x08" and self.recvdata[-2]!="\x20": 229 | for i in range(self.recvdata.find("\x20")): 230 | mycursor.deletePreviousChar() 231 | self.recvdata="" 232 | self.keyPressMsg="else" 233 | else: 234 | pass 235 | else: 236 | pass 237 | else: 238 | if self.recvdata.find("\x1b\x5b")>0 and self.recvdata[-1]=="\x08": 239 | for i in range(self.recvdata.find("\x1b\x5b")): 240 | if self.recvdata[i]=="\x08": 241 | mycursor.deletePreviousChar() 242 | self.recvdata="" 243 | self.keyPressMsg="else" 244 | elif self.recvdata.count("\x1b\x5b")==2 and self.recvdata[-1]=="\x44": 245 | for i in range(self.recvdata.find("\x1b\x5b")): 246 | if self.recvdata[i]=="\x08": 247 | mycursor.deletePreviousChar() 248 | self.recvdata="" 249 | #else: 250 | # print("9999") 251 | elif self.keyPressMsg=="\x09" and not self.ui.cursor.atEnd():#debug 252 | self.recvdata+=data 253 | if self.recvdata=="\x08": 254 | lastLineCursorNum=self.ui.cursor.columnNumber() 255 | allMsg=self.toPlainText() 256 | showMsg="" 257 | movecursorNum=0 258 | allMsg=allMsg.split("\n") 259 | for i in allMsg: 260 | if i==allMsg[-1]: 261 | showMsg+=i[0:-1] 262 | movecursorNum=len(i[lastLineCursorNum:]) 263 | else: 264 | showMsg+=i+"\n" 265 | self.setPlainText(showMsg) 266 | 267 | self.ui.cursorLeftOrRight-=movecursorNum 268 | self.ui.cursor=self.textCursor() 269 | self.moveCursor(QTextCursor.Left,QTextCursor.MoveAnchor) 270 | self.recvdata="" 271 | elif self.recvdata[0]=="\x1b": 272 | if self.recvdata[-1]=="\x44": 273 | movecursorNum=int(self.recvdata[self.recvdata.find("\x1b")+2:-1]) 274 | lastLineCursorNum=self.ui.cursor.columnNumber() 275 | allMsg=self.toPlainText() 276 | showMsg="" 277 | allMsg=allMsg.split("\n") 278 | for i in allMsg: 279 | if i==allMsg[-1]: 280 | showMsg+=i[0:lastLineCursorNum] 281 | else: 282 | showMsg+=i+"\n" 283 | self.setPlainText(showMsg) 284 | self.keyPressMsg="else" 285 | self.recvdata="" 286 | 287 | self.ui.cursorLeftOrRight-=movecursorNum 288 | self.ui.cursor=self.textCursor() 289 | self.moveCursor(QTextCursor.Left,QTextCursor.MoveAnchor) 290 | else: 291 | self.ui.cursor.insertText(self.recvdata) 292 | self.recvdata="" 293 | elif self.keyPressMsg=="\x1b\x5b\x33\x7e" and not self.ui.cursor.atEnd():#Delete 294 | self.recvdata+=data 295 | allMsg=self.toPlainText() 296 | allMsg=allMsg.split("\n") 297 | showMsg="" 298 | lastLineCursorNum=self.ui.cursor.columnNumber() 299 | 300 | if self.currentBoard=="microbit": 301 | if (len(allMsg[-1])-lastLineCursorNum==1) and self.recvdata=="\x20\x08": 302 | self.ui.cursor.deleteChar() 303 | self.keyPressMsg="else" 304 | self.recvdata="" 305 | else: 306 | if self.recvdata[-2:]=="\x08\x08": 307 | pass 308 | elif self.recvdata[-1]=="\x08" and self.recvdata[-2]!="\x20": 309 | self.ui.cursor.deleteChar() 310 | self.keyPressMsg="else" 311 | self.recvdata="" 312 | else: 313 | pass 314 | else: 315 | if self.recvdata=="\x1b\x5b\x4b" and (len(allMsg[-1])-lastLineCursorNum==1): 316 | self.ui.cursor.deleteChar() 317 | self.keyPressMsg="else" 318 | self.recvdata="" 319 | elif len(self.recvdata)>3 and self.recvdata[-1]=="\x08":#这里,不应该让keypressmsg=else 320 | self.ui.cursor.deleteChar() 321 | self.keyPressMsg="else" 322 | self.recvdata="" 323 | elif len(self.recvdata)>3 and self.recvdata[3:].find("\x1b\x5b")>0 and self.recvdata[-1]=="\x44": 324 | self.ui.cursor.deleteChar() 325 | self.keyPressMsg="else" 326 | self.recvdata="" 327 | elif self.recvdata=="\x08": 328 | self.recvdata="" 329 | else: 330 | pass 331 | elif self.keyPressMsg=="\x1b\x5b\x44":#Key_Left 332 | if data=="\x08": 333 | self.ui.cursorLeftOrRight-=1 334 | self.ui.cursor=self.textCursor() 335 | self.moveCursor(QTextCursor.Left,QTextCursor.MoveAnchor) 336 | elif self.keyPressMsg=="\x1b\x5b\x43":#Key_Right 337 | self.ui.cursorLeftOrRight+=1 338 | self.ui.cursor=self.textCursor() 339 | self.moveCursor(QTextCursor.Right, QTextCursor.MoveAnchor) 340 | elif self.keyPressMsg=="\x1b\x5b\x41":#Key_Up 341 | if data == "\x08": 342 | myBottomMsg=self.toPlainText() 343 | msgNum=self.document().lineCount() 344 | plainMsg="" 345 | mySplite=myBottomMsg.split("\n") 346 | for mysplite in mySplite: 347 | msgNum-=1 348 | if msgNum != 0: 349 | plainMsg+=mysplite+"\n" 350 | plainMsg+=">>> " 351 | self.setPlainText(plainMsg) 352 | elif data == "\x1b" or self.recvdata.find("\x1b")>=0: 353 | self.recvdata+=data 354 | if self.recvdata.find("[K")>=0: 355 | self.recvdata="" 356 | myBottomMsg=self.toPlainText() 357 | msgNum=self.document().lineCount() 358 | plainMsg="" 359 | mySplite=myBottomMsg.split("\n") 360 | for mysplite in mySplite: 361 | msgNum-=1 362 | if msgNum != 0: 363 | plainMsg+=mysplite+"\n" 364 | plainMsg+=">>> " 365 | self.setPlainText(plainMsg) 366 | elif self.recvdata.find("D")>=0: 367 | self.recvdata="" 368 | myBottomMsg=self.toPlainText() 369 | msgNum=self.document().lineCount() 370 | plainMsg="" 371 | mySplite=myBottomMsg.split("\n") 372 | for mysplite in mySplite: 373 | msgNum-=1 374 | if msgNum != 0: 375 | plainMsg+=mysplite+"\n" 376 | plainMsg+=">>> " 377 | self.setPlainText(plainMsg) 378 | else: 379 | self.ui.cursor.insertText(data) 380 | elif self.keyPressMsg=="\x1b\x5b\x42":#Key_Down 381 | if data == "\x08": 382 | myBottomMsg=self.toPlainText() 383 | msgNum=self.document().lineCount() 384 | plainMsg="" 385 | mySplite=myBottomMsg.split("\n") 386 | for mysplite in mySplite: 387 | msgNum-=1 388 | if msgNum != 0: 389 | plainMsg+=mysplite+"\n" 390 | plainMsg+=">>> " 391 | self.setPlainText(plainMsg) 392 | elif data == "\x1b" or self.recvdata.find("\x1b")>=0: 393 | self.recvdata+=data 394 | if self.recvdata.find("D")>=0: 395 | self.recvdata="" 396 | myBottomMsg=self.toPlainText() 397 | msgNum=self.document().lineCount() 398 | plainMsg="" 399 | mySplite=myBottomMsg.split("\n") 400 | for mysplite in mySplite: 401 | msgNum-=1 402 | if msgNum != 0: 403 | plainMsg+=mysplite+"\n" 404 | plainMsg+=">>> " 405 | self.setPlainText(plainMsg) 406 | elif self.recvdata.find("[K")>=0: 407 | self.recvdata="" 408 | myBottomMsg=self.toPlainText() 409 | msgNum=self.document().lineCount() 410 | plainMsg="" 411 | mySplite=myBottomMsg.split("\n") 412 | for mysplite in mySplite: 413 | msgNum-=1 414 | if msgNum != 0: 415 | plainMsg+=mysplite+"\n" 416 | plainMsg+=">>> " 417 | self.setPlainText(plainMsg) 418 | else: 419 | self.ui.cursor.insertText(data) 420 | else: 421 | if not self.ui.cursor.atEnd(): 422 | self.recvdata+=data 423 | if self.recvdata.find("\x08")>=0 and len(self.recvdata)>1 and self.recvdata[1:].find("\x08")>=0: 424 | if self.messycode!=b'': 425 | self.recvdata='' 426 | self.messycode=b'' 427 | return 428 | self.recvdata=self.recvdata[0] 429 | self.ui.cursor.insertText(self.recvdata) 430 | self.recvdata="" 431 | elif self.recvdata=="\x08": 432 | self.recvdata="" 433 | elif self.recvdata.find("[")>0 and self.recvdata[-1]=="\x44": 434 | if self.messycode!=b'': 435 | self.recvdata='' 436 | self.messycode=b'' 437 | return 438 | self.recvdata=self.recvdata[0] 439 | self.ui.cursor.insertText(self.recvdata) 440 | self.recvdata="" 441 | elif self.recvdata=="\x1b\x5b\x4b": 442 | self.keyPressMsg="\x1b\x5b\x33\x7e" 443 | else: 444 | if data=="\n": 445 | data="" 446 | try: 447 | self.insertPlainText(data) 448 | except: 449 | print('recv unexpected word.') 450 | 451 | def mousePressEvent(self,event): 452 | if event.button()==Qt.LeftButton: 453 | self.startCursorPosition =event.pos() 454 | self.cursor = self.cursorForPosition(self.startCursorPosition) 455 | self.startPosition = self.cursor.position() 456 | self.emit(SIGNAL("setCursor")) 457 | 458 | def mouseMoveEvent(self,event): 459 | if event.button()==Qt.NoButton: 460 | self.terminalSelect=True 461 | self.endCursorPosition = event.pos() 462 | self.cursor = self.cursorForPosition(self.endCursorPosition) 463 | position = self.cursor.position() 464 | self.cursor.setPosition(self.startPosition) 465 | self.cursor.setPosition(position, QTextCursor.KeepAnchor) 466 | self.setTextCursor(self.cursor) 467 | self.cursor.select(QTextCursor.WordUnderCursor) 468 | 469 | def mouseReleaseEvent(self,event): 470 | if event.button()==Qt.LeftButton: 471 | pass 472 | 473 | 474 | 475 | class myTreeView(QTreeView): 476 | def __init__(self,parent): 477 | super(myTreeView,self).__init__(parent) 478 | self.ui=parent 479 | 480 | self.setHeaderHidden(True) 481 | self.setStyleSheet(""" 482 | QTreeView{ 483 | background-color: qlineargradient(y1: 0, y2: 1,stop: 0 #0D0B0B, stop: 1 #5D5C5C); 484 | border-width:1px; 485 | border-color:#888888; 486 | border-style:solid; 487 | color:white; 488 | } 489 | 490 | QTreeView::branch:closed:has-children { 491 | border-image: none; 492 | image: url(':/treeBranchOpen.png'); 493 | } 494 | 495 | QTreeView::branch:open:has-children { 496 | border-image: none; 497 | image: url(':/treeBranchClose.png'); 498 | }""") 499 | 500 | 501 | self.setEditTriggers(QAbstractItemView.NoEditTriggers) 502 | 503 | self.setAcceptDrops(True) 504 | self.setDragDropMode(QAbstractItemView.DragDrop) 505 | 506 | self.filename="" 507 | self.dragFrom="" 508 | self.dropDir="" 509 | #self.connect(self,SIGNAL("clicked(QModelIndex)"),self.chooseFile) 510 | self.connect(self,SIGNAL("pressed(QModelIndex)"),self.treepressed) 511 | 512 | def setmodel(self,model): 513 | self.setModel(model) 514 | 515 | #def mousePressEvent(self,event): 516 | # if event.button()==Qt.LeftButton: 517 | # print("left") 518 | # elif event.button()==Qt.RightButton: 519 | # print("right") 520 | # else: 521 | # print("else") 522 | # return QMainWindow.eventFilter(self,event) 523 | def createRightMenu(self): 524 | self.setContextMenuPolicy(Qt.CustomContextMenu) 525 | 526 | self.runFile=QAction(self.tr("Run"),self) 527 | self.connect(self.runFile,SIGNAL("triggered()"),self.rightMenuRunFile) 528 | 529 | self.openFile=QAction(self.tr("Open"),self) 530 | self.connect(self.openFile,SIGNAL("triggered()"),self.rightMenuOpenFile) 531 | 532 | self.closeFile=QAction(self.tr("Close"),self) 533 | self.connect(self.closeFile,SIGNAL("triggered()"),self.rightMenuCloseFile) 534 | 535 | self.deleteFile=QAction(self.tr("Delete"),self) 536 | self.connect(self.deleteFile,SIGNAL("triggered()"),self.rightMenuDeleteFile) 537 | 538 | self.defaultProgram=QAction(self.tr("Default Run"),self) 539 | self.connect(self.defaultProgram,SIGNAL("triggered()"),self.rightMenuDefaultProgram) 540 | 541 | self.rename=QAction(self.tr("Rename"),self) 542 | self.connect(self.rename,SIGNAL("triggered()"),self.rightMenuRename) 543 | 544 | self.newDir=QAction(self.tr("New Dir"),self) 545 | self.connect(self.newDir,SIGNAL("triggered()"),self.rightMenuNewDir) 546 | 547 | self.rightClickMenu=QMenu(self) 548 | self.rightClickMenu.setStyleSheet( 549 | """QMenu{background-color:rgb(67,67,67); 550 | color:white;} 551 | QMenu::item{padding:4px 16px;} 552 | QMenu::item::selected{background-color:rgb(127,127,127);}""" 553 | ) 554 | self.rightClickMenu.addAction(self.runFile) 555 | self.rightClickMenu.addAction(self.openFile) 556 | self.rightClickMenu.addAction(self.closeFile) 557 | self.rightClickMenu.addAction(self.deleteFile) 558 | self.rightClickMenu.addAction(self.defaultProgram) 559 | self.rightClickMenu.addAction(self.rename) 560 | self.rightClickMenu.addAction(self.newDir) 561 | 562 | self.connect(self,SIGNAL("customContextMenuRequested(const QPoint&)"),self.slotRightClickMenu) 563 | 564 | def slotRightClickMenu(self,point): 565 | self.rightClickMenu.clear() 566 | if (self.ui.fileName=="." or self.ui.fileName=="/flash") and self.ui.myserial.ser.isOpen(): 567 | self.rightClickMenu.addAction(self.newDir) 568 | elif (self.ui.fileName=="." or self.ui.fileName=="/flash") and not self.ui.myserial.ser.isOpen(): 569 | pass 570 | elif self.ui.fileName=="/sd" or \ 571 | (((sys.platform=="linux" and self.ui.fileName.find(rootDirectoryPath)>=0) or (sys.platform=="win32" and self.ui.fileName.find(":")>=0) or (sys.platform=="darwin" and self.ui.fileName.find(rootDirectoryPath)>=0)) and self.ui.fileName.split("/")[-1]=="uPy_lib"): 572 | pass 573 | elif ((sys.platform=="linux" and self.ui.fileName.find(rootDirectoryPath)>=0) or (sys.platform=="win32" and self.ui.fileName.find(":")>=0) or (sys.platform=="darwin" and self.ui.fileName.find(rootDirectoryPath)>=0)) and self.ui.fileName.find("uPy_lib")>0: 574 | self.rightClickMenu.addAction(self.openFile) 575 | self.rightClickMenu.addAction(self.closeFile) 576 | elif ((sys.platform=="linux" and self.ui.fileName.find(rootDirectoryPath)>=0) or (sys.platform=="win32" and self.ui.fileName.find(":")>=0) or (sys.platform=="darwin" and self.ui.fileName.find(rootDirectoryPath)>=0)) and self.ui.fileName.split("/")[-1]=="workSpace": 577 | self.rightClickMenu.addAction(self.openFile) 578 | elif ((sys.platform=="linux" and self.ui.fileName.find(rootDirectoryPath)>=0) or (sys.platform=="win32" and self.ui.fileName.find(":")>=0) or (sys.platform=="darwin" and self.ui.fileName.find(rootDirectoryPath)>=0)) and self.ui.fileName.find("workSpace")>0: 579 | self.rightClickMenu.addAction(self.openFile) 580 | self.rightClickMenu.addAction(self.closeFile) 581 | self.rightClickMenu.addAction(self.deleteFile) 582 | else: 583 | self.rightClickMenu.addAction(self.runFile) 584 | self.rightClickMenu.addAction(self.openFile) 585 | self.rightClickMenu.addAction(self.closeFile) 586 | self.rightClickMenu.addAction(self.deleteFile) 587 | self.rightClickMenu.addAction(self.defaultProgram) 588 | self.rightClickMenu.addAction(self.rename) 589 | self.rightClickMenu.addAction(self.newDir) 590 | 591 | self.rightClickMenu.exec_(self.mapToGlobal(point)) 592 | 593 | def rightMenuRunFile(self): 594 | self.ui.treeRightMenuRunFile() 595 | 596 | def rightMenuOpenFile(self): 597 | self.ui.treeRightMenuOpenFile() 598 | 599 | def rightMenuCloseFile(self): 600 | self.ui.treeRightMenuCloseFile() 601 | 602 | def rightMenuDeleteFile(self): 603 | self.ui.treeRightMenuDeleteFile() 604 | 605 | def rightMenuDefaultProgram(self): 606 | self.ui.treeRightMenuDefaultProgram() 607 | 608 | def rightMenuRename(self): 609 | self.ui.treeRightMenuRename() 610 | 611 | def rightMenuNewDir(self): 612 | self.ui.treeRightMenuNewDir() 613 | 614 | 615 | def getQmodelIndexParent(self,index): 616 | if index.data() != None: 617 | self.ui.fileName="/"+str(index.data())+self.ui.fileName 618 | self.getQmodelIndexParent(index.parent()) 619 | else: 620 | return 621 | 622 | def chooseFile(self,index): 623 | self.ui.fileName="" 624 | self.getQmodelIndexParent(index) 625 | print("--4--%s"%self.ui.fileName) 626 | dirList=self.ui.fileName.split("/") 627 | 628 | if dirList[1]=="device": 629 | self.ui.fileName=self.ui.fileName[7:] 630 | self.ui.fileName=self.ui.rootDir+self.ui.fileName 631 | elif dirList[1]=="sd": 632 | pass 633 | elif dirList[1]=="uPy_lib": 634 | self.ui.fileName="%s/AppData/Local/uPyCraft/examples"%rootDirectoryPath+self.ui.fileName 635 | elif dirList[1]=="workSpace": 636 | if self.ui.createWorkSpacePath(): 637 | self.ui.fileName=self.ui.workspacePath[0:-10]+self.ui.fileName 638 | self.ui.fileName=self.ui.fileName.replace("\\","/") 639 | self.ui.fileName=self.ui.fileName.replace("//","/") 640 | else: 641 | self.ui.fileName="" 642 | else: 643 | pass 644 | 645 | print("--5--%s"%self.ui.fileName) 646 | 647 | def treepressed(self,index): 648 | self.chooseFile(index) 649 | self.dropDir="" 650 | self.getDropDir(index) 651 | 652 | def dragEnterEvent(self,event): 653 | if event.mimeData().hasFormat("text/uri-list")==True:#External drag 654 | self.dragFrom="External" 655 | event.acceptProposedAction() 656 | elif event.mimeData().hasFormat("application/x-qabstractitemmodeldatalist")==True:#Internal drag 657 | self.dragFrom="Internal" 658 | event.acceptProposedAction() 659 | else: 660 | self.dragFrom="" 661 | event.ignore() 662 | def dragMoveEvent(self,event): 663 | pass 664 | def dragLeaveEvent(self,event): 665 | pass 666 | def dropEvent(self,event): 667 | if event.mimeData().hasUrls: 668 | urls=event.mimeData().urls() 669 | dropDownFileName="" 670 | for url in urls: 671 | dropDownFileName=url.toLocalFile() 672 | 673 | index=self.indexAt(self.mapFrom(self,event.pos())) 674 | 675 | if self.dragFrom=="External": 676 | self.dropDir="" 677 | self.getDropDir(index) 678 | print("dropdir=%s"%self.dropDir) 679 | if self.dropDir=="": 680 | self.ui.terminal.append("drop to this place is not support") 681 | return 682 | 683 | filename="" 684 | dorpdownfilename="" 685 | dirList=self.dropDir.split("/") 686 | if dirList[1]=="device" and str(dirList[-1]).find(".")<0: 687 | self.dropDir=self.dropDir[7:] 688 | dorpdownfilename=dropDownFileName.split("/") 689 | filename=self.ui.rootDir+self.dropDir+"/"+dorpdownfilename[-1] 690 | elif dirList[1]=="device" and str(dirList[-1]).find(".")>0: 691 | self.dropDir=self.dropDir[7:str(self.dropDir).find(dirList[-1])-1] 692 | dorpdownfilename=dropDownFileName.split("/") 693 | filename=self.ui.rootDir+self.dropDir+"/"+dorpdownfilename[-1] 694 | elif dirList[1]=="workSpace" and str(dirList[-1]).find(".")<0: 695 | shutil.copyfile(dropDownFileName,self.ui.workspacePath[0:-10]+self.dropDir+"/"+dropDownFileName.split("/")[-1]) 696 | self.ui.createWorkSpaceMenu() 697 | return 698 | elif dirList[1]=="workSpace" and str(dirList[-1]).find(".")>0: 699 | newPath=self.ui.workspacePath[0:-10] 700 | for i in self.dropDir.split("/"): 701 | if i=="": 702 | pass 703 | elif i==self.dropDir.split("/")[-1]: 704 | break 705 | else: 706 | newPath=newPath+"/"+i 707 | newPath=newPath+"/"+dropDownFileName.split("/")[-1] 708 | shutil.copyfile(dropDownFileName,newPath) 709 | self.ui.createWorkSpaceMenu() 710 | return 711 | else: 712 | self.ui.terminal.append("drop to this place is not support") 713 | return 714 | 715 | if not self.ui.myserial.ser.isOpen(): 716 | self.ui.terminal.append("serial not open,can not download file") 717 | return 718 | self.ui.emit(SIGNAL("changeDragDropModel"),True) 719 | self.ui.uitoctrlQueue.put("dropdownfile:::%s:::%s"%(filename,dropDownFileName)) 720 | print("filename=%s"%filename) 721 | print("dropDownFileName=%s"%dropDownFileName) 722 | 723 | elif self.dragFrom=="Internal": 724 | if not self.ui.myserial.ser.isOpen(): 725 | self.ui.terminal.append("serial not open,can not drag file") 726 | return 727 | oldDragFileName=self.dropDir 728 | print("oldDragFileName=%s"%oldDragFileName) 729 | if oldDragFileName=="/device" or oldDragFileName=="/sd" or \ 730 | oldDragFileName=="/uPy_lib" or oldDragFileName=="workSpace": 731 | self.ui.terminal.append("dir device,sd,uPy_lib can't be move.") 732 | return 733 | self.dropDir="" 734 | self.getDropDir(index) 735 | newDropFileName=self.dropDir 736 | if self.dropDir=="": 737 | self.ui.terminal.append("error place") 738 | return 739 | try: 740 | purposeFileName=str(self.dropDir).split("/")[1] 741 | except Exception: 742 | self.ui.terminal.append("drag error") 743 | return 744 | if purposeFileName=="sd" or purposeFileName=="uPy_lib" or purposeFileName=="workSpace": 745 | self.ui.terminal.append("file can't be move to sd or uPy_lib or workSpace.") 746 | return 747 | 748 | if str(oldDragFileName).find(".")<0: 749 | self.ui.terminal.append("now version only suport drag file,no suport for dir.") 750 | return 751 | 752 | dirListDrag=oldDragFileName.split("/") 753 | dirListDrop=newDropFileName.split("/") 754 | if dirListDrag[1]=="device" and str(dirListDrop[-1]).find(".")<0: 755 | if oldDragFileName[0:str(oldDragFileName).find(dirListDrag[-1])-1]==newDropFileName: 756 | self.ui.terminal.append("the same dir,not move.") 757 | return 758 | oldDragFileName=oldDragFileName[7:] 759 | oldDragFileName=self.ui.rootDir+oldDragFileName 760 | newDropFileName=newDropFileName[7:] 761 | newDropFileName=self.ui.rootDir+newDropFileName 762 | 763 | self.ui.uitoctrlQueue.put("dragChangeDir:::%s:::%s"%(oldDragFileName,newDropFileName)) 764 | elif dirListDrag[1]=="device" and str(dirListDrop[-1]).find(".")>0: 765 | if oldDragFileName[0:str(oldDragFileName).find(dirListDrag[-1])-1]\ 766 | ==newDropFileName[0:str(newDropFileName).find(dirListDrop[-1])-1]: 767 | self.ui.terminal.append("the same dir,not move.") 768 | return 769 | oldDragFileName=oldDragFileName[7:] 770 | oldDragFileName=self.ui.rootDir+oldDragFileName 771 | newDropFileName=newDropFileName[7:str(newDropFileName).find(dirListDrop[-1])-1] 772 | newDropFileName=self.ui.rootDir+newDropFileName 773 | 774 | self.ui.uitoctrlQueue.put("dragChangeDir:::%s:::%s"%(oldDragFileName,newDropFileName)) 775 | elif dirListDrag[1]=="sd": 776 | pass 777 | elif dirListDrag[1]=="uPy_lib" or dirListDrag[1]=="workSpace":#device外部拖入,需下载 778 | if dirListDrag[1]=="uPy_lib": 779 | oldDragFileName="%s/AppData/Local/uPyCraft/examples"%rootDirectoryPath+oldDragFileName 780 | elif dirListDrag[1]=="workSpace": 781 | oldDragFileName=self.ui.workspacePath[0:-10]+oldDragFileName 782 | if str(dirListDrop[-1]).find(".")<0: 783 | newDropFileName=newDropFileName[7:] 784 | newDropFileName=self.ui.rootDir+newDropFileName 785 | else: 786 | newDropFileName=newDropFileName[7:str(newDropFileName).find(dirListDrop[-1])-1] 787 | newDropFileName=self.ui.rootDir+newDropFileName 788 | self.ui.emit(SIGNAL("changeDragDropModel"),True) 789 | self.ui.uitoctrlQueue.put("dragChangeDir:::%s:::%s"%(oldDragFileName,newDropFileName)) 790 | else: 791 | pass 792 | else: 793 | pass 794 | else: 795 | event.ignore() 796 | 797 | def getDropDir(self,index): 798 | if index.data() != None: 799 | self.dropDir="/"+index.data()+self.dropDir 800 | self.getDropDir(index.parent()) 801 | else: 802 | return 803 | 804 | class myTabWidget(QTabWidget): 805 | def __init__(self,editorRightMenu,fileitem,parent): 806 | super(myTabWidget,self).__init__(parent) 807 | self.ui=parent 808 | self.setAcceptDrops(True) 809 | self.editorRightMenu=editorRightMenu 810 | self.fileitem=fileitem 811 | self.currentTab=-1 812 | 813 | self.line=0 814 | self.index=0 815 | 816 | self.connect(self, SIGNAL("tabCloseRequested(int)"),self.closeTab) 817 | self.connect(self, SIGNAL("currentChanged(int)"),self.currentTabChange) 818 | 819 | def closeTab(self,tabId): 820 | if tabId<0: 821 | return 822 | tabname = self.tabText(tabId) 823 | 824 | tabTip = self.tabToolTip(tabId) 825 | self.removeTab(tabId) 826 | 827 | if tabname=="untitled": 828 | pass 829 | else: 830 | if tabTip in self.fileitem.list: 831 | self.fileitem.list.remove(tabTip) 832 | self.fileitem.size-=1 833 | 834 | def dragEnterEvent(self,event): 835 | print("tabwidget dragenterevent1.") 836 | if event.mimeData().hasFormat("text/uri-list")==True:#External drag 837 | event.acceptProposedAction() 838 | elif event.mimeData().hasFormat("application/x-qabstractitemmodeldatalist")==True:#Internal drag 839 | event.ignore() 840 | else: 841 | event.ignore() 842 | def dragMoveEvent(self,event): 843 | event.acceptProposedAction() 844 | def dragLeaveEvent(self,event): 845 | pass 846 | def dropEvent(self,event): 847 | print("tabwidget dropevent1.") 848 | if event.mimeData().hasUrls: 849 | urls=event.mimeData().urls() 850 | dropOpenFileName="" 851 | for url in urls: 852 | dropOpenFileName=url.toLocalFile() 853 | print("dropOpenFileName=%s"%dropOpenFileName) 854 | print(type(dropOpenFileName)) 855 | if dropOpenFileName.find(".py")<0 and\ 856 | dropOpenFileName.find(".txt")<0 and\ 857 | dropOpenFileName.find(".json")<0 and\ 858 | dropOpenFileName.find(".ini")<0: 859 | print("current version can not open this file") 860 | return 861 | self.ui.pcOpenFile(dropOpenFileName) 862 | 863 | def currentTabChange(self,tabId): 864 | self.currentTab=tabId 865 | print(self.currentTab) 866 | def createNewTab(self,filename,msg,lexer): 867 | if type(msg) is bytes: 868 | msg=msg.decode(encoding='utf-8') 869 | #if str(msg).find("\r\n")>=0: 870 | # msg=msg.replace('\n','') 871 | #elif str(msg).find("\n")>=0 and str(msg).find("\r")<0: 872 | # msg=msg.replace("\n","\r") 873 | #else: 874 | # print("creatNewTab has other endswith.") 875 | msg=msg.replace("\r\n","\r") 876 | msg=msg.replace("\n","\r") 877 | 878 | #editor=QsciScintilla() 879 | editor=myQsciScintilla() 880 | editor.setUtf8(True) 881 | editor.setLexer(lexer) 882 | editor.setMarginsBackgroundColor(QColor(39,43,48))#行号背景色 883 | editor.setMarginsForegroundColor(QColor(255,255,255))#行号前景色 884 | editor.setAutoCompletionThreshold(2) 885 | editor.setAutoCompletionSource(QsciScintilla.AcsAll) 886 | editor.setEolMode(QsciScintilla.EolUnix) 887 | 888 | #显示缩进参考线 889 | editor.SendScintilla(QsciScintilla.SCI_SETINDENTATIONGUIDES,QsciScintilla.SC_IV_LOOKFORWARD) 890 | #设置匹配项的背景色 891 | editor.setMatchedBraceBackgroundColor(QColor(30,120,184)) 892 | 893 | 894 | 895 | 896 | 897 | if str(filename).find("/")>=0: 898 | tabname=filename.split("/") 899 | tabname=tabname[-1] 900 | elif str(filename)=="untitled": 901 | tabname="untitled" 902 | else: 903 | tabname=filename 904 | 905 | self.addTab(editor,tabname) 906 | self.setTabToolTip(self.count()-1,filename) 907 | 908 | if filename=="untitled": 909 | self.tabBar().setTabTextColor(self.count()-1, QColor(Qt.red)) 910 | self.setTabIcon(self.count()-1, QIcon(':/pc.png')) 911 | if self.ui.currentBoard=="microbit": 912 | msg="from microbit import *\r#write your program:\r" 913 | elif (sys.platform=="linux" and str(filename).find(rootDirectoryPath)>=0) or (sys.platform=="win32" and str(filename).find(":")>0) or (sys.platform=="darwin" and str(filename).find(rootDirectoryPath)>=0): 914 | self.tabBar().setTabTextColor(self.count()-1, QColor(Qt.red)) 915 | self.setTabIcon(self.count()-1, QIcon(':/pc.png')) 916 | else: 917 | self.tabBar().setTabTextColor(self.count()-1, QColor(Qt.blue)) 918 | self.setTabIcon(self.count()-1, QIcon(':/ic.png')) 919 | 920 | editor.setText(msg) 921 | 922 | editor.setContextMenuPolicy(Qt.CustomContextMenu) 923 | self.connect(editor,SIGNAL("customContextMenuRequested(const QPoint&)"),self.slotEditorRightClickMenu) 924 | 925 | if self.editorRightMenu==None: 926 | self.editorRightMenu=QMenu(self) 927 | self.editorRightMenu.setStyleSheet(""" 928 | QMenu{background-color:rgb(67,67,67); 929 | color:white;} 930 | QMenu::item{padding:4px 16px;} 931 | QMenu::item::selected{background-color:rgb(124,124,124);} 932 | """) 933 | 934 | undo=QAction(self.tr("Undo"),self) 935 | undo.setShortcut("Ctrl+Z") 936 | self.connect(undo,SIGNAL("triggered()"),self.slotUndo) 937 | 938 | redo=QAction(self.tr("Redo"),self) 939 | redo.setShortcut("Ctrl+Y") 940 | self.connect(redo,SIGNAL("triggered()"),self.slotRedo) 941 | 942 | cut=QAction(self.tr("Cut"),self) 943 | cut.setShortcut("Ctrl+X") 944 | self.connect(cut,SIGNAL("triggered()"),self.slotCut) 945 | 946 | copy=QAction(self.tr("Copy"),self) 947 | copy.setShortcut("Ctrl+C") 948 | self.connect(copy,SIGNAL("triggered()"),self.slotCopy) 949 | 950 | paste=QAction(self.tr("Paste"),self) 951 | paste.setShortcut("Ctrl+V") 952 | self.connect(paste,SIGNAL("triggered()"),self.slotPaste) 953 | 954 | self.editorRightMenu.addAction(undo) 955 | self.editorRightMenu.addAction(redo) 956 | self.editorRightMenu.addAction(cut) 957 | self.editorRightMenu.addAction(copy) 958 | self.editorRightMenu.addAction(paste) 959 | 960 | #set brace match 961 | editor.setBraceMatching(editor.StrictBraceMatch) 962 | 963 | #set indent replace 4 space 964 | editor.setIndentationsUseTabs(False) 965 | editor.setTabWidth(2) 966 | 967 | #The line number display area 968 | editor.setMarginType(0, QsciScintilla.NumberMargin) 969 | editor.setMarginLineNumbers(0, True) 970 | editor.setMarginWidth(0,35) 971 | 972 | #set auto indentation 973 | editor.setAutoIndent(True) 974 | 975 | #syntax check 976 | editor.setMarginType(1, QsciScintilla.SymbolMargin) 977 | editor.setMarginLineNumbers(1, False) 978 | editor.setMarginWidth(1,5) 979 | editor.setMarginSensitivity(1,False) 980 | editor.setMarginMarkerMask(1,0x1FFFFFF) 981 | editor.markerDefine(QsciScintilla.Background,1) 982 | 983 | #set cursor color 984 | editor.setCaretForegroundColor(QColor(255,255,255)) 985 | 986 | #Automatic folding area 987 | editor.setFolding(QsciScintilla.PlainFoldStyle) 988 | editor.setFoldMarginColors(QColor(39,43,48),QColor(39,43,48)) 989 | 990 | editor.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 991 | editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 992 | 993 | #set tab's stylesheet 994 | editor.setStyleSheet("""QWidget{font-size:20px;border: 0px solid white;border-radius:1px;}""") 995 | 996 | 997 | 998 | self.setCurrentWidget(editor) 999 | if filename!="untitled": 1000 | self.fileitem.size+=1 1001 | self.fileitem.list.append(filename) 1002 | 1003 | 1004 | self.connect(editor,SIGNAL("dragOpenFile"),self.dragOpenFile) 1005 | 1006 | self.connect(editor,SIGNAL("textChanged()"),self.editorTextChange) 1007 | self.connect(editor,SIGNAL("selectionChanged()"),self.selectionChanged) 1008 | self.connect(editor,SIGNAL("linesChanged()"),self.linesChanged) 1009 | self.connect(editor,SIGNAL("cursorPositionChanged(int,int)"),self.cursorPositionChanged) 1010 | self.connect(editor,SIGNAL("userListActivated(int,const QString)"),self.userListActivated) 1011 | #self.connect(editor,SIGNAL("SCN_AUTOCSELECTION(const char*,int)"),self.scn_updateui) 1012 | 1013 | def slotEditorRightClickMenu(self,point): 1014 | self.editorRightMenu.exec_(self.currentWidget().mapToGlobal(point)) 1015 | 1016 | def slotUndo(self): 1017 | if self.currentTab<0: 1018 | return 1019 | self.currentWidget().undo() 1020 | 1021 | def slotRedo(self): 1022 | if self.currentTab<0: 1023 | return 1024 | self.currentWidget().redo() 1025 | 1026 | def slotCut(self): 1027 | if self.currentTab<0: 1028 | return 1029 | elif not self.currentWidget().hasSelectedText(): 1030 | print("cut no msg selected") 1031 | return 1032 | else: 1033 | self.ui.clipboard.setText(self.currentWidget().selectedText()) 1034 | self.currentWidget().removeSelectedText() 1035 | 1036 | def slotCopy(self): 1037 | if self.currentTab<0: 1038 | return 1039 | if not self.currentWidget().hasSelectedText(): 1040 | print("copy no msg selected") 1041 | self.ui.cutCopyPasteMsg = self.currentWidget().selectedText() 1042 | self.ui.clipboard.setText(self.ui.cutCopyPasteMsg) 1043 | 1044 | def slotPaste(self): 1045 | if self.currentTab<0: 1046 | return 1047 | else: 1048 | self.currentWidget().insertAt(self.ui.clipboard.text(),self.line,self.index) 1049 | 1050 | def editorTextChange(self): 1051 | tabname=self.tabText(self.currentTab) 1052 | if tabname=="untitled": 1053 | return 1054 | elif tabname[0] == "*": 1055 | return 1056 | else: 1057 | if str(self.tabToolTip(self.currentTab)).find(currentExamplesPath)<0: 1058 | tabname = "*" + tabname 1059 | self.setTabText(self.currentTab,tabname) 1060 | 1061 | def selectionChanged(self): 1062 | pass 1063 | 1064 | def linesChanged(self):#linesChanged is before cursorPositionChanged 1065 | #such as import math,should be:write(dir(math)),then read return and into 1066 | #functionList 1067 | return 1068 | 1069 | lastlinetext= str(self.tabWidget.currentWidget().text(self.editorLine)) 1070 | 1071 | if self.myserial.ser.isOpen()==False: 1072 | return 1073 | 1074 | return 1075 | #self.IntoFun(lastlinetext) 1076 | 1077 | def cursorPositionChanged(self,line,index): 1078 | self.line=line 1079 | self.index=index 1080 | if self.ui.currentBoard=="microbit": 1081 | return 1082 | 1083 | linetext= str(self.currentWidget().text(line)) 1084 | 1085 | if linetext=="" or linetext==None or len(linetext)==0: 1086 | return 1087 | 1088 | if linetext.find("\r")>=0 or linetext.find('\n')>=0: 1089 | if len(linetext)<=2 or index==0: 1090 | return 1091 | linetext=linetext[0:index] 1092 | #try: 1093 | if linetext[-1]==".": 1094 | begin=0 1095 | result=-1 1096 | showText="" 1097 | for i in linetext[0:-1]: 1098 | if ord(i)<=0x2F or (ord(i)>=0x3A and ord(i)<=0x40) or (ord(i)>=0x5B and ord(i)<0x5F) or (ord(i)>0x5F and ord(i)<=0x60) or \ 1099 | (ord(i)>=0x7B and ord(i)<=0x7F): 1100 | result=begin 1101 | begin+=1 1102 | 1103 | if result==-1: 1104 | showText=linetext[0:-1] 1105 | elif result==0: 1106 | showText=linetext[1:-1] 1107 | else: 1108 | showText=linetext[result+1:-1] 1109 | 1110 | #if functionList.get(showText)!=None: 1111 | # self.tabWidget.currentWidget().showUserList(1,functionList.get(showText)) 1112 | #except: 1113 | #pass 1114 | else: 1115 | if index==0: 1116 | return 1117 | linetext=linetext[0:index] 1118 | if linetext[-1]==".": 1119 | begin=0 1120 | result=-1 1121 | showText="" 1122 | for i in linetext[0:-1]: 1123 | if ord(i)<=0x2F or (ord(i)>=0x3A and ord(i)<=0x40) or (ord(i)>=0x5B and ord(i)<0x5F) or (ord(i)>0x5F and ord(i)<=0x60) or \ 1124 | (ord(i)>=0x7B and ord(i)<=0x7F): 1125 | result=begin 1126 | begin+=1 1127 | if result==-1: 1128 | showText=linetext[0:-1] 1129 | elif result==0: 1130 | showText=linetext[1:-1] 1131 | else: 1132 | showText=linetext[result+1:-1] 1133 | 1134 | #if functionList.get(showText)!=None: 1135 | # self.tabWidget.currentWidget().showUserList(1,functionList.get(showText)) 1136 | 1137 | def userListActivated(self,ida,text): 1138 | linetext= str(self.tabWidget.currentWidget().text(self.editorLine)) 1139 | linetext=linetext[0:self.editorIndex] 1140 | textsplit= linetext.split(' ') 1141 | linetext=textsplit[-1] 1142 | linetext=linetext.split(".")[-1] 1143 | 1144 | if linetext=="": 1145 | self.currentWidget().insertAt(text,self.line,self.index) 1146 | self.currentWidget().setCursorPosition(self.line,self.index+len(text)) 1147 | else: 1148 | self.currentWidget().insertAt(text[str(text).find(linetext)+len(linetext):],self.line,self.index) 1149 | self.currentWidget().setCursorPosition(self.line,self.index+len(text[str(text).find(linetext)+len(linetext):])) 1150 | 1151 | def dragOpenFile(self,filename): 1152 | if filename.find(".py")<0 and filename.find(".txt")<0 and\ 1153 | filename.find(".json")<0 and filename.find(".ini")<0: 1154 | print("current version can not open this file.") 1155 | return 1156 | else: 1157 | self.ui.pcOpenFile(filename) 1158 | 1159 | class myQsciScintilla(QsciScintilla): 1160 | def __init__(self,parent=None): 1161 | super(myQsciScintilla,self).__init__(parent) 1162 | 1163 | def dragEnterEvent(self,event): 1164 | print("tabwidget dragenterevent2.") 1165 | if event.mimeData().hasFormat("text/url-list")==True: 1166 | event.acceptProposedAction() 1167 | else: 1168 | event.ignore() 1169 | def dragMoveEvent(self,event): 1170 | event.acceptProposedAction() 1171 | def dropEvent(self,event): 1172 | print("tabwidget dropevent2.") 1173 | if event.mimeData().hasUrls: 1174 | urls=event.mimeData().urls() 1175 | dropOpenFileName="" 1176 | for url in urls: 1177 | dropOpenFileName=url.toLocalFile() 1178 | self.emit(SIGNAL("dragOpenFile"),dropOpenFileName) 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | #app=QApplication(sys.argv) 1202 | #main=myTextEdit()中 1203 | #main.show() 1204 | #app.exec_() 1205 | -------------------------------------------------------------------------------- /microbit_api.py: -------------------------------------------------------------------------------- 1 | MICROPYTHON_APIS = [ 2 | # System state objects. 3 | "microbit.panic() \nPut micro:bit in panic() mode and display an unhappy face.\nPress the reset button to exit panic() mode.", 4 | "microbit.sleep(time) \nPut micro:bit to sleep for some milliseconds (1 second = 1000 ms) of time.\nsleep(2000) gives micro:bit a 2 second nap.", 5 | "microbit.running_time() \nReturn running_time() in milliseconds since micro:bit's last reset.", 6 | "microbit.temperature() \nReturn micro:bit's temperature in degrees Celcius.", 7 | # Accelerometer 3D orientation 8 | "microbit.accelerometer.get_x() \nReturn micro:bit's tilt (X acceleration) in milli-g's.", 9 | "microbit.accelerometer.get_y() \nReturn micro:bit's tilt (Y acceleration) in milli-g's.", 10 | "microbit.accelerometer.get_z() \nReturn micro:bit's up-down motion (Z acceleration) in milli-g's.\nZ is a positive number when moving up. Moving down, Z is a negative number.", 11 | "microbit.accelerometer.is_gesture(name) \nReturn True or False to indicate if the named gesture is currently active.\nMicroPython understands the following gestures: 'up', 'down', 'left', 'right',\n'face up', 'face down', 'freefall', '3g', '6g', '8g' and 'shake'.", 12 | "microbit.accelerometer.was_gesture(name) \nReturn True or False to indicate if the named gesture was active since the\nlast call.\nMicroPython understands the following gestures: 'up', 'down', 'left', 'right',\n'face up', 'face down', 'freefall', '3g', '6g', '8g' and 'shake'.", 13 | "microbit.accelerometer.get_gestures() \nReturn a list indicating the gesture history. The most recent gesture is last.\nCalling this method also clears the gesture history.\nMicroPython understands the following gestures: 'up', 'down', 'left', 'right',\n'face up', 'face down', 'freefall', '3g', '6g', '8g' and 'shake'.", 14 | # Pushbutton 15 | "microbit.button_a.is_pressed() \nIf button A is pressed down, is_pressed() is True, else False.", 16 | "microbit.button_a.was_pressed() \nUse was_pressed() to learn if button A was pressed since the last time\nwas_pressed() was called. Returns True or False.", 17 | "microbit.button_a.get_presses() \nUse get_presses() to get the running total of button presses, and also\nreset this counter to zero.", 18 | "microbit.button_b.is_pressed() \nIf button B is pressed down, is_pressed() is True, else False.", 19 | "microbit.button_b.was_pressed() \nUse was_pressed() to learn if button B was pressed since the last time\nwas_pressed() was called. Returns True or False.", 20 | "microbit.button_b.get_presses() \nUse get_presses() to get the running total of button presses, and also\nreset this counter to zero.", 21 | # Compass 3D direction heading 22 | "microbit.compass.is_calibrated() \nIf micro:bit's compass is_calibrated() and adjusted for accuracy, return True.\nIf compass hasn't been adjusted for accuracy, return False.", 23 | "microbit.compass.calibrate() \nIf micro:bit is confused, calibrate() the compass to adjust the its accuracy.\nWill ask you to rotate the device to draw a circle on the display. Afterwards, micro:bit will know which way is north.", 24 | "microbit.compass.clear_calibration() \nReset micro:bit's compass using clear_calibration() command.\nRun calibrate() to improve accuracy.", 25 | "microbit.compass.get_x() \nReturn magnetic field detected along micro:bit's X axis.\nUsually, the compass returns the earth's magnetic field in micro-Tesla units.\nUnless...a strong magnet is nearby!", 26 | "microbit.compass.get_y() \nReturn magnetic field detected along micro:bit's Y axis.\nUsually, the compass returns the earth's magnetic field in micro-Tesla units.\nUnless...a strong magnet is nearby!", 27 | "microbit.compass.get_z() \nReturn magnetic field detected along micro:bit's Z axis.\nUsually, the compass returns the earth's magnetic field in micro-Tesla units.\nUnless...a strong magnet is nearby!", 28 | "microbit.compass.get_field_strength() \nReturn strength of magnetic field around micro:bit.", 29 | "microbit.compass.heading() \nReturn a number between 0-360 indicating the device's heading. 0 is north.", 30 | # Display 5x5 LED grid 31 | "microbit.display.show(x, delay=400, wait=True, loop=False, clear=False) \nUse show(x) to print the string or image 'x' to the display. If 'x' is a list\nof images they will be animated together.\nUse 'delay' to specify the speed of frame changes in milliseconds.\nIf wait is False animation will happen in the background while the program continues.\nIf loop is True the animation will repeat forever.\nIf clear is True the display will clear at the end of the animation.", 32 | "microbit.display.scroll(string, delay=150, wait=True, loop=False, monospace=False) \nUse scroll(string) to scroll the string across the display.\nUse delay to control how fast the text scrolls.\nIf wait is False the text will scroll in the background while the program continues.\nIf loop is True the text will repeat forever.\nIf monospace is True the characters will always take up 5 pixel-columns.", 33 | "microbit.display.clear() \nUse clear() to clear micro:bit's display.", 34 | "microbit.display.get_pixel(x, y) \nUse get_pixel(x, y) to return the display's brightness at LED pixel (x,y).\nBrightness can be from 0 (LED is off) to 9 (maximum LED brightness).", 35 | "microbit.display.set_pixel(x, y, b) \nUse set_pixel(x, y, b) to set the display at LED pixel (x,y) to brightness 'b'\nwhich can be set between 0 (off) to 9 (full brightness).", 36 | "microbit.display.on() \nUse on() to turn on the display.", 37 | "microbit.display.off() \nUse off() to turn off the display.", 38 | "microbit.display.is_on() \nUse is_on() to query if the micro:bit's display is on (True) or off (False).", 39 | # Pins 40 | "microbit.pin0.is_touched() \nIf pin0 is_touched() on micro:bit, return True. If nothing is touching the\npin, return False.", 41 | "microbit.pin0.read_digital() \nread_digital() value from pin0. The reading will be either 0 (lo) or 1 (hi).", 42 | "microbit.pin0.write_digital(value) \nSet pin0 to output high if value is 1, or to low, it it is 0.", 43 | "microbit.pin0.read_analog() \nRead the voltage applied to pin0. Return the reading as a number between\n0 (meaning 0v) and 1023 (meaning 3.3v).", 44 | "microbit.pin0.write_analog(value) \nSet pin0 to output a value between 0 and 1023.", 45 | "microbit.pin0.set_analog_period(period) \nSet the period of the PWM signal output to period milliseconds.", 46 | "microbit.pin0.set_analog_period_microseconds(period) \nSet the period of the PWM signal output to period microseconds.", 47 | 48 | "microbit.pin1.is_touched() \nIf pin1 is_touched() on micro:bit, return True. If nothing is touching the\npin, return False.", 49 | "microbit.pin1.read_digital() \nread_digital() value from pin1. The reading will be either 0 (lo) or 1 (hi).", 50 | "microbit.pin1.write_digital(value) \nSet pin1 to output high if value is 1, or to low, it it is 0.", 51 | "microbit.pin1.read_analog() \nRead the voltage applied to pin1. Return the reading as a number between\n0 (meaning 0v) and 1023 (meaning 3.3v).", 52 | "microbit.pin1.write_analog(value) \nSet pin1 to output a value between 0 and 1023.", 53 | "microbit.pin1.set_analog_period(period) \nSet the period of the PWM signal output to period milliseconds.", 54 | "microbit.pin1.set_analog_period_microseconds(period) \nSet the period of the PWM signal output to period microseconds.", 55 | 56 | "microbit.pin2.is_touched() \nIf pin2 is_touched() on micro:bit, return True. If nothing is touching the\npin, return False.", 57 | "microbit.pin2.read_digital() \nread_digital() value from pin2. The reading will be either 0 (lo) or 1 (hi).", 58 | "microbit.pin2.write_digital(value) \nSet pin2 to output high if value is 1, or to low, it it is 0.", 59 | "microbit.pin2.read_analog() \nRead the voltage applied to pin2. Return the reading as a number between\n0 (meaning 0v) and 1023 (meaning 3.3v).", 60 | "microbit.pin2.write_analog(value) \nSet pin2 to output a value between 0 and 1023.", 61 | "microbit.pin2.set_analog_period(period) \nSet the period of the PWM signal output to period milliseconds.", 62 | "microbit.pin2.set_analog_period_microseconds(period) \nSet the period of the PWM signal output to period microseconds.", 63 | 64 | "microbit.pin3.read_digital() \nread_digital() value from pin3. The reading will be either 0 (lo) or 1 (hi).", 65 | "microbit.pin2.write_digital(value) \nSet pin3 to output high if value is 1, or to low, it it is 0.", 66 | "microbit.pin3.read_analog() \nRead the voltage applied to pin3. Return the reading as a number between\n0 (meaning 0v) and 1023 (meaning 3.3v).", 67 | "microbit.pin3.write_analog(value) \nSet pin3 to output a value between 0 and 1023.", 68 | "microbit.pin3.set_analog_period(period) \nSet the period of the PWM signal output to period milliseconds.", 69 | "microbit.pin3.set_analog_period_microseconds(period) \nSet the period of the PWM signal output to period microseconds.", 70 | 71 | "microbit.pin4.read_digital() \nread_digital() value from pin4. The reading will be either 0 (lo) or 1 (hi).", 72 | "microbit.pin4.write_digital(value) \nSet pin4 to output high if value is 1, or to low, it it is 0.", 73 | "microbit.pin4.read_analog() \nRead the voltage applied to pin4. Return the reading as a number between\n0 (meaning 0v) and 1023 (meaning 3.3v).", 74 | "microbit.pin4.write_analog(value) \nSet pin4 to output a value between 0 and 1023.", 75 | "microbit.pin4.set_analog_period(period) \nSet the period of the PWM signal output to period milliseconds.", 76 | "microbit.pin4.set_analog_period_microseconds(period) \nSet the period of the PWM signal output to period microseconds.", 77 | 78 | "microbit.pin5.read_digital() \nread_digital() value from pin5. The reading will be either 0 (lo) or 1 (hi).", 79 | "microbit.pin5.write_digital(value) \nSet pin5 to output high if value is 1, or to low, it it is 0.", 80 | 81 | "microbit.pin6.read_digital() \nread_digital() value from pin6. The reading will be either 0 (lo) or 1 (hi).", 82 | "microbit.pin6.write_digital(value) \nSet pin6 to output high if value is 1, or to low, it it is 0.", 83 | 84 | "microbit.pin7.read_digital() \nread_digital() value from pin7. The reading will be either 0 (lo) or 1 (hi).", 85 | "microbit.pin7.write_digital(value) \nSet pin7 to output high if value is 1, or to low, it it is 0.", 86 | 87 | "microbit.pin8.read_digital() \nread_digital() value from pin8. The reading will be either 0 (lo) or 1 (hi).", 88 | "microbit.pin8.write_digital(value) \nSet pin8 to output high if value is 1, or to low, it it is 0.", 89 | 90 | "microbit.pin9.read_digital() \nread_digital() value from pin9. The reading will be either 0 (lo) or 1 (hi).", 91 | "microbit.pin9.write_digital(value) \nSet pin9 to output high if value is 1, or to low, it it is 0.", 92 | 93 | "microbit.pin10.read_digital() \nread_digital() value from pin10. The reading will be either 0 (lo) or 1 (hi).", 94 | "microbit.pin10.write_digital(value) \nSet pin10 to output high if value is 1, or to low, it it is 0.", 95 | "microbit.pin10.read_analog() \nRead the voltage applied to pin10. Return the reading as a number between\n0 (meaning 0v) and 1023 (meaning 3.3v).", 96 | "microbit.pin10.write_analog(value) \nSet pin10 to output a value between 0 and 1023.", 97 | "microbit.pin10.set_analog_period(period) \nSet the period of the PWM signal output to period milliseconds.", 98 | "microbit.pin10.set_analog_period_microseconds(period) \nSet the period of the PWM signal output to period microseconds.", 99 | 100 | "microbit.pin11.read_digital() \nread_digital() value from pin11. The reading will be either 0 (lo) or 1 (hi).", 101 | "microbit.pin11.write_digital(value) \nSet pin11 to output high if value is 1, or to low, it it is 0.", 102 | 103 | "microbit.pin12.read_digital() \nread_digital() value from pin12. The reading will be either 0 (lo) or 1 (hi).", 104 | "microbit.pin12.write_digital(value) \nSet pin12 to output high if value is 1, or to low, it it is 0.", 105 | 106 | "microbit.pin13.read_digital() \nread_digital() value from pin13. The reading will be either 0 (lo) or 1 (hi).", 107 | "microbit.pin13.write_digital(value) \nSet pin13 to output high if value is 1, or to low, it it is 0.", 108 | 109 | "microbit.pin14.read_digital() \nread_digital() value from pin14. The reading will be either 0 (lo) or 1 (hi).", 110 | "microbit.pin14.write_digital(value) \nSet pin14 to output high if value is 1, or to low, it it is 0.", 111 | 112 | "microbit.pin15.read_digital() \nread_digital() value from pin15. The reading will be either 0 (lo) or 1 (hi).", 113 | "microbit.pin15.write_digital(value) \nSet pin15 to output high if value is 1, or to low, it it is 0.", 114 | 115 | "microbit.pin16.read_digital() \nread_digital() value from pin16. The reading will be either 0 (lo) or 1 (hi).", 116 | "microbit.pin16.write_digital(value) \nSet pin16 to output high if value is 1, or to low, it it is 0.", 117 | 118 | "microbit.pin19.read_digital() \nread_digital() value from pin19. The reading will be either 0 (lo) or 1 (hi).", 119 | "microbit.pin19.write_digital(value) \nSet pin19 to output high if value is 1, or to low, it it is 0.", 120 | 121 | "microbit.pin20.read_digital() \nread_digital() value from pin20. The reading will be either 0 (lo) or 1 (hi).", 122 | "microbit.pin20.write_digital(value) \nSet pin20 to output high if value is 1, or to low, it it is 0.", 123 | # I2C 124 | "microbit.i2c.read(address, n, repeat=False) \nUse read(address, n) to read 'n' bytes from the device with the 7-bit address.\nIf repeat is True, no stop bit will be sent.", 125 | "microbit.i2c.write(adress, buffer, repeat=False) \nUse write(address, buffer) to write to the 'buffer' of the device at the 7-bit 'address'.\nIf repeat is True, no stop bit will be sent.", 126 | "microbit.i2c.init(frequency, scl, sda) \nUse init(frequency, scl, sda) to set the bus frequency and pins.", 127 | # Image 128 | "microbit.Image(string) \nCreate and use built-in IMAGES to show on the display. Use:\nImage(\n '09090:'\n '99999:'\n '99999:'\n '09990:'\n '00900:')\n...to make a new 5x5 heart image. Numbers go from 0 (off) to 9 (brightest). Note\nthe colon ':' to set the end of a row.", 129 | "microbit.Image.width() \nReturn the width of the image in pixels.", 130 | "microbit.Image.height() \nReturn the height of the image in pixels.", 131 | "microbit.Image.get_pixel(x, y) \nUse get_pixel(x, y) to return the image's brightness at LED pixel (x,y).\nBrightness can be from 0 (LED is off) to 9 (maximum LED brightness).", 132 | "microbit.Image.set_pixel(x, y, b) \nUse set_pixel(x, y, b) to set the LED pixel (x,y) in the image to brightness\n'b' which can be set between 0 (off) to 9 (full brightness).", 133 | "microbit.Image.shift_left(n) \nUse shift_left(n) to make a copy of the image but moved 'n' pixels to the left.", 134 | "microbit.Image.shift_right(n) \nUse shift_right(n) to make a copy of the image but moved 'n' pixels to\nthe right.", 135 | "microbit.Image.shift_up(n) \nUse shift_up(n) to make a copy of the image but moved 'n' pixels up.", 136 | "microbit.Image.shift_down(n) \nUse shift_down(n) to make a copy of the image but moved 'n' pixels down.", 137 | "microbit.Image.copy() \nUse copy() to make a new exact copy of the image.", 138 | "microbit.Image.crop(x1, y1, x2, y2) \nUse crop(x1, y1, x2, y2) to make a cut-out copy of the image where coordinate\n(x1,y1) is the top left corner of the cut-out area and coordinate (x2,y2) is the\nbottom right corner.", 139 | "microbit.Image.invert() \nUse invert() to make a negative copy of the image. Where a pixel was bright or\non in the original, it is dim or off in the negative copy.", 140 | "microbit.Image.HEART", 141 | "microbit.Image.HEART_SMALL", 142 | "microbit.Image.HAPPY", 143 | "microbit.Image.SMILE", 144 | "microbit.Image.SAD", 145 | "microbit.Image.CONFUSED", 146 | "microbit.Image.ANGRY", 147 | "microbit.Image.ASLEEP", 148 | "microbit.Image.SURPRISED", 149 | "microbit.Image.SILLY", 150 | "microbit.Image.FABULOUS", 151 | "microbit.Image.MEH", 152 | "microbit.Image.YES", 153 | "microbit.Image.NO", 154 | "microbit.Image.CLOCK12", 155 | "microbit.Image.CLOCK11", 156 | "microbit.Image.CLOCK10", 157 | "microbit.Image.CLOCK9", 158 | "microbit.Image.CLOCK8", 159 | "microbit.Image.CLOCK7", 160 | "microbit.Image.CLOCK6", 161 | "microbit.Image.CLOCK5", 162 | "microbit.Image.CLOCK4", 163 | "microbit.Image.CLOCK3", 164 | "microbit.Image.CLOCK2", 165 | "microbit.Image.CLOCK1", 166 | "microbit.Image.ARROW_N", 167 | "microbit.Image.ARROW_NE", 168 | "microbit.Image.ARROW_E", 169 | "microbit.Image.ARROW_SE", 170 | "microbit.Image.ARROW_S", 171 | "microbit.Image.ARROW_SW", 172 | "microbit.Image.ARROW_W", 173 | "microbit.Image.ARROW_NW", 174 | "microbit.Image.TRIANGLE", 175 | "microbit.Image.TRIANGLE_LEFT", 176 | "microbit.Image.CHESSBOARD", 177 | "microbit.Image.DIAMOND", 178 | "microbit.Image.DIAMOND_SMALL", 179 | "microbit.Image.SQUARE", 180 | "microbit.Image.SQUARE_SMALL", 181 | "microbit.Image.RABBIT", 182 | "microbit.Image.COW", 183 | "microbit.Image.MUSIC_CROTCHET", 184 | "microbit.Image.MUSIC_QUAVER", 185 | "microbit.Image.MUSIC_QUAVERS", 186 | "microbit.Image.PITCHFORK", 187 | "microbit.Image.XMAS", 188 | "microbit.Image.PACMAN", 189 | "microbit.Image.TARGET", 190 | "microbit.Image.TSHIRT", 191 | "microbit.Image.ROLLERSKATE", 192 | "microbit.Image.DUCK", 193 | "microbit.Image.HOUSE", 194 | "microbit.Image.TORTOISE", 195 | "microbit.Image.BUTTERFLY", 196 | "microbit.Image.STICKFIGURE", 197 | "microbit.Image.GHOST", 198 | "microbit.Image.SWORD", 199 | "microbit.Image.GIRAFFE", 200 | "microbit.Image.SKULL", 201 | "microbit.Image.UMBRELLA", 202 | "microbit.Image.SNAKE", 203 | "microbit.Image.ALL_CLOCKS", 204 | "microbit.Image.ALL_ARROWS", 205 | # uart 206 | "microbit.uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=None, rx=None) \nUse init() to set up communication using the default values. \nOtherwise override the defaults as named arguments.", 207 | "microbit.uart.any() \nIf there are incoming characters waiting to be read, any() will return True.\nOtherwise, returns False.", 208 | "microbit.uart.read(n) \nUse read() to read characters.\nUse read(n) to read, at most, 'n' bytes of data.", 209 | "microbit.uart.readall() \nUse readall() to read as much data as possible.", 210 | "microbit.uart.readline() \nUse readline() to read a line that ends with a newline character.", 211 | "microbit.uart.readinto(buf, n) \nUse readinto(buf) to read bytes into the buffer 'buf'.\nUse readinto(buff, n) to read, at most, 'n' number of bytes into 'buf'.", 212 | "microbit.uart.write() \nUse write(buf) to write the bytes in buffer 'buf' to the connected device.", 213 | # SPI 214 | "microbit.spi.init(baudrate=1000000, bits=8, mode=0, sclk=pin13, mosi=pin15, miso=pin14) \nSet up communication. Override the defaults for baudrate, mode,\nSCLK, MOSI and MISO. The default connections are pin13 for SCLK, pin15 for\nMOSI and pin14 for MISO.", 215 | "microbit.spi.write(buf) \nUse write(buf) to write bytes in buffer 'buf' to the connected device.", 216 | "microbit.spi.read(n) \nUse read(n) to read 'n' bytes of data.", 217 | "microbit.spi.write_readinto(out, in) \nUse write_readinto(out, in) to write the 'out' buffer to the connected device\nand read any response into the 'in' buffer. The length of the buffers should\nbe the same. The buffers can be the same object.", 218 | # Music module 219 | "music.set_tempo(number, bpm) \nMake a beat last a 'number' of ticks long and\nplayed at 'bpm' beats per minute.", 220 | "music.pitch(freq, length=-1, pin=microbit.pin0, wait=True) \nMake micro:bit play a note at 'freq' frequency for\n'length' milliseconds. E.g. pitch(440, 1000) will play concert 'A' for 1 second.\nIf length is a negative number the pitch is played continuously.\nUse the optional pin argument to override the default output for the speaker.\nIf wait is False the music will play in the background while the program\ncontinues.", 221 | "music.play(music, pin=microbit.pin0, wait=True, loop=False) \nMake micro:bit play 'music' list of notes. Try out the built in music to see\nhow it works. E.g. music.play(music.PUNCHLINE).\nUse the optional pin argument to override the default output for the speaker.\nIf wait is False the music will play in the background while the program\ncontinues.\nIf loop is True, the tune will repeat.", 222 | "music.get_tempo() \nReturn the number of ticks in a beat and number of beats per minute.", 223 | "music.stop(pin=microbit.pin0) \nStops all music playback on the given pin. If no pin is given, pin0 is assumed.", 224 | "music.reset()\nIf things go wrong, reset() the music to its default settings.", 225 | "music.DADADADUM", 226 | "music.ENTERTAINER", 227 | "music.PRELUDE", 228 | "music.ODE", 229 | "music.NYAN", 230 | "music.RINGTONE", 231 | "music.FUNK", 232 | "music.BLUES", 233 | "music.BIRTHDAY", 234 | "music.WEDDING", 235 | "music.FUNERAL", 236 | "music.PUNCHLINE", 237 | "music.PYTHON", 238 | "music.BADDY", 239 | "music.CHASE", 240 | "music.BA_DING", 241 | "music.WAWAWAWAA", 242 | "music.JUMP_UP", 243 | "music.JUMP_DOWN", 244 | "music.POWER_UP", 245 | "music.POWER_DOWN", 246 | # Antigravity 247 | "antigravity", 248 | # This module 249 | "this.authors() \nUse authors() to reveal the names of the people who created this software.", 250 | # Love module 251 | "love.badaboom()\nHear my soul speak:\nThe very instant that I saw you, did\nMy heart fly to your service.", 252 | # NeoPixel module 253 | "neopixel.NeoPixel(pin, n) \nCreate a list representing a strip of 'n' neopixels controlled from the\nspecified pin (e.g. microbit.pin0).\nUse the resulting object to change each pixel by position (starting from 0).\nIndividual pixels are given RGB (red, green, blue) values between 0-255 as a\ntupe. For example, (255, 255, 255) is white:\n\nnp = neopixel.NeoPixel(microbit.pin0, 8)\nnp[0] = (255, 0, 128)\nnp.show()", 254 | "neopixel.NeoPixel.clear() \nClear all the pixels.", 255 | "neopixel.NeoPixel.show() \nShow the pixels. Must be called for any updates to become visible.", 256 | # RNG 257 | "random.getrandbits(n) \nReturn an integer with n random bits.", 258 | "random.seed(n) \nInitialise the random number generator with a known integer 'n'.", 259 | "random.randint(a, b) \nReturn a random whole number between a and b (inclusive).", 260 | "random.randrange(stop) \nReturn a random whole number between 0 and up to (but not including) stop.", 261 | "random.choice(seq) \nReturn a randomly selected element from a sequence of objects (such as a list).", 262 | "random.random() \nReturn a random floating point number between 0.0 and 1.0.", 263 | "random.uniform(a, b) \nReturn a random floating point number between a and b (inclusive).", 264 | # OS 265 | "os.listdir() \nReturn a list of the names of all the files contained within the local\non-device file system.", 266 | "os.remove(filename) \nRemove (delete) the file named filename.", 267 | "os.size(filename) \nReturn the size, in bytes, of the file named filename.", 268 | "os.uname() \nReturn information about MicroPython and the device.", 269 | # SYS 270 | "sys.version", 271 | "sys.version_info", 272 | "sys.implementation", 273 | "sys.platform", 274 | "sys.byteorder", 275 | "sys.print_exception(ex) \nPrint to the REPL information about the exception 'ex'.", 276 | # String functions 277 | "find(sub, start, end) \nReturn the lowest index in the string where substring 'sub' is found. The optional\n'start' and 'end' arguments specify the slice of string to use.\nReturns -1 if 'sub' cannot be found.", 278 | "rfind(sub, start, end) \nReturn the highest index in the string where substring 'sub' is found. The optional\n'start' and 'end' arguments specify the slice of string to use.\nReturns -1 if 'sub' cannot be found.", 279 | "index(sub, start, end) \nReturn the lowest index in the string where substring 'sub' is found. The optional\n'start' and 'end' arguments specify the slice of string to use.\nRaises a ValueError if 'sub' cannot be found.", 280 | "rindex(sub, start, end) \nReturn the highest index in the string where substring 'sub' is found. The optional\n'start' and 'end' arguments specify the slice of string to use.\nRaises a ValueError if 'sub' cannot be found.", 281 | "join(iterable) \nReturn a string which is the concatenation of the strings in 'iterable'.\nThe separator between elements is the string providing this method.", 282 | "split(sep=None, maxsplit=-1) \nReturn a list of the words in a string, using 'sep' as the delimiter string.\nIf 'sep' is not provided, the splitting algorithm uses whitespace.\nIf the optional 'maxsplit' is provided, splitting will occur 'maxsplit' times.", 283 | "rsplit(sep=None, maxsplit=-1) \nReturn a list of the words in a string, using 'sep' as the delimiter string.\nIf 'sep' is not provided, the splitting algorithm uses whitespace.\nIf the optional 'maxsplit' is provided, splitting will only occur 'maxsplit'\ntimes from the right.", 284 | "startswith(prefix) \nReturns True if the string starts with 'prefix'.", 285 | "endswith(suffix) \nReturns True if the string ends with 'suffix'.", 286 | "strip(chars) \nReturn a copy of the string with the leading and trailing characters removed.\nThe chars argument is a string specifying the set of characters to be removed.\nIf omitted or None, the chars argument defaults to removing whitespace.\nThe chars argument is not a prefix or suffix; rather, all combinations of its values are stripped", 287 | "lstrip(chars) \nReturn a copy of the string with leading characters removed. The chars argument\nis a string specifying the set of characters to be removed.\nIf omitted or None, the chars argument defaults to removing whitespace.\nThe chars argument is not a prefix; rather, all combinations of its values are\nstripped", 288 | "rstrip(chars) \nReturn a copy of the string with trailing characters removed. The chars argument\nis a string specifying the set of characters to be removed.\nIf omitted or None, the chars argument defaults to removing whitespace.\nThe chars argument is not a suffix; rather, all combinations of its values are\nstripped", 289 | "format(*args, **kwargs) \nPerform a string formatting operation. The string on which this method is called\ncan contain literal text or replacement fields delimited by braces {}. Each\nreplacement field contains either the numeric index of a positional argument,\nor the name of a keyword argument.\nReturns a copy of the string where each replacement field is replaced with the\nstring value of the corresponding argument.", 290 | "replace(old, new) \nReturn a copy of the string with all othe occurrences of 'old' replaced with 'new'.", 291 | "count(sub, start, end) \nReturn the number of non-overlapping occurrences of substring 'sub'.\nOptional arguments 'start' and 'end' specify the slice of the string to use. ", 292 | "partition(sep) \nSplit the string at the first occurrence of 'sep', and return a 3-tuple containing\nthe part before the separator, the separator itself, and the part after the separator.\nIf the separator is not found, return a 3-tuple containing the string itself,\nfollowed by two empty strings.", 293 | "rpartition(sep) \nSplit the string at the last occurrence of 'sep', and return a 3-tuple containing\nthe part before the separator, the separator itself, and the part after the separator.\nIf the separator is not found, return a 3-tuple containing two empty strings,\nfollowed by the string itself.", 294 | "lower() \nReturn a copy of the string with all the cased characters converted to lowercase.", 295 | "upper() \nReturn a copy of the string with all the cased characters converted to uppercase.", 296 | "isspace() \nReturn True if there are only whitespace characters in the string and thers is\nat least one character.", 297 | "isalpha() \nReturn True if all the characters in the string are alphabetic and there is\nat least one character.", 298 | "isdigit() \nReturn True if all characters in the string are digits and there is\nat least one character.", 299 | "isupper() \nReturn True if all characters in the string are uppercase and there is\nat least one character.", 300 | "islower() \nReturn True if all characters in the string are lowercase and there is\nat least one character.", 301 | # Math functions 302 | "math.sqrt(x) \nReturn the square root of 'x'.", 303 | "math.pow(x, y) \nReturn 'x' raised to the power 'y'.", 304 | "math.exp(x) \nReturn math.e**'x'.", 305 | "math.log(x, base=math.e) \nWith one argument, return the natural logarithm of 'x' (to base e).\nWith two arguments, return the logarithm of 'x' to the given 'base'.", 306 | "math.cos(x) \nReturn the cosine of 'x' radians.", 307 | "math.sin(x) \nReturn the sine of 'x' radians.", 308 | "math.tan(x) \nReturn the tangent of 'x' radians.", 309 | "math.acos(x) \nReturn the arc cosine of 'x', in radians.", 310 | "math.asin(x) \nReturn the arc sine of 'x', in radians.", 311 | "math.atan(x) \nReturn the arc tangent of 'x', in radians.", 312 | "math.atan2(x, y) \nReturn atan(y / x), in radians.", 313 | "math.ceil(x) \nReturn the ceiling of 'x', the smallest integer greater than or equal to 'x'.", 314 | "math.copysign(x, y) \nReturn a float with the magnitude (absolute value) of 'x' but the sign of 'y'. ", 315 | "math.fabs(x) \nReturn the absolute value of 'x'.", 316 | "math.floor(x) \nReturn the floor of 'x', the largest integer less than or equal to 'x'.", 317 | "math.fmod(x, y) \nReturn 'x' modulo 'y'.", 318 | "math.frexp(x) \nReturn the mantissa and exponent of 'x' as the pair (m, e). ", 319 | "math.ldexp(x, i) \nReturn 'x' * (2**'i').", 320 | "math.modf(x) \nReturn the fractional and integer parts of x.\nBoth results carry the sign of x and are floats.", 321 | "math.isfinite(x) \nReturn True if 'x' is neither an infinity nor a NaN, and False otherwise.", 322 | "math.isinf(x) \nReturn True if 'x' is a positive or negative infinity, and False otherwise.", 323 | "math.isnan(x) \nReturn True if 'x' is a NaN (not a number), and False otherwise.", 324 | "math.trunc(x) \nReturn the Real value 'x' truncated to an Integral (usually an integer).", 325 | "math.radians(x) \nConvert angle 'x' from degrees to radians.", 326 | "math.degrees(x) \nConvert angle 'x' from radians to degrees.", 327 | # built-in functions 328 | "abs(x) \nReturn the absolute value of the number 'x'.", 329 | "all(iterable) \nReturn True if all elements of iterable are true (or iterable is empty).", 330 | "any(iterable) \nReturn True if any element of iterable is true. If iterable is empty, return False.", 331 | "bin(x) \nConvert an integer (whole) number into a binary string.", 332 | "bool(x) \nReturn a Boolean value, i.e. one of True or False. The argument 'x' is used to\ngenerate the resulting truth value.", 333 | "bytearray(seq) \nReturn a new array of bytes specified by the sequence 'seq' of integers.", 334 | "bytes(seq) \nReturn a new 'bytes' object - an immutable sequence of 'seq' integers.", 335 | "callable(object) \nReturn True if the 'object' appears to be callable. Otherwise return False.", 336 | "chr(i) \nReturn a string representing a character whose Unicode code point is the integer 'i'.", 337 | "classmethod(function) \nReturn a class method for a function. Usually used as a decorator:\n\nclass C:\n @classmethod\n def func(cls): ...", 338 | "dict(): \nCreate a new dictionary object.", 339 | "dir(object) \nReturn a list of names in the scope of 'object'. If no object is supplied,\nreturns a ist of names in the current local scope.", 340 | "divmod(a, b) \nTake two (non complex) numbers and return a pair of numbers consisting of the quotient and remainder. For example, divmod(5, 4) results in (1, 1). That is, what's is 5 divided by 4? It's 1 remainder 1.", 341 | "enumerate(iterable, start=0) \nReturn an enumerate object from an iterable object.\nEach iteration of the resulting object returns a tuple containing a count and the value. For example:\n\nseasons = ['Spring', 'Summer', 'Autumn', 'Winter']\nlist(enumerate(seasons))\n[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]", 342 | "eval(expression, globals=None, locals=None) \nThe 'expression' string containing a Python expression is parsed and evaluated given\nthe context specified by 'globals' and 'locals' which must be dictionary objects.", 343 | "exec(object, globals, locals) \nThis function supports dynamic execution of Python code. The 'object' must be\na string containing Python code that can be parsed and evaluated. If `globals` and\n`locals` are emitted the code is executed in the local scope. Otherwise, both\n'globals' and 'locals' must be dictionary objects.", 344 | "filter(function, iterable) \nConstruct an iterator from those elements of 'iterable' for which 'function' returns True.", 345 | "float(x) \nReturn a floating point number constructed from a number or string 'x'.", 346 | "frozenset(iterable) \nReturn a new frozenset object, optionally with elements taken from 'iterable'.", 347 | "getattr(object, name, default) \nReturn the value fo the named attribute of 'object'. 'name' must be a string.\nOptionally return 'default' if 'name' is not an attribute of 'object'.", 348 | "globals() \nReturn a dictionary representing the current global symbol table.\nI.e. named objects that are currently in the global scope.", 349 | "hasattr(object, name) \nReturns True if the 'object' has an attribute called 'name'. 'name' must be a string.", 350 | "hash(object) \nReturn a hash value of the object (if it has one). Hash values are integers.", 351 | "help(object) \nInvoke the built-in help system (intended for interactive use in the REPL.", 352 | "hex(x) \nConvert an integer 'x' to a lowercase hexadevimal string prefixed with '0x'. For example, hex(255) returns '0xff'.", 353 | "id(object) \nReturn the identity of an object. This is an integer that is guaranteed to be unique.", 354 | "int(x, base=10) \nReturn an integer constructed from a number or string 'x'. The optional 'base' (indicating the base of the number) defaults to 10.", 355 | "isinstance(object, classinfo) \nReturn True if the 'object' is an instance of 'classinfo'.", 356 | "issubclass(class, classinfo) \nReturn True if the 'class' is a subclass (direct, indirect or virtual) of 'classinfo'.", 357 | "iter(object) \nReturn an iterator object for the 'object' (that must support the iteration protocol.", 358 | "len(object) \nReturn the length (the number of items) in an 'object'.", 359 | "list(iterable) \nReturn a list, optionally based upon the members of 'iterable'.", 360 | "locals() \nReturn a dictionary representing the current local symbol table. I.e. named objects\nthat are currently in the local scope.", 361 | "map(function, iterable) \nReturn an iterator that applies 'function' to every item of 'iterable', yielding the results.", 362 | "max(items) \nReturn the largest item in 'items', which can be either an iterable or two or more arguments.", 363 | "min(items) \nReturn the smallest item in 'items', which can be either an iterable or two or more arguments.", 364 | "next(iterator) \nRetrieve the next item from the iterator.", 365 | "object() \nReturn a new featureless object.", 366 | "oct(x) \nConvert an integer number to an octal (base 8) string.", 367 | "open(file, mode='rt') \nOpen 'file' and return a corresponding file object. The 'mode' is an optional\nstring that specifies how the file is opened:\n'r' - open for reading\n'w' - open for writing\n'b' - binary mode\n't' - text mode.", 368 | "ord(c) \nGiven a string representing one Unicode character, return an integer representing the Unicode code point of that character.", 369 | "pow(x, y, z) \nReturn 'x' to the power of 'y'. If the optional 'z' is given, return 'x' to the power of 'y' modulo 'z' (giving the remainder).", 370 | "print(*objects, sep=' ', end='\\n') \nPrint objects, separated by 'sep' and followed by 'end'. All non-keyword arguments are converted to strings.", 371 | "range(start, stop, step) \nReturn an immutable sequence containing items between 'start' and 'stop' with 'step' difference between them.", 372 | "repr(object) \nReturn a string containing a printable representation of an 'object'.", 373 | "reversed(seq) \nReturn a reverse iterator of the sequence 'seq'.", 374 | "round(number, ndigits) \nReturn the floating point 'number' rounded to the (optional) 'ndigits'.\nIf 'ndigits' is omitted, round to the nearest whole number.", 375 | "set(iterable) \nReturn a new set object, optionally containing elements taken from iterable.", 376 | "setattr(object, name, value) \nSet the 'value' to the attribute called 'name' on object 'object'. 'name' must be a string.", 377 | "sorted(iterable, key, reverse) \nReturn a new sorted list from the items in iterable. The optional 'key' specifies\na function used for comparison and the optional 'reverse' is a boolean indicating the comparison should be reversed.", 378 | "staticmethod(function) \nReturns a static method for a function. Usually used as a decorator:\n\nclass C:\n @staticmethod\ndef func(): ...", 379 | "str(object) \nReturn a string version of 'object'.", 380 | "sum(iterable, start=0) \nSums 'start' and items of an iterable from left to right and returns the total.", 381 | "super(type, object-or-type) \nReturn a proxy object that delegates method calls to a parent or sibling class\nof 'type'. This is useful for accessing inherited methods that have been\noverridden in a class.", 382 | "tuple(iterable) \nReturn an immutable sequence based upon the items in 'iterable'.", 383 | "type(object) \nReturn the type of an object (i.e. what sort of thing it is).", 384 | "zip(*iterables) \nMake an iterator that aggregates elements from each of the passed in iterables.\nFor example:\nx = [1, 2, 3]\ny = [4, 5, 6]\nlist(zip(x, y))\n[(1, 4), (2, 5), (3, 6)]", 385 | # Radio 386 | "radio.on() \nTurns on the radio. This needs to be called since the radio draws power and\ntakes up memory that you may otherwise need.", 387 | "radio.off() \nTurns off the radio, thus saving power and memory.", 388 | "radio.config(length=32, queue=3, channel=7, power=0, address=0x75626974, group=0, data_rate=radio.RATE_1MBIT) \nConfigures the various settings relating to the radio. The specified default\nvalues are sensible.\n'length' is the maximum length, in bytes, of a message. It can be up to 251\nbytes long.\n'queue' is the number of messages to store on the message queue.\n'channel' (0-100) defines the channel to which the radio is tuned.\n'address' is an arbitrary 32-bit address that's used to filter packets.\n'group' is an 8-bit value used with 'address' when filtering packets.\n'data_rate' is the throughput speed. It can be one of: radio.RATE_250KbIT,\nradio.RATE_1MbIT (the default) or radio.2MBIT.", 389 | "radio.reset() \nReset the settings to their default value.", 390 | "radio.send_bytes(message) \nSends a message containing bytes.", 391 | "radio.receive_bytes() \nReceive the next incoming message from the message queue. Returns 'None' if\nthere are no pending messages. Messages are returned as bytes.", 392 | "radio.send(message) \nSend a message string.", 393 | "radio.receive() \nReceive the next incoming message from the message queue as a string. Returns\n'None' if there are no pending messages.", 394 | "radio.RATE_250KBIT", 395 | "radio.RATE_1MBIT", 396 | "radio.RATE_2MBIT", 397 | # Audio 398 | "audio.play(source, wait=True, pins=(pin0, pin1)) \nPlay the source to completion where 'source' is an iterable, each element of\nwhich must be an AudioFrame instance.", 399 | "audio.AudioFrame()() \nRepresents a list of 32 samples each of which is a signed byte. It takes just\nover 4ms to play a single frame.", 400 | # Speech 401 | "speech.translate(words) \nReturn a string containing the phonemes for the English words in the string\n'words'.", 402 | "speech.say(words, pitch=64, speed=72, mouth=128, throat=128) \nSay the English words in the string 'words'. Override the optional pitch,\nspeed, mouth and throat settings to change the tone of voice.", 403 | "speech.pronounce(phonemes, pitch=64, speed=72, mouth=128, throat=128) \nPronounce the phonemes in the string 'phonemes'. Override the optional pitch,\nspeed, mouth and throat settings to change the tone of voice.", 404 | "speech.sing(song, pitch=64, speed=72, mouth=128, throat=128) \nSing the phonemes in the string 'song'. Add pitch information to a phoneme\nwith a hash followed by a number between 1-255 like this: '#112DOWWWWWWWW'.\nOverride the optional pitch, speed, mouth and throat settings to change the\ntone of voice.", 405 | ] 406 | -------------------------------------------------------------------------------- /pack.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | import py2exe 3 | import sys 4 | 5 | 6 | #this allows to run it with a simple double click. 7 | sys.argv.append('py2exe') 8 | 9 | py2exe_options = { 10 | "includes": ["sip","PyQt4.QtCore","PyQt4.QtGui"], 11 | "dll_excludes": ["MSVCP90.dll"], 12 | "compressed": 1, 13 | "optimize": 2, 14 | "ascii": 0, 15 | "bundle_files": 0, 16 | } 17 | 18 | setup( 19 | name = 'IDE', 20 | version = '1.0', 21 | windows = [{"script":'uPyCraft.py', 22 | "icon_resources": [(1,"./images/logo.ico")] 23 | }], 24 | zipfile = None, 25 | 26 | options = {'py2exe': py2exe_options} 27 | ) -------------------------------------------------------------------------------- /pyflakesChange/api.py: -------------------------------------------------------------------------------- 1 | """ 2 | API for the command-line I{pyflakes} tool. 3 | """ 4 | from __future__ import with_statement 5 | 6 | import sys 7 | import os 8 | import _ast 9 | 10 | from pyflakes import checker, __version__ 11 | from pyflakes import reporter as modReporter 12 | 13 | __all__ = ['check', 'checkPath', 'checkRecursive', 'iterSourceCode', 'main'] 14 | 15 | 16 | def check(codeString, filename, reporter=None): 17 | """ 18 | Check the Python source given by C{codeString} for flakes. 19 | 20 | @param codeString: The Python source to check. 21 | @type codeString: C{str} 22 | 23 | @param filename: The name of the file the source came from, used to report 24 | errors. 25 | @type filename: C{str} 26 | 27 | @param reporter: A L{Reporter} instance, where errors and warnings will be 28 | reported. 29 | 30 | @return: The number of warnings emitted. 31 | @rtype: C{int} 32 | """ 33 | if reporter is None: 34 | reporter = modReporter._makeDefaultReporter() 35 | # First, compile into an AST and handle syntax errors. 36 | try: 37 | tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST) 38 | except SyntaxError: 39 | value = sys.exc_info()[1] 40 | msg = value.args[0] 41 | 42 | (lineno, offset, text) = value.lineno, value.offset, value.text 43 | 44 | if checker.PYPY: 45 | if text is None: 46 | lines = codeString.splitlines() 47 | if len(lines) >= lineno: 48 | text = lines[lineno - 1] 49 | if sys.version_info >= (3, ) and isinstance(text, bytes): 50 | try: 51 | text = text.decode('ascii') 52 | except UnicodeDecodeError: 53 | text = None 54 | offset -= 1 55 | 56 | # If there's an encoding problem with the file, the text is None. 57 | if text is None: 58 | # Avoid using msg, since for the only known case, it contains a 59 | # bogus message that claims the encoding the file declared was 60 | # unknown. 61 | reporter.unexpectedError(filename, 'problem decoding source') 62 | else: 63 | reporter.syntaxError(filename, msg, lineno, offset, text) 64 | return 1 65 | except Exception: 66 | reporter.unexpectedError(filename, 'problem decoding source') 67 | return 1 68 | # Okay, it's syntactically valid. Now check it. 69 | w = checker.Checker(tree, filename) 70 | w.messages.sort(key=lambda m: m.lineno) 71 | for warning in w.messages: 72 | reporter.flake(warning) 73 | return len(w.messages) 74 | 75 | 76 | def checkPath(filename, reporter=None): 77 | """ 78 | Check the given path, printing out any warnings detected. 79 | 80 | @param reporter: A L{Reporter} instance, where errors and warnings will be 81 | reported. 82 | 83 | @return: the number of warnings printed 84 | """ 85 | if reporter is None: 86 | reporter = modReporter._makeDefaultReporter() 87 | try: 88 | # in Python 2.6, compile() will choke on \r\n line endings. In later 89 | # versions of python it's smarter, and we want binary mode to give 90 | # compile() the best opportunity to do the right thing WRT text 91 | # encodings. 92 | if sys.version_info < (2, 7): 93 | mode = 'rU' 94 | else: 95 | mode = 'rb' 96 | 97 | with open(filename, mode) as f: 98 | codestr = f.read() 99 | if sys.version_info < (2, 7): 100 | codestr += '\n' # Work around for Python <= 2.6 101 | except UnicodeError: 102 | reporter.unexpectedError(filename, 'problem decoding source') 103 | return 1 104 | except IOError: 105 | msg = sys.exc_info()[1] 106 | reporter.unexpectedError(filename, msg.args[1]) 107 | return 1 108 | return check(codestr, filename, reporter) 109 | 110 | 111 | def iterSourceCode(paths): 112 | """ 113 | Iterate over all Python source files in C{paths}. 114 | 115 | @param paths: A list of paths. Directories will be recursed into and 116 | any .py files found will be yielded. Any non-directories will be 117 | yielded as-is. 118 | """ 119 | for path in paths: 120 | if os.path.isdir(path): 121 | for dirpath, dirnames, filenames in os.walk(path): 122 | for filename in filenames: 123 | if filename.endswith('.py'): 124 | yield os.path.join(dirpath, filename) 125 | else: 126 | yield path 127 | 128 | 129 | def checkRecursive(paths, reporter): 130 | """ 131 | Recursively check all source files in C{paths}. 132 | 133 | @param paths: A list of paths to Python source files and directories 134 | containing Python source files. 135 | @param reporter: A L{Reporter} where all of the warnings and errors 136 | will be reported to. 137 | @return: The number of warnings found. 138 | """ 139 | warnings = 0 140 | for sourcePath in iterSourceCode(paths): 141 | warnings += checkPath(sourcePath, reporter) 142 | return warnings 143 | 144 | 145 | def _exitOnSignal(sigName, message): 146 | """Handles a signal with sys.exit. 147 | 148 | Some of these signals (SIGPIPE, for example) don't exist or are invalid on 149 | Windows. So, ignore errors that might arise. 150 | """ 151 | import signal 152 | 153 | try: 154 | sigNumber = getattr(signal, sigName) 155 | except AttributeError: 156 | # the signal constants defined in the signal module are defined by 157 | # whether the C library supports them or not. So, SIGPIPE might not 158 | # even be defined. 159 | return 160 | 161 | def handler(sig, f): 162 | sys.exit(message) 163 | 164 | try: 165 | signal.signal(sigNumber, handler) 166 | except ValueError: 167 | # It's also possible the signal is defined, but then it's invalid. In 168 | # this case, signal.signal raises ValueError. 169 | pass 170 | 171 | 172 | def main(prog=None, args=None): 173 | """Entry point for the script "pyflakes".""" 174 | import optparse 175 | argsSave=[] 176 | argsSave.append(args) 177 | args=None 178 | 179 | # Handle "Keyboard Interrupt" and "Broken pipe" gracefully 180 | _exitOnSignal('SIGINT', '... stopped') 181 | _exitOnSignal('SIGPIPE', 1) 182 | 183 | parser = optparse.OptionParser(prog=prog, version=__version__) 184 | (__, args) = parser.parse_args(args=args) 185 | reporter = modReporter._makeDefaultReporter() 186 | 187 | args=argsSave 188 | #print __ 189 | #print args 190 | if args: 191 | warnings = checkRecursive(args, reporter) 192 | return 193 | else: 194 | warnings = check(sys.stdin.read(), '', reporter) 195 | raise SystemExit(warnings > 0) 196 | ''' 197 | def main(prog=None, args=None): 198 | """Entry point for the script "pyflakes".""" 199 | import optparse 200 | # Handle "Keyboard Interrupt" and "Broken pipe" gracefully 201 | _exitOnSignal('SIGINT', '... stopped') 202 | _exitOnSignal('SIGPIPE', 1) 203 | 204 | parser = optparse.OptionParser(prog=prog, version=__version__) 205 | (__, args) = parser.parse_args(args=args) 206 | reporter = modReporter._makeDefaultReporter() 207 | 208 | if args: 209 | warnings = checkRecursive(args, reporter) 210 | else: 211 | warnings = check(sys.stdin.read(), '', reporter) 212 | raise SystemExit(warnings > 0) 213 | ''' -------------------------------------------------------------------------------- /readWriteUart.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import time 6 | import threading 7 | 8 | from PyQt4.QtCore import * 9 | from PyQt4.QtGui import * 10 | 11 | class readWriteUart(QThread): 12 | def __init__(self,queue,parent): 13 | super(readWriteUart,self).__init__(parent) 14 | self.ui=parent 15 | self.model="" 16 | self.writemsg="" 17 | self.lastmodel="" 18 | self.queue=queue 19 | self.maybeCN=b"" 20 | self.currentBoard="esp32" 21 | self.connect(self.ui,SIGNAL("changeCurrentBoard"),self.changeCurrentBoard) 22 | 23 | def run(self): 24 | readNum=0 25 | sendData="" 26 | execSendData="" 27 | self.maybeCN=b"" 28 | while True: 29 | if self.ui.myserial.ser.isOpen(): 30 | if not self.queue.empty(): 31 | cmd=self.queue.get() 32 | print("cmd=%s"%cmd) 33 | if cmd.find(":::")>=0: 34 | cmd=cmd.split(":::") 35 | self.model=cmd[0] 36 | if type(cmd[1]) is bytes: 37 | self.writemsg=cmd[1] 38 | elif type(cmd[1]) is str: 39 | self.writemsg=cmd[1].encode('utf-8') 40 | else: 41 | self.model=cmd 42 | self.writemsg="" 43 | 44 | if self.model=="close": 45 | self.lastmodel="" 46 | self.model="" 47 | break 48 | elif self.model=="uitouart": 49 | if self.writemsg.decode()=="\x03": 50 | self.lastmodel="" 51 | elif self.lastmodel=="exec_": 52 | self.emit(SIGNAL("uiRecvFromUart"),"program is running,do anything with stop it!1\n") 53 | continue 54 | try: 55 | self.ui.myserial.ser.write(self.writemsg) 56 | if self.currentBoard != "microbit": 57 | self.ui.myserial.ser.flush() 58 | except Exception: 59 | self.lastmodel="" 60 | self.model="" 61 | break 62 | elif self.model=="ctrltouart": 63 | if self.lastmodel=="exec_": 64 | self.emit(SIGNAL("uiRecvFromUart"),"program is running,do anything with stop it!2\n") 65 | self.model="uitouart" 66 | continue 67 | try: 68 | self.ui.myserial.ser.write(self.writemsg) 69 | if self.currentBoard != "microbit": 70 | self.ui.myserial.ser.flush() 71 | except Exception: 72 | self.lastmodel="" 73 | self.model="" 74 | break 75 | elif self.model=="exec_": 76 | if self.lastmodel=="exec_": 77 | self.emit(SIGNAL("uiRecvFromUart"),"program is running,do anything with stop it!3\n") 78 | self.model="uitouart" 79 | continue 80 | self.lastmodel="exec_" 81 | try: 82 | self.ui.myserial.ser.write(self.writemsg) 83 | if self.currentBoard != "microbit": 84 | self.ui.myserial.ser.flush() 85 | except Exception: 86 | self.lastmodel="" 87 | self.model="" 88 | break 89 | 90 | if self.model=="" or self.model=="uitouart": 91 | try: 92 | data=self.ui.myserial.ser.read(1) 93 | except Exception as e: 94 | break 95 | if data==b'': 96 | continue 97 | if ord(data)>127: 98 | pass 99 | else: 100 | data=data.decode() 101 | if self.lastmodel=="exec_": 102 | execSendData+=str(data) 103 | if execSendData.find(">")<0: 104 | execSendData="" 105 | elif execSendData.find(">>> ")>=0: 106 | execSendData="" 107 | self.lastmodel="" 108 | 109 | self.emit(SIGNAL("uiRecvFromUart"),data) 110 | 111 | #if self.ui.myserial.ser.inWaiting()>=128: 112 | # self.ui.myserial.ser.flushInput() 113 | elif self.model=="exec_": 114 | try: 115 | data=self.ui.myserial.ser.read(1) 116 | except Exception: 117 | break 118 | try: 119 | data=data.decode() 120 | except Exception as e: 121 | print(e) 122 | execSendData+=str(data) 123 | if execSendData.find(">")<0: 124 | execSendData="" 125 | elif execSendData.find(">>> ")>=0: 126 | execSendData="" 127 | self.lastmodel="" 128 | self.emit(SIGNAL("uiRecvFromUart"),data) 129 | if self.ui.myserial.ser.inWaiting()>=128: 130 | self.ui.myserial.ser.flushInput() 131 | elif self.model=="ctrltouart": 132 | try: 133 | data=self.ui.myserial.ser.read(10) 134 | except Exception: 135 | break 136 | 137 | if len(data)>2: 138 | if str(data[-2:-1]).find("b'\\xe")>=0: 139 | time.sleep(0.001) 140 | recv=self.ui.myserial.ser.read(1) 141 | if recv==b'': 142 | data=data[0:-2] 143 | else: 144 | data+=recv 145 | elif str(data[-1:]).find("b'\\xe")>=0: 146 | time.sleep(0.001) 147 | recv=self.ui.myserial.ser.read(2) 148 | if recv==b'' or len(recv)!=2: 149 | data=data[0:-1] 150 | else: 151 | data+=recv 152 | else: 153 | pass 154 | elif len(data)==2: 155 | if str(data[0:1]).find("b'\\xe")>=0: 156 | time.sleep(0.001) 157 | recv=self.ui.myserial.ser.read(1) 158 | if recv==b'': 159 | data=data[0:-2] 160 | else: 161 | data+=recv 162 | elif str(data[1:]).find("b'\\xe")>=0: 163 | time.sleep(0.001) 164 | recv=self.ui.myserial.ser.read(2) 165 | if recv==b'' or len(recv)!=2: 166 | data=data[0:-1] 167 | else: 168 | data+=recv 169 | else: 170 | if data==b'': 171 | pass 172 | else: 173 | if str(data).find("b'\\xe")>=0: 174 | time.sleep(0.001) 175 | recv=self.ui.myserial.ser.read(2) 176 | if recv==b'' or len(recv)!=2: 177 | data=data[0:-1] 178 | else: 179 | data+=recv 180 | 181 | 182 | if self.maybeCN!=b'': 183 | data=self.maybeCN+data 184 | try: 185 | data=data.decode() 186 | self.maybeCN=b'' 187 | except Exception as e: 188 | #print("data:%s"%data) 189 | if len(self.maybeCN)>=3: 190 | self.maybeCN=b'' 191 | continue 192 | self.maybeCN=data 193 | continue 194 | self.maybeCN=b'' 195 | 196 | 197 | if data=="" or data==None: 198 | readNum+=1 199 | if readNum==6: 200 | self.emit(SIGNAL("ctrlRecvUartMsg"),sendData) 201 | sendData="" 202 | readNum=0 203 | else: 204 | sendData+=data 205 | readNum=0 206 | else: 207 | self.emit(SIGNAL("uiRecvFromUart"),"error read model") 208 | 209 | else: 210 | time.sleep(0.01) 211 | 212 | print("class read out") 213 | self.lastmodel="" 214 | self.model="" 215 | self.exit() 216 | 217 | def changeCurrentBoard(self,board): 218 | self.currentBoard=board 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | images/clear.png 5 | images/serialClose.png 6 | images/serialConnect.png 7 | images/downloadAndRun.png 8 | images/fileOpen.png 9 | images/ic.png 10 | images/logo.ico 11 | images/logo.png 12 | images/newFile.png 13 | images/pc.png 14 | images/redo.png 15 | images/save.png 16 | images/stop.png 17 | images/undo.png 18 | images/syntaxCheck.png 19 | images/tabClose.png 20 | images/tabCloseHover.png 21 | images/treeFileOpen.png 22 | images/treeMenuClosed.png 23 | images/treeBranchClose.png 24 | images/treeBranchOpen.png 25 | 26 | -------------------------------------------------------------------------------- /threadDownloadFirmware.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import time 6 | import threading 7 | import Esp 8 | import urllib 9 | from urllib import request 10 | import socket 11 | import shutil 12 | import codecs 13 | 14 | #from PyQt4 import QtGui, QtCore 15 | from PyQt4.QtCore import * 16 | from PyQt4.QtGui import * 17 | 18 | 19 | class threadUserFirmware(QThread): 20 | def __init__(self, board, savepath, com, iserase, size, addr, parent): 21 | super(threadUserFirmware,self).__init__(parent) 22 | 23 | self.board=board 24 | self.savepath=savepath 25 | self.com=com 26 | self.iserase=iserase 27 | self.size=size 28 | self.erasePer=0 29 | self.erasestart=False 30 | self.erasetimer=None 31 | self.burnaddr=0 32 | if addr=="0x0": 33 | self.burnaddr=0 34 | else: 35 | self.burnaddr=0x1000 36 | 37 | print("burnaddr=====%d"%self.burnaddr) 38 | 39 | def run(self): 40 | esptool=Esp.ESPTool() 41 | self.connect(esptool,SIGNAL("percentchange"),self.updateFirmwarePer) 42 | self.connect(esptool,SIGNAL("eraseStart"),self.eraseStart) 43 | 44 | if self.iserase=="yes": 45 | self.erasetimer=threading.Timer(0.1,self.eraseTimer) 46 | self.erasetimer.start() 47 | try: 48 | Esp.Burn(esptool,str(self.board),self.savepath,self.com,True) 49 | time.sleep(1) 50 | self.erasePer=100 51 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 52 | self.erasetimer.cancel() 53 | except: 54 | time.sleep(1) 55 | self.erasePer=-1 56 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 57 | self.erasetimer.cancel() 58 | self.erasestart=False 59 | self.exit() 60 | return 61 | 62 | if self.iserase=="yes": 63 | self.emit(SIGNAL("firmwareAnyErase"),100) 64 | try: 65 | if self.board=="esp32" or self.board=="esp8266" or self.board=="TPYBoardV202": 66 | Esp.Burn(esptool,str(self.board),self.savepath,self.com,False,self.burnaddr) 67 | else:#microbit 68 | print("In threaddownloadfirmware:savepath=%s"%self.savepath) 69 | self.emit(SIGNAL("firmwareAnyUpdate"),-2) 70 | time.sleep(0.5) 71 | self.emit(SIGNAL("goMicrobitUpdate")) 72 | except: 73 | self.emit(SIGNAL("firmwareAnyUpdate"),-1) 74 | self.exit() 75 | return 76 | if self.board=="esp8266": 77 | Esp.downOkReset() 78 | 79 | self.exit() 80 | 81 | def cbdownFramware(self,blocknum,blocksize,totalsize): 82 | print(blocknum) 83 | print(blocksize) 84 | print(totalsize) 85 | 86 | per=100.0*blocknum*blocksize/self.size 87 | if per>=100: 88 | per=100 89 | self.emit(SIGNAL("firmwareAnyDown"),per) 90 | return 91 | 92 | self.emit(SIGNAL("firmwareAnyDown"),per) 93 | 94 | def updateFirmwarePer(self,per): 95 | print("updateFirmwarePer:%d"%per) 96 | self.emit(SIGNAL("firmwareAnyUpdate"),per) 97 | 98 | def eraseStart(self): 99 | self.erasestart=True 100 | 101 | def eraseTimer(self): 102 | if self.erasestart==True: 103 | self.erasePer+=0.5 104 | 105 | if self.erasePer>=99: 106 | self.erasePer=99 107 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 108 | self.erasestart=False 109 | return 110 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 111 | 112 | self.erasetimer=threading.Timer(0.1,self.eraseTimer) 113 | self.erasetimer.start() 114 | 115 | class threadDownloadFirmware(QThread): 116 | def __init__(self, url, board, savepath, com, iserase, size, addr, parent): 117 | super(threadDownloadFirmware,self).__init__(parent) 118 | self.url=url 119 | self.board=board 120 | self.savepath=savepath 121 | self.com=com 122 | self.iserase=iserase 123 | self.size=size 124 | self.erasePer=0 125 | self.reDownloadNum=0 126 | self.downloadOk=False 127 | self.erasestart=False 128 | 129 | self.erasetimer=None 130 | 131 | self.burnaddr=0 132 | if addr=="0x0": 133 | self.burnaddr=0 134 | else: 135 | self.burnaddr=0x1000 136 | 137 | print("burnaddr2=====%d"%self.burnaddr) 138 | 139 | 140 | def run(self): 141 | self.reDownload() 142 | if self.downloadOk==True: 143 | 144 | esptool=Esp.ESPTool() 145 | self.connect(esptool,SIGNAL("percentchange"),self.updateFirmwarePer) 146 | self.connect(esptool,SIGNAL("eraseStart"),self.eraseStart) 147 | 148 | if self.iserase=="yes": 149 | self.erasetimer=threading.Timer(0.1,self.eraseTimer) 150 | self.erasetimer.start() 151 | try: 152 | Esp.Burn(esptool,str(self.board),self.savepath,self.com,True) 153 | time.sleep(1) 154 | self.erasePer=100 155 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 156 | self.erasetimer.cancel() 157 | except: 158 | time.sleep(1) 159 | self.erasePer=-1 160 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 161 | self.erasetimer.cancel() 162 | self.erasestart=False 163 | self.exit() 164 | return 165 | 166 | if self.iserase=="yes": 167 | self.emit(SIGNAL("firmwareAnyErase"),100) 168 | try: 169 | if self.board=="esp32" or self.board=="esp8266" or self.board=="TPYBoardV202": 170 | Esp.Burn(esptool,str(self.board),self.savepath,self.com,False,self.burnaddr) 171 | else:#microbit 172 | print("In threaddownloadfirmware:savepath=%s"%self.savepath) 173 | self.emit(SIGNAL("firmwareAnyUpdate"),-2) 174 | time.sleep(0.5) 175 | self.emit(SIGNAL("goMicrobitUpdate")) 176 | except: 177 | self.emit(SIGNAL("firmwareAnyUpdate"),-1) 178 | self.exit() 179 | return 180 | if self.board=="esp8266" or self.board=="TPYBoardV202": 181 | Esp.downOkReset() 182 | 183 | self.exit() 184 | 185 | def reDownload(self): 186 | if self.reDownloadNum==3: 187 | self.downloadOk=False 188 | self.emit(SIGNAL("firmwareAnyDown"),-1) 189 | return 190 | try: 191 | socket.setdefaulttimeout(5) 192 | request.urlretrieve(self.url,self.savepath,self.cbdownFramware) 193 | self.downloadOk=True 194 | return 195 | except: 196 | print("urllib err :%s"%self.url) 197 | self.reDownloadNum+=1 198 | self.reDownload() 199 | 200 | 201 | 202 | def cbdownFramware(self,blocknum,blocksize,totalsize): 203 | print(blocknum) 204 | print(blocksize) 205 | print(totalsize) 206 | 207 | per=100.0*blocknum*blocksize/self.size 208 | if per>=100: 209 | per=100 210 | self.emit(SIGNAL("firmwareAnyDown"),per) 211 | return 212 | 213 | self.emit(SIGNAL("firmwareAnyDown"),per) 214 | 215 | def updateFirmwarePer(self,per): 216 | print("updateFirmwarePer:%d"%per) 217 | self.emit(SIGNAL("firmwareAnyUpdate"),per) 218 | 219 | def eraseStart(self): 220 | self.erasestart=True 221 | 222 | def eraseTimer(self): 223 | if self.erasestart==True: 224 | self.erasePer+=0.5 225 | 226 | if self.erasePer>=99: 227 | self.erasePer=99 228 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 229 | self.erasestart=False 230 | return 231 | self.emit(SIGNAL("firmwareAnyErase"),self.erasePer) 232 | 233 | self.erasetimer=threading.Timer(0.1,self.eraseTimer) 234 | self.erasetimer.start() 235 | -------------------------------------------------------------------------------- /updateNewFirmware.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | import sys 3 | import serial 4 | import serial.tools.list_ports 5 | import time 6 | 7 | from PyQt4.QtCore import * 8 | from PyQt4.QtGui import * 9 | 10 | class updateNewFirmwareBar(QDialog): 11 | def __init__(self,windowname,isErase,isUPY,parent=None): 12 | super(updateNewFirmwareBar,self).__init__(parent) 13 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 14 | 15 | self.setWindowTitle(windowname) 16 | self.setWindowIcon(QIcon(':/logo.png')) 17 | 18 | self.updateLabel=QLabel(self.tr("Burn")) 19 | self.updateBar=QProgressBar(self) 20 | self.updateBar.setStyleSheet("""QProgressBar::chunk{background-color: qlineargradient( x1: 0, x2: 1,stop: 0 #FF4E50, stop: 1 #FFBE2B);}""") 21 | self.updateBar.setTextVisible(False) 22 | self.updateBarLabel=QLabel(self.tr("0%")) 23 | self.updateBarLabel.setStyleSheet("color:red;") 24 | 25 | self.isUPY=isUPY 26 | if isUPY: 27 | self.downloadLabel=QLabel(self.tr("Download")) 28 | self.downloadBar=QProgressBar(self) 29 | self.downloadBar.setStyleSheet("""QProgressBar::chunk{background-color: qlineargradient( x1: 0, x2: 1,stop: 0 #FF4E50, stop: 1 #FFBE2B);}""") 30 | self.downloadBar.setTextVisible(False) 31 | self.downloadBarLable=QLabel(self.tr("0%")) 32 | self.downloadBarLable.setStyleSheet("color:red;") 33 | 34 | self.erasePer=0 35 | 36 | detailLayout=QWidget() 37 | layout = QGridLayout(detailLayout) 38 | 39 | if isErase: 40 | self.eraseBar=QProgressBar(self) 41 | self.eraseLabel=QLabel(self.tr("EraseFlash")) 42 | self.eraseBar.setStyleSheet("""QProgressBar::chunk{background-color: qlineargradient( x1: 0, x2: 1,stop: 0 #FF4E50, stop: 1 #FFBE2B);}""") 43 | self.eraseBar.setTextVisible(False) 44 | self.eraseLabelLabel=QLabel(self.tr("0%")) 45 | self.eraseLabelLabel.setStyleSheet("color:red;") 46 | 47 | if self.isUPY==True: 48 | layout.addWidget(self.downloadLabel,0,0) 49 | layout.addWidget(self.downloadBar,0,1) 50 | layout.addWidget(self.downloadBarLable,0,2) 51 | 52 | layout.addWidget(self.eraseLabel,1,0) 53 | layout.addWidget(self.eraseBar,1,1) 54 | layout.addWidget(self.eraseLabelLabel,1,2) 55 | 56 | layout.addWidget(self.updateLabel,2,0) 57 | layout.addWidget(self.updateBar,2,1) 58 | layout.addWidget(self.updateBarLabel,2,2) 59 | else: 60 | layout.addWidget(self.eraseLabel,0,0) 61 | layout.addWidget(self.eraseBar,0,1) 62 | layout.addWidget(self.eraseLabelLabel,0,2) 63 | 64 | layout.addWidget(self.updateLabel,1,0) 65 | layout.addWidget(self.updateBar,1,1) 66 | layout.addWidget(self.updateBarLabel,1,2) 67 | self.resize(600,150) 68 | else: 69 | if self.isUPY==True: 70 | layout.addWidget(self.downloadLabel,0,0) 71 | layout.addWidget(self.downloadBar,0,1) 72 | layout.addWidget(self.downloadBarLable,0,2) 73 | 74 | layout.addWidget(self.updateLabel,1,0) 75 | layout.addWidget(self.updateBar,1,1) 76 | layout.addWidget(self.updateBarLabel,1,2) 77 | else: 78 | layout.addWidget(self.updateLabel,0,0) 79 | layout.addWidget(self.updateBar,0,1) 80 | layout.addWidget(self.updateBarLabel,0,2) 81 | self.resize(600,100) 82 | 83 | self.setLayout(layout) 84 | 85 | 86 | def downloadEvent(self,per): 87 | if per>=100: 88 | per=100 89 | self.downloadBar.setValue(per) 90 | self.downloadBarLable.setText(self.tr("%d"%int(per)+"%")) 91 | return 92 | self.downloadBar.setValue(per) 93 | self.downloadBarLable.setText(self.tr("%d"%int(per)+"%")) 94 | 95 | 96 | def eraseEvent(self,per): 97 | if per>=100: 98 | per=100 99 | self.eraseBar.setValue(per) 100 | self.eraseLabelLabel.setText(self.tr("%d"%int(per)+"%")) 101 | return 102 | self.eraseBar.setValue(per) 103 | self.eraseLabelLabel.setText(self.tr("%d"%int(per)+"%")) 104 | 105 | def updateEvent(self,per): 106 | if per>=100: 107 | per=100 108 | self.updateBar.setValue(per) 109 | self.updateBarLabel.setText(self.tr("%d"%int(per)+"%")) 110 | self.close() 111 | return 112 | self.updateBar.setValue(per) 113 | self.updateBarLabel.setText(self.tr("%d"%int(per)+"%")) 114 | 115 | class updateNewFirmware(QDialog): 116 | def __init__(self,windowname,isAuto=False,parent=None): 117 | super(updateNewFirmware,self).__init__(parent) 118 | self.setWindowFlags(Qt.WindowCloseButtonHint)#HelpButtonHint? 119 | self.setWindowTitle(windowname) 120 | self.setWindowIcon(QIcon(':/logo.png')) 121 | self.setStyleSheet("""QDialog{background-color: rgb(236, 236, 236);color:black;} 122 | QPushButton{background-color:rgb(253,97,72);color:white;} 123 | QPushButton:hover{background-color:rgb(212,212,212);color:black;} 124 | """) 125 | self.isAuto=isAuto 126 | if self.isAuto: 127 | Com_List=[] 128 | port_list = list(serial.tools.list_ports.comports()) 129 | for port in port_list: 130 | Com_List.append(port[0]) 131 | 132 | self.comLabel=QLabel(self.tr("com")) 133 | self.comChoose=QComboBox() 134 | self.comChoose.addItems(Com_List) 135 | 136 | self.okButton=QPushButton(self.tr("ok")) 137 | self.cancelButton=QPushButton(self.tr("cancel")) 138 | 139 | self.boardLabel=QLabel(self.tr("board")) 140 | self.boardComboBox=QComboBox() 141 | self.boardComboBox.addItems(["esp8266","TPYBoardV202","esp32","microbit"]) 142 | self.boardComboBox.setCurrentIndex(2) 143 | 144 | self.burnAddrLabel=QLabel(self.tr("burn_addr")) 145 | self.burnAddrComboBox=QComboBox() 146 | self.burnAddrComboBox.addItems(["0x0","0x1000"]) 147 | self.burnAddrComboBox.setCurrentIndex(0) 148 | 149 | self.eraseflashLabel=QLabel(self.tr("erase_flash")) 150 | self.eraseComboBox=QComboBox() 151 | self.eraseComboBox.addItems(["yes","no"]) 152 | self.eraseComboBox.setCurrentIndex(1) 153 | 154 | 155 | self.myGroupBox = QGroupBox(self.tr("Firmware Choose")) 156 | 157 | self.detailWidget=QWidget() 158 | layout = QGridLayout(self.detailWidget) 159 | ######### 160 | self.myGroupBox = QGroupBox(self.tr("Firmware Choose")) 161 | 162 | self.myGroupBoxLayout = QGridLayout() 163 | 164 | self.firmwareTip=QLabel(self.tr("Firmware Choose")) 165 | self.radioUPY=QRadioButton("uPyCraft") 166 | self.radioUser=QRadioButton("Users") 167 | self.firmwareName=QLineEdit() 168 | self.chooseFirmwareButton=QPushButton(self.tr("choose")) 169 | 170 | self.myGroupBoxLayout.addWidget(self.radioUPY,0,0) 171 | self.myGroupBoxLayout.addWidget(self.radioUser,1,0) 172 | self.myGroupBoxLayout.addWidget(self.firmwareName,1,1) 173 | self.myGroupBoxLayout.addWidget(self.chooseFirmwareButton,1,2) 174 | 175 | self.myGroupBox.setLayout(self.myGroupBoxLayout) 176 | ######### 177 | 178 | if isAuto: 179 | layout.addWidget(self.boardLabel,0,0) 180 | layout.addWidget(self.boardComboBox,0,2) 181 | 182 | layout.addWidget(self.burnAddrLabel,1,0) 183 | layout.addWidget(self.burnAddrComboBox,1,2) 184 | 185 | layout.addWidget(self.eraseflashLabel,2,0) 186 | layout.addWidget(self.eraseComboBox,2,2) 187 | 188 | layout.addWidget(self.comLabel,3,0) 189 | layout.addWidget(self.comChoose,3,2) 190 | 191 | layout.addWidget(self.myGroupBox,4,0,2,3) 192 | 193 | layout.addWidget(self.okButton,7,0) 194 | layout.addWidget(self.cancelButton,7,2) 195 | else: 196 | layout.addWidget(self.boardLabel,0,0) 197 | layout.addWidget(self.boardComboBox,0,2) 198 | 199 | layout.addWidget(self.burnAddrLabel,1,0) 200 | layout.addWidget(self.burnAddrComboBox,1,2) 201 | 202 | layout.addWidget(self.eraseflashLabel,2,0) 203 | layout.addWidget(self.eraseComboBox,2,2) 204 | 205 | layout.addWidget(self.myGroupBox,3,0,2,3) 206 | 207 | layout.addWidget(self.okButton,6,0) 208 | layout.addWidget(self.cancelButton,6,2) 209 | 210 | self.radioUPY.setChecked(True) 211 | self.firmwareName.setEnabled(False) 212 | self.chooseFirmwareButton.setVisible(False) 213 | 214 | if self.boardComboBox.currentText()=="microbit": 215 | self.eraseComboBox.setCurrentIndex(1)# for erase:0 yes,1 no 216 | self.eraseComboBox.setEnabled(False) 217 | else: 218 | self.eraseComboBox.setEnabled(True) 219 | 220 | if self.boardComboBox.currentText()=="esp32": 221 | self.burnAddrComboBox.setCurrentIndex(0) 222 | self.burnAddrComboBox.setEnabled(True) 223 | else: 224 | self.burnAddrComboBox.setEnabled(False) 225 | 226 | self.resize(450,200) 227 | self.setLayout(layout) 228 | 229 | self.connect(self.okButton,SIGNAL("clicked()"),self.chooseOk) 230 | self.connect(self.cancelButton,SIGNAL("clicked()"),self.chooseCancel) 231 | self.connect(self.boardComboBox,SIGNAL("activated(int)"),self.boardChange) 232 | self.connect(self.radioUPY,SIGNAL("toggled(bool)"),self.radioUPYChanged) 233 | self.connect(self.radioUser,SIGNAL("toggled(bool)"),self.radioUserChanged) 234 | 235 | def radioUPYChanged(self,choosed): 236 | if choosed: 237 | self.firmwareName.clear() 238 | self.firmwareName.setEnabled(False) 239 | self.chooseFirmwareButton.setVisible(False) 240 | 241 | def radioUserChanged(self,choosed): 242 | if choosed: 243 | self.firmwareName.setEnabled(True) 244 | self.chooseFirmwareButton.setVisible(True) 245 | 246 | 247 | def boardChange(self,item): 248 | print(self.boardComboBox.currentText()) 249 | if self.boardComboBox.currentText()=="microbit": 250 | self.eraseComboBox.setCurrentIndex(1)# for erase:0 yes,1 no 251 | self.eraseComboBox.setEnabled(False) 252 | else: 253 | self.eraseComboBox.setCurrentIndex(0) 254 | self.eraseComboBox.setEnabled(True) 255 | 256 | if self.boardComboBox.currentText()=="esp32": 257 | self.burnAddrComboBox.setCurrentIndex(0) 258 | self.burnAddrComboBox.setEnabled(True) 259 | else: 260 | self.burnAddrComboBox.setCurrentIndex(0) 261 | self.burnAddrComboBox.setEnabled(False) 262 | 263 | def chooseOk(self): 264 | self.close() 265 | 266 | def chooseCancel(self): 267 | self.close() 268 | 269 | 270 | #app=QApplication(sys.argv) 271 | #main=updateNewFirmware("test") 272 | #main.show() 273 | #app.exec_() 274 | --------------------------------------------------------------------------------