├── 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 |
--------------------------------------------------------------------------------