Started implementing the MicroPython support. micropython

Sun, 07 Jul 2019 18:48:17 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 07 Jul 2019 18:48:17 +0200
branch
micropython
changeset 7054
fb84d8489bc1
parent 7053
f0a7469a2ad4
child 7058
bdd583f96e96

Started implementing the MicroPython support.

eric6.e4p file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonDevices.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonReplWidget.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonReplWidget.ui file | annotate | diff | comparison | revisions
eric6/MicroPython/__init__.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/InterfacePage.py file | annotate | diff | comparison | revisions
eric6/Preferences/ConfigurationPages/InterfacePage.ui file | annotate | diff | comparison | revisions
eric6/Preferences/__init__.py file | annotate | diff | comparison | revisions
eric6/UI/UserInterface.py file | annotate | diff | comparison | revisions
eric6/icons/default/adafruitDevice.png file | annotate | diff | comparison | revisions
eric6/icons/default/chart.svg file | annotate | diff | comparison | revisions
eric6/icons/default/disconnect.svg file | annotate | diff | comparison | revisions
eric6/icons/default/esp32Device.png file | annotate | diff | comparison | revisions
eric6/icons/default/filemanager.svg file | annotate | diff | comparison | revisions
eric6/icons/default/microbitDevice.png file | annotate | diff | comparison | revisions
eric6/icons/default/micropython.png file | annotate | diff | comparison | revisions
eric6/icons/default/micropython48.png file | annotate | diff | comparison | revisions
eric6/icons/default/question.svg file | annotate | diff | comparison | revisions
eric6/icons/default/start.svg file | annotate | diff | comparison | revisions
eric6/icons/default/terminal.svg file | annotate | diff | comparison | revisions
--- a/eric6.e4p	Sun Jul 07 14:58:07 2019 +0200
+++ b/eric6.e4p	Sun Jul 07 18:48:17 2019 +0200
@@ -454,6 +454,9 @@
     <Source>eric6/IconEditor/__init__.py</Source>
     <Source>eric6/IconEditor/cursors/__init__.py</Source>
     <Source>eric6/IconEditor/cursors/cursors_rc.py</Source>
+    <Source>eric6/MicroPython/MicroPythonDevices.py</Source>
+    <Source>eric6/MicroPython/MicroPythonReplWidget.py</Source>
+    <Source>eric6/MicroPython/__init__.py</Source>
     <Source>eric6/MultiProject/AddProjectDialog.py</Source>
     <Source>eric6/MultiProject/MultiProject.py</Source>
     <Source>eric6/MultiProject/MultiProjectBrowser.py</Source>
@@ -1832,6 +1835,7 @@
     <Form>eric6/HexEdit/HexEditReplaceWidget.ui</Form>
     <Form>eric6/HexEdit/HexEditSearchWidget.ui</Form>
     <Form>eric6/IconEditor/IconSizeDialog.ui</Form>
+    <Form>eric6/MicroPython/MicroPythonReplWidget.ui</Form>
     <Form>eric6/MultiProject/AddProjectDialog.ui</Form>
     <Form>eric6/MultiProject/PropertiesDialog.ui</Form>
     <Form>eric6/Network/IRC/IrcChannelEditDialog.ui</Form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/MicroPython/MicroPythonDevices.py	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing some utility functions and the MicroPythonDevice base
+class.
+"""
+
+from __future__ import unicode_literals
+
+import logging
+
+from PyQt5.QtCore import QObject
+
+import Globals
+import UI.PixmapCache
+
+
+SupportedBoards = {
+    "esp": {
+        "ids": [
+            (0x1A86, 0x7523),       # HL-340
+            (0x10C4, 0xEA60),       # CP210x
+            (0x0403, 0x6015),       # Sparkfun ESP32 VID, PID
+        ],
+        "description": "ESP8266, ESP32",
+        "icon": "esp32Device",
+    },
+    
+    "adafruit": {
+        "ids": [
+            (0x239A, 0x8015),       # Adafruit Feather M0 CircuitPython
+            (0x239A, 0x8023),       # Adafruit Feather M0 Express CircuitPython
+            (0x239A, 0x801B),       # Adafruit Feather M0 Express CircuitPython
+            (0x239A, 0x8014),       # Adafruit Metro M0 CircuitPython
+            (0x239A, 0x8019),       # Adafruit CircuitPlayground
+                                    #   Express CircuitPython
+            (0x239A, 0x801D),       # Adafruit Gemma M0
+            (0x239A, 0x801F),       # Adafruit Trinket M0
+            (0x239A, 0x8012),       # Adafruit ItsyBitsy M0
+            (0x239A, 0x8021),       # Adafruit Metro M4
+            (0x239A, 0x8025),       # Adafruit Feather RadioFruit
+            (0x239A, 0x8026),       # Adafruit Feather M4
+            (0x239A, 0x8028),       # Adafruit pIRKey M0
+            (0x239A, 0x802A),       # Adafruit Feather 52840
+            (0x239A, 0x802C),       # Adafruit Itsy M4
+            (0x239A, 0x802E),       # Adafruit CRICKit M0
+            (0x239A, 0xD1ED),       # Adafruit HalloWing M0
+            (0x239A, 0x8030),       # Adafruit NeoTrellis M4
+            (0x239A, 0x8032),       # Grand Central
+            (0x2B04, 0xC00C),       # Particle Argon
+            (0x2B04, 0xC00D),       # Particle Boron
+            (0x2B04, 0xC00E),       # Particle Xenon
+            (0x239A, 0x8034),       # future board
+            (0x239A, 0x8036),       # future board
+            (0x239A, 0x8038),       # future board
+            (0x239A, 0x803A),       # future board
+            (0x239A, 0x803C),       # future board
+            (0x239A, 0x803E),       # future board
+            (0x239A, None),         # Any Adafruit Boards
+        ],
+        "description": "Adafruit CircuitPython",
+        "icon": "adafruitDevice",
+    },
+    
+    "bbc_microbit": {
+        "ids": [
+            (0x0D28, 0x0204),       # micro:bit USB VID, PID
+        ],
+        "description": "BBC micro:bit",
+        "icon": "microbitDevice",
+    },
+}
+
+
+def getSupportedDevices():
+    """
+    Function to get a list of supported MicroPython devices.
+    
+    @return set of tuples with the board type and description
+    @rtype set of tuples of (str, str)
+    """
+    boards = []
+    for board in SupportedBoards:
+        boards.append(
+            (board, SupportedBoards[board]["description"]))
+    return boards
+
+
+def getFoundDevices():
+    """
+    Function to check the serial ports for supported MicroPython devices.
+    
+    @return set of tuples with the board type, a description and the serial
+        port it is connected at
+    @rtype set of tuples of (str, str, str)
+    """
+    from PyQt5.QtSerialPort import QSerialPortInfo
+    
+    foundDevices = []
+    
+    availablePorts = QSerialPortInfo.availablePorts()
+    for port in availablePorts:
+        vid = port.vendorIdentifier()
+        pid = port.productIdentifier()
+        for board in SupportedBoards:
+            if ((vid, pid) in SupportedBoards[board]["ids"] or
+                    (vid, None) in SupportedBoards[board]["ids"]):
+                foundDevices.append(
+                    (board, SupportedBoards[board]["description"],
+                     port.portName()))
+                break
+        else:
+            logging.debug("Unknown device: (0x%04x:0x%04x)", vid, pid)
+    
+    return foundDevices
+
+
+def getDeviceIcon(boardName, iconFormat=True):
+    """
+    Function to get the icon for the given board.
+    
+    @param boardName name of the board
+    @type str
+    @param iconFormat flag indicating to get an icon or a pixmap
+    @type bool
+    @return icon for the board (iconFormat == True) or
+        a pixmap (iconFormat == False)
+    @rtype QIcon or QPixmap
+    """
+    if boardName in SupportedBoards:
+        iconName = SupportedBoards[boardName]["icon"]
+    else:
+        # return a generic MicroPython icon
+        iconName = "micropython48"
+    
+    if iconFormat:
+        return UI.PixmapCache.getIcon(iconName)
+    else:
+        return UI.PixmapCache.getPixmap(iconName)
+
+
+def getDevice(deviceType):
+    """
+    Public method to instantiate a specific MicroPython device interface.
+    
+    @param deviceType type of the device interface
+    @type str
+    @return instantiated device interface
+    @rtype MicroPythonDevice
+    """
+    # TODO: not implemented yet
+    return None
+
+
+class MicroPythonDevice(QObject):
+    """
+    Base class for the more specific MicroPython devices.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super(MicroPythonDevice, self).__init__(parent)
+    
+    def supportedActions(self):
+        """
+        Public method to get the names of the supported actions.
+        
+        @return tuple of supported actions out of "repl", "run", "files",
+            "chart"
+        @rtype tuple of str
+        """
+        return tuple()
+    
+    def findDevice(self, deviceType):
+        """
+        Public method to find the first device of a specific type.
+        
+        @param deviceType device type
+        @type str
+        @return tuple containing the port the device is connected to and its
+            serial number
+        @rtype tuple of (str, str)
+        """
+        from PyQt5.QtSerialPort import QSerialPortInfo
+        
+        availablePorts = QSerialPortInfo.availablePorts()
+        for port in availablePorts:
+            vid = port.vendorIdentifier()
+            pid = port.productIdentifier()
+            for board in SupportedBoards:
+                if ((vid, pid) in SupportedBoards[board] or
+                        (vid, None) in SupportedBoards[board]):
+                    portName = port.portName()
+                    serialNumber = port.serialNumber()
+                    return (self.__portPath(portName), serialNumber)
+        
+        return (None, None)
+    
+    def __portPath(self, portName):
+        """
+        Private method to get the full path of a given port.
+        
+        @param portName name of the port the path shall be determined for
+        @type str
+        @return full port path
+        @rtype str
+        """
+        if Globals.isWindowsPlatform():
+            # return name unchanged
+            return portName
+        else:
+            # assume Posix system (Linux or macOS)
+            return "/dev/{0}".format(portName)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/MicroPython/MicroPythonReplWidget.py	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,373 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the MicroPython REPL widget.
+"""
+
+from __future__ import unicode_literals
+
+import re
+
+from PyQt5.QtCore import pyqtSlot, Qt, QPoint, QEvent
+from PyQt5.QtGui import QColor, QKeySequence, QTextCursor
+from PyQt5.QtWidgets import (
+    QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy)
+try:
+    from PyQt5.QtSerialPort import QSerialPortInfo  # __IGNORE_WARNING__
+    HAS_QTSERIALPORT = True
+except ImportError:
+    HAS_QTSERIALPORT = False
+
+from E5Gui.E5ZoomWidget import E5ZoomWidget
+
+from .Ui_MicroPythonReplWidget import Ui_MicroPythonReplWidget
+
+from . import MicroPythonDevices
+
+import Globals
+import UI.PixmapCache
+
+
+class MicroPythonReplWidget(QWidget, Ui_MicroPythonReplWidget):
+    """
+    Class implementing the MicroPython REPL widget.
+    """
+    ZoomMin = -10
+    ZoomMax = 20
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super(MicroPythonReplWidget, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon(
+            "", False))
+        self.checkButton.setIcon(UI.PixmapCache.getIcon("question"))
+        self.runButton.setIcon(UI.PixmapCache.getIcon("start"))
+        self.replButton.setIcon(UI.PixmapCache.getIcon("terminal"))
+        self.filesButton.setIcon(UI.PixmapCache.getIcon("filemanager"))
+        self.chartButton.setIcon(UI.PixmapCache.getIcon("chart"))
+        self.disconnectButton.setIcon(UI.PixmapCache.getIcon("disconnect"))
+        
+        self.__zoomLayout = QHBoxLayout()
+        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
+                                 QSizePolicy.Minimum)
+        self.__zoomLayout.addSpacerItem(spacerItem)
+        
+        self.__zoom0 = self.replEdit.fontPointSize()
+        self.__zoomWidget = E5ZoomWidget(
+            UI.PixmapCache.getPixmap("zoomOut"),
+            UI.PixmapCache.getPixmap("zoomIn"),
+            UI.PixmapCache.getPixmap("zoomReset"), self)
+        self.__zoomLayout.addWidget(self.__zoomWidget)
+        self.layout().insertLayout(
+            self.layout().count() - 1,
+            self.__zoomLayout)
+        self.__zoomWidget.setMinimum(self.ZoomMin)
+        self.__zoomWidget.setMaximum(self.ZoomMax)
+        self.__zoomWidget.valueChanged.connect(self.__doZoom)
+        self.__currentZoom = 0
+        
+        self.__serial = None
+        self.__device = None
+        self.setConnected(False)
+        
+        if not HAS_QTSERIALPORT:
+            self.replEdit.setHtml(self.tr(
+                "<h3>The QtSerialPort package is not available.<br/>"
+                "MicroPython support is deactivated.</h3>"))
+            self.setEnabled(False)
+            return
+        
+        self.__vt100Re = re.compile(
+            r'(?P<count>[\d]*)(;?[\d]*)*(?P<action>[ABCDKm])')
+        
+        self.__populateDeviceTypeComboBox()
+        
+        self.replEdit.setAcceptRichText(False)
+        self.replEdit.setUndoRedoEnabled(False)
+        self.replEdit.setContextMenuPolicy(Qt.CustomContextMenu)
+        
+        self.replEdit.installEventFilter(self)
+        
+        self.replEdit.customContextMenuRequested.connect(
+            self.__showContextMenu)
+    
+    def __populateDeviceTypeComboBox(self):
+        """
+        Private method to populate the device type selector.
+        """
+        self.deviceTypeComboBox.clear()
+        self.deviceInfoLabel.clear()
+        
+        self.deviceTypeComboBox.addItem("", "")
+        devices = MicroPythonDevices.getFoundDevices()
+        if devices:
+            self.deviceInfoLabel.setText(
+                self.tr("%n supported device(s) detected.", n=len(devices)))
+            for device in sorted(devices):
+                self.deviceTypeComboBox.addItem(
+                    self.tr("{0} at {1}".format(device[1], device[2])),
+                    device[0])
+        else:
+            self.deviceInfoLabel.setText(
+                self.tr("No supported devices detected."))
+        
+        self.on_deviceTypeComboBox_activated(0)
+    
+    @pyqtSlot(int)
+    def on_deviceTypeComboBox_activated(self, index):
+        """
+        Private slot handling the selection of a device type.
+        
+        @param index index of the selected device
+        @type int
+        """
+        deviceType = self.deviceTypeComboBox.itemData(index)
+        self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon(
+            deviceType, False))
+        
+        self.__device = MicroPythonDevices.getDevice(deviceType)
+        if self.__device:
+            actions = self.__device.supportedActions()
+        else:
+            actions = tuple()
+        self.__setActionButtons(actions)
+    
+    @pyqtSlot()
+    def on_checkButton_clicked(self):
+        """
+        Private slot to check for connected devices.
+        """
+        self.__populateDeviceTypeComboBox()
+    
+    def __setActionButtons(self, actions):
+        """
+        Private method to set the enabled state of the various action buttons.
+        
+        @param actions tuple of supported actions out of "repl", "run",
+            "files", "chart"
+        @type tuple of str
+        """
+        self.runButton.setEnabled("run" in actions)
+        self.replButton.setEnabled("repl" in actions)
+        self.filesButton.setEnabled("files" in actions)
+        self.chartButton.setEnabled("chart" in actions)
+    
+    @pyqtSlot(QPoint)
+    def __showContextMenu(self, pos):
+        """
+        Privat slot to show the REPL context menu.
+        
+        @param pos position to show the menu at
+        @type QPoint
+        """
+        if Globals.isMacPlatform():
+            copyKeys = QKeySequence(Qt.CTRL + Qt.Key_C)
+            pasteKeys = QKeySequence(Qt.CTRL + Qt.Key_V)
+        else:
+            copyKeys = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_C)
+            pasteKeys = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_V)
+        menu = QMenu(self)
+        menu.addAction(self.tr("Copy"), self.replEdit.copy, copyKeys)
+        menu.addAction(self.tr("Paste"), self.__paste, pasteKeys)
+        menu.exec_(self.replEdit.mapToGlobal(pos))
+    
+    def setConnected(self, connected):
+        """
+        Public method to set the connection status LED.
+        
+        @param connected connection state
+        @type bool
+        """
+        if connected:
+            self.deviceConnectedLed.setColor(QColor(Qt.green))
+        else:
+            self.deviceConnectedLed.setColor(QColor(Qt.red))
+        
+        self.deviceTypeComboBox.setEnabled(not connected)
+        
+        self.disconnectButton.setEnabled(connected)
+    
+    @pyqtSlot()
+    def on_replButton_clicked(self):
+        """
+        Private slot to connect to the selected device and start a REPL.
+        """
+        # TODO: not implemented yet
+        raise NotImplementedError
+    
+    @pyqtSlot()
+    def on_disconnectButton_clicked(self):
+        """
+        Private slot to disconnect from the currently connected device.
+        """
+        # TODO: not implemented yet
+        raise NotImplementedError
+    
+    def __activatePlotter(self):
+        """
+        Private method to activate a data plotter widget.
+        """
+        # TODO: not implemented yet
+        raise NotImplementedError
+    
+    def __deactivatePlotter(self):
+        """
+        Private method to deactivate the plotter widget.
+        """
+        # TODO: not implemented yet
+    
+    @pyqtSlot()
+    def __paste(self):
+        """
+        Private slot to perform a paste operation.
+        """
+        clipboard = QApplication.clipboard()
+        if clipboard and clipboard.text():
+            pasteText = clipboard.text().replace('\n\r', '\r')
+            pasteText = pasteText.replace('\n', '\r')
+            self.__serial and self.__serial.write(pasteText.encode("utf-8"))
+    
+    def eventFilter(self, obj, evt):
+        """
+        Public method to process events for the REPL pane.
+        
+        @param obj reference to the object the event was meant for
+        @type QObject
+        @param evt reference to the event object
+        @type QEvent
+        @return flag to indicate that the event was handled
+        @rtype bool
+        """
+        if obj is self.replEdit and evt.type() == QEvent.KeyPress:
+            # handle the key press event on behalve of the REPL pane
+            key = evt.key()
+            msg = bytes(evt.text(), 'utf8')
+            if key == Qt.Key_Backspace:
+                msg = b'\b'
+            elif key == Qt.Key_Delete:
+                msg = b'\x1B[\x33\x7E'
+            elif key == Qt.Key_Up:
+                msg = b'\x1B[A'
+            elif key == Qt.Key_Down:
+                msg = b'\x1B[B'
+            elif key == Qt.Key_Right:
+                msg = b'\x1B[C'
+            elif key == Qt.Key_Left:
+                msg = b'\x1B[D'
+            elif key == Qt.Key_Home:
+                msg = b'\x1B[H'
+            elif key == Qt.Key_End:
+                msg = b'\x1B[F'
+            elif ((Globals.isMacPlatform() and
+                   evt.modifiers() == Qt.MetaModifier) or
+                  (not Globals.isMacPlatform() and
+                   evt.modifiers() == Qt.ControlModifier)):
+                if Qt.Key_A <= key <= Qt.Key_Z:
+                    # devices treat an input of \x01 as Ctrl+A, etc.
+                    msg = bytes([1 + key - Qt.Key_A])
+            elif (evt.modifiers() == Qt.ControlModifier | Qt.ShiftModifier or
+                  (Globals.isMacPlatform() and
+                   evt.modifiers() == Qt.ControlModifier)):
+                if key == Qt.Key_C:
+                    self.replEdit.copy()
+                    msg = b''
+                elif key == Qt.Key_V:
+                    self.__paste()
+                    msg = b''
+            self.__serial and self.__serial.write(msg)
+            return True
+        
+        else:
+            # standard event processing
+            return super(MicroPythonReplWidget, self).eventFilter(obj, evt)
+    
+    def __processData(self, data):
+        """
+        Private slot to process bytes received from the device.
+        
+        @param data bytes received from the device
+        @type bytes
+        """
+        tc = self.replEdit.textCursor()
+        # the text cursor must be on the last line
+        while tc.movePosition(QTextCursor.Down):
+            pass
+        
+        index = 1
+        while index < len(data):
+            if data[index] == 8:        # \b
+                tc.movePosition(QTextCursor.Left)
+                self.replEdit.setTextCursor(tc)
+            elif data[index] == 13:     # \r
+                pass
+            elif (len(data) > index + 1 and
+                  data[index] == 27 and
+                  data[index + 1] == 91):
+                # VT100 cursor command detected: <Esc>[
+                index += 2      # move index to after the [
+                match = self.__vt100Re.search(data[index:].decaode("utf-8"))
+                if match:
+                    # move to last position in control sequence
+                    # ++ will be done at end of loop
+                    index += match.end() - 1
+                    
+                    if match.group("count") == "":
+                        count = 1
+                    else:
+                        count = int(match.group("count"))
+                    
+                    action = match.group("action")
+                    if action == "A":       # up
+                        tc.movePosition(QTextCursor.Up, n=count)
+                        self.replEdit.setTextCursor(tc)
+                    elif action == "B":     # down
+                        tc.movePosition(QTextCursor.Down, n=count)
+                        self.replEdit.setTextCursor(tc)
+                    elif action == "C":     # right
+                        tc.movePosition(QTextCursor.Right, n=count)
+                        self.replEdit.setTextCursor(tc)
+                    elif action == "D":     # left
+                        tc.movePosition(QTextCursor.Left, n=count)
+                        self.replEdit.setTextCursor(tc)
+                    elif action == "K":     # delete things
+                        if match.group("count") == "":      # delete to eol
+                            tc.movePosition(QTextCursor.EndOfLine,
+                                            mode=QTextCursor.KeepAnchor)
+                            tc.removeSelectedText()
+                            self.replEdit.setTextCursor(tc)
+                    # TODO: add handling of 'm' (colors)
+            elif data[index] == 10:     # \n
+                tc.movePosition(QTextCursor.End)
+                self.replEdit.setTextCursor(tc)
+                self.replEdit.insertPlainText(chr(data[index]))
+            else:
+                tc.deleteChar()
+                self.replEdit.setTextCursor(tc)
+                self.replEdit.insertPlainText(chr(data[index]))
+            
+            index += 1
+        
+        self.replEdit.ensureCursorVisible()
+    
+    def __doZoom(self, value):
+        """
+        Private slot to zoom the REPL pane.
+        
+        @param value zoom value
+        @param int
+        """
+        if value < self.__currentZoom:
+            self.replEdit.zoomOut(self.__currentZoom - value)
+        elif value > self.__currentZoom:
+            self.replEdit.zoomIn(value - self.__currentZoom)
+        self.__currentZoom = value
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/MicroPython/MicroPythonReplWidget.ui	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MicroPythonReplWidget</class>
+ <widget class="QWidget" name="MicroPythonReplWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>456</width>
+    <height>548</height>
+   </rect>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="deviceIconLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>48</width>
+         <height>48</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="1" column="0" colspan="3">
+        <widget class="QLabel" name="deviceInfoLabel">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QComboBox" name="deviceTypeComboBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="2">
+        <widget class="E5Led" name="deviceConnectedLed" native="true"/>
+       </item>
+       <item row="0" column="1">
+        <widget class="QToolButton" name="checkButton">
+         <property name="toolTip">
+          <string>Press to check for connected devices</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QToolButton" name="runButton">
+       <property name="toolTip">
+        <string>Press to run the current script on the selected device</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="replButton">
+       <property name="toolTip">
+        <string>Press to open a terminal (REPL) on the selected device</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="filesButton">
+       <property name="toolTip">
+        <string>Press to open a file manager on the selected device (REPL must be disconnected first)</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="chartButton">
+       <property name="toolTip">
+        <string>Press to open a chart window to display data receive from the selected device</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QToolButton" name="disconnectButton">
+       <property name="toolTip">
+        <string>Press to disconnect the selected device</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QTextEdit" name="replEdit"/>
+   </item>
+   <item>
+    <widget class="QLabel" name="statusLabel"/>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>E5Led</class>
+   <extends>QWidget</extends>
+   <header>E5Gui/E5Led.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>deviceTypeComboBox</tabstop>
+  <tabstop>checkButton</tabstop>
+  <tabstop>runButton</tabstop>
+  <tabstop>replButton</tabstop>
+  <tabstop>filesButton</tabstop>
+  <tabstop>chartButton</tabstop>
+  <tabstop>disconnectButton</tabstop>
+  <tabstop>replEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/MicroPython/__init__.py	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing an interface to MicroPython devices like esp32.
+"""
+
+from __future__ import unicode_literals
--- a/eric6/Preferences/ConfigurationPages/InterfacePage.py	Sun Jul 07 14:58:07 2019 +0200
+++ b/eric6/Preferences/ConfigurationPages/InterfacePage.py	Sun Jul 07 18:48:17 2019 +0200
@@ -86,6 +86,8 @@
         # right side
         self.codeDocumentationViewerCheckBox.setChecked(
             Preferences.getUI("ShowCodeDocumentationViewer"))
+        self.microPythonCheckBox.setChecked(
+            Preferences.getUI("ShowMicroPython"))
         self.pypiCheckBox.setChecked(
             Preferences.getUI("ShowPyPIPackageManager"))
         self.condaCheckBox.setChecked(
@@ -175,6 +177,9 @@
             "ShowCodeDocumentationViewer",
             self.codeDocumentationViewerCheckBox.isChecked())
         Preferences.setUI(
+            "ShowMicroPython",
+            self.microPythonCheckBox.isChecked())
+        Preferences.setUI(
             "ShowPyPIPackageManager",
             self.pypiCheckBox.isChecked())
         Preferences.setUI(
--- a/eric6/Preferences/ConfigurationPages/InterfacePage.ui	Sun Jul 07 14:58:07 2019 +0200
+++ b/eric6/Preferences/ConfigurationPages/InterfacePage.ui	Sun Jul 07 18:48:17 2019 +0200
@@ -445,6 +445,16 @@
            </property>
           </widget>
          </item>
+         <item row="0" column="1">
+          <widget class="QCheckBox" name="microPythonCheckBox">
+           <property name="toolTip">
+            <string>Select to activate the MicroPython widget</string>
+           </property>
+           <property name="text">
+            <string>MicroPython</string>
+           </property>
+          </widget>
+         </item>
         </layout>
        </widget>
       </item>
@@ -518,6 +528,7 @@
   <tabstop>fileBrowserCheckBox</tabstop>
   <tabstop>symbolsCheckBox</tabstop>
   <tabstop>codeDocumentationViewerCheckBox</tabstop>
+  <tabstop>microPythonCheckBox</tabstop>
   <tabstop>pypiCheckBox</tabstop>
   <tabstop>condaCheckBox</tabstop>
   <tabstop>cooperationCheckBox</tabstop>
--- a/eric6/Preferences/__init__.py	Sun Jul 07 14:58:07 2019 +0200
+++ b/eric6/Preferences/__init__.py	Sun Jul 07 18:48:17 2019 +0200
@@ -168,6 +168,7 @@
         "ShowCondaPackageManager": True,        # right side
         "ShowCooperation": True,                # right side
         "ShowIrc": True,                        # right side
+        "ShowMicroPython": True,                # right side
         "ShowNumbersViewer": True,              # bottom side
         "ViewProfiles2": {
             "edit": [
@@ -1995,7 +1996,7 @@
                "ShowCodeDocumentationViewer", "ShowPyPIPackageManager",
                "ShowCondaPackageManager", "ShowCooperation", "ShowIrc",
                "ShowTemplateViewer", "ShowFileBrowser", "ShowSymbolsViewer",
-               "ShowNumbersViewer", "UseNativeMenuBar"]:
+               "ShowNumbersViewer", "ShowMicroPython", "UseNativeMenuBar"]:
         return toBool(prefClass.settings.value(
             "UI/" + key, prefClass.uiDefaults[key]))
     elif key in ["TabViewManagerFilenameLength", "CaptionFilenameLength",
--- a/eric6/UI/UserInterface.py	Sun Jul 07 14:58:07 2019 +0200
+++ b/eric6/UI/UserInterface.py	Sun Jul 07 18:48:17 2019 +0200
@@ -907,6 +907,15 @@
                                   UI.PixmapCache.getIcon("irc.png"),
                                   self.tr("IRC"))
         
+        if Preferences.getUI("ShowMicroPython"):
+            # Create the MicroPython part of the user interface
+            logging.debug("Creating MicroPython Widget...")
+            from MicroPython.MicroPythonReplWidget import MicroPythonReplWidget
+            self.microPythonRepl = MicroPythonReplWidget(self)
+            self.rToolbox.addItem(self.microPythonRepl,
+                                  UI.PixmapCache.getIcon("micropython"),
+                                  self.tr("MicroPython"))
+        
         ####################################################
         ## Populate the bottom toolbox
         ####################################################
@@ -1095,6 +1104,15 @@
                 self.irc, UI.PixmapCache.getIcon("irc.png"),
                 self.tr("IRC"))
         
+        if Preferences.getUI("ShowMicroPython"):
+            # Create the MicroPython part of the user interface
+            logging.debug("Creating MicroPython Widget...")
+            from MicroPython.MicroPythonReplWidget import MicroPythonReplWidget
+            self.microPythonRepl = MicroPythonReplWidget(self)
+            self.rightSidebar.addTab(
+                self.microPythonRepl, UI.PixmapCache.getIcon("micropython"),
+                self.tr("MicroPython"))
+        
         ####################################################
         ## Populate the bottom side bar
         ####################################################
Binary file eric6/icons/default/adafruitDevice.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/icons/default/chart.svg	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
+  <defs id="defs3051">
+    <style type="text/css" id="current-color-scheme">
+      .ColorScheme-Text {
+        color:#232629;
+      }
+      .ColorScheme-Highlight {
+        color:#3daee9;
+      }
+      </style>
+  </defs>
+ <path 
+     style="fill:currentColor;fill-opacity:1;stroke:none" 
+     d="M 4 3 L 4 9 L 4 10 L 4 15 L 4 16 L 4 17 L 3 17 L 3 18 L 4 18 L 4 19 L 5 19 L 5 18 L 18.292969 18 L 19 18 L 19 17.292969 L 19 17 L 18.707031 17 L 17.958984 16.251953 L 17.130859 15.423828 L 15.130859 13.423828 L 15.126953 13.427734 L 15.121094 13.423828 L 12.998047 15.546875 L 11.703125 14.251953 L 10.875 13.423828 L 8.875 11.423828 L 8.8730469 11.423828 L 7 11.423828 L 6 11.423828 L 5 11.423828 L 5 11 L 5 10 L 6 10 L 7 10 L 8.8730469 10 L 8.875 10 L 10.875 8 L 11.703125 7.171875 L 12.998047 5.8769531 L 15.121094 8 L 15.126953 7.9960938 L 15.130859 8 L 17.130859 6 L 17.958984 5.171875 L 19 4.1308594 L 18.292969 3.4238281 L 17.251953 4.4648438 L 16.423828 5.2929688 L 15.126953 6.5898438 L 13 4.4648438 L 12.998047 4.4667969 L 12.996094 4.4648438 L 11.46875 5.9921875 L 5 5.9921875 L 5 5 L 5 3 L 4 3 z M 5 6 L 11.460938 6 L 10.996094 6.4648438 L 10.167969 7.2929688 L 8.4609375 9 L 7 9 L 6 9 L 5 9 L 5 6 z M 5 12.423828 L 6 12.423828 L 7 12.423828 L 8.4609375 12.423828 L 10.167969 14.130859 L 10.996094 14.958984 L 11.460938 15.423828 L 5 15.423828 L 5 15 L 5 12.423828 z M 15.126953 14.833984 L 16.423828 16.130859 L 17.251953 16.958984 L 17.292969 17 L 5 17 L 5 16 L 5 15.431641 L 11.46875 15.431641 L 12.996094 16.958984 L 12.998047 16.957031 L 13 16.958984 L 15.126953 14.833984 z "
+     class="ColorScheme-Text"
+     />
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/icons/default/disconnect.svg	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,22 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
+  <defs id="defs3051">
+    <style type="text/css" id="current-color-scheme">
+      .ColorScheme-Text {
+        color:#232629;
+      }
+      .ColorScheme-NegativeText {
+        color:#da4453;
+      }
+      </style>
+  </defs>
+ <path 
+     style="fill:currentColor;fill-opacity:1;stroke:none" 
+     d="M 18.292969 3 L 14.792969 6.5 L 13.292969 5 L 11.292969 7 L 9.5 8.7929688 L 11 10.292969 L 11.707031 11 L 13.207031 12.5 L 15 10.707031 L 17 8.7070312 L 15.5 7.2070312 L 19 3.7070312 L 18.292969 3 z M 8.7929688 9.5 L 8 10.292969 L 6 12.292969 L 7.5 13.792969 L 3 18.292969 L 3.7070312 19 L 8.2070312 14.5 L 9.7070312 16 L 11.707031 14 L 12.5 13.207031 L 11 11.707031 L 10.292969 11 L 8.7929688 9.5 z "
+     class="ColorScheme-Text"
+     />
+    <path
+     style="fill:currentColor;fill-opacity:1;stroke:none" 
+     d="M 14.833984 14 L 14 14.833984 L 15.666016 16.5 L 14 18.166016 L 14.833984 19 L 16.5 17.333984 L 18.166016 19 L 19 18.166016 L 17.333984 16.5 L 19 14.833984 L 18.166016 14 L 16.5 15.666016 L 14.833984 14 z "
+     class="ColorScheme-NegativeText"
+     />
+</svg>
Binary file eric6/icons/default/esp32Device.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/icons/default/filemanager.svg	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="22"
+   height="22"
+   viewBox="0 0 22 22"
+   id="svg7925"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="system-file-manager.svg">
+  <defs
+     id="defs7927">
+    <linearGradient
+       id="linearGradient4274"
+       inkscape:collect="always">
+      <stop
+         id="stop4276"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop4278"
+         offset="1"
+         style="stop-color:#ffffff;stop-opacity:0.48760331" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4274"
+       id="linearGradient8485"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.69224711,0,0,0.69224711,-264.27155,1668.4354)"
+       x1="390.57144"
+       y1="498.298"
+       x2="442.57144"
+       y2="498.298" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4393"
+       id="linearGradient4399"
+       x1="419.4624"
+       y1="499.23697"
+       x2="432.57144"
+       y2="523.79797"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.34616832,0,0,0.34616832,-141.20459,864.54218)" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4393">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop4395" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop4397" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4172-5"
+       id="linearGradient4178"
+       y1="548.88599"
+       y2="495.30789"
+       x2="397.2283"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.34616832,0,0,0.34605565,-133.24271,862.87242)"
+       x1="434.16153" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4172-5">
+      <stop
+         style="stop-color:#127bdc;stop-opacity:1"
+         id="stop4174-6" />
+      <stop
+         offset="1"
+         style="stop-color:#64b4f4;stop-opacity:1"
+         id="stop4176-6" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4227"
+       id="linearGradient4225"
+       gradientUnits="userSpaceOnUse"
+       x1="396.57144"
+       y1="498.798"
+       x2="426.57144"
+       y2="511.798"
+       gradientTransform="matrix(0.34616832,0,0,0.34616832,-133.24271,864.50368)" />
+    <linearGradient
+       id="linearGradient4227"
+       inkscape:collect="always">
+      <stop
+         id="stop4229"
+         offset="0"
+         style="stop-color:#f5f5f5;stop-opacity:1" />
+      <stop
+         id="stop4231"
+         offset="1"
+         style="stop-color:#f9f9f9;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       gradientTransform="matrix(0.34616832,0,0,0.34616832,-133.24271,862.81136)"
+       inkscape:collect="always"
+       xlink:href="#linearGradient4291"
+       id="linearGradient4297"
+       x1="388.57144"
+       y1="487.798"
+       x2="416.57144"
+       y2="507.798"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4291">
+      <stop
+         style="stop-color:#1d5e8c;stop-opacity:1"
+         offset="0"
+         id="stop4293" />
+      <stop
+         style="stop-color:#2675a7;stop-opacity:1"
+         offset="1"
+         id="stop4295" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4274"
+       id="linearGradient8603"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.34616832,0,0,0.34616832,-133.24271,2893.0497)"
+       x1="390.57144"
+       y1="498.298"
+       x2="442.57144"
+       y2="498.298" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4274"
+       id="linearGradient8603-0"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.34616832,0,0,0.34616832,-135.15325,827.3248)"
+       x1="390.57144"
+       y1="498.298"
+       x2="442.57144"
+       y2="498.298" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="14.052007"
+     inkscape:cy="13.482364"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     units="px"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-nodes="true"
+     inkscape:object-nodes="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid8605" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7930">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Livello 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1030.3622)">
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:url(#linearGradient4297);fill-opacity:1"
+       id="rect4180"
+       d="m 1,1042.3622 20,0.501 0,-8.501 -10,0 -1.588488,-2.0013 -8.411512,0 z"
+       sodipodi:nodetypes="ccccccc" />
+    <rect
+       ry="1.0000174"
+       rx="0.9128685"
+       y="1036.3622"
+       x="2"
+       height="5.0000172"
+       width="18"
+       id="rect4223"
+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4225);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+    <path
+       inkscape:connector-curvature="0"
+       style="fill:url(#linearGradient4178)"
+       d="m 9,1038.3622 -2,1 -6,0 -0.0895868,1.0011 -5e-7,9.5003 c 0,0.2699 0.244354,0.4954 0.4919395,0.4954 l 19.0105828,0.01 c 0.255387,0.01 0.500065,-0.1978 0.500065,-0.5 L 21,1038.3622 Z"
+       id="rect4113"
+       sodipodi:nodetypes="cccccscccc" />
+    <path
+       inkscape:connector-curvature="0"
+       style="opacity:0.3;fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
+       id="path4224"
+       d="m 1,1039.3622 -0.0895868,1.0011 7.0895868,0 1,-2 -2,0.9989 z"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       inkscape:connector-curvature="0"
+       style="opacity:0.3;fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
+       id="path4196"
+       d="m 9.411512,1032.3622 0.588488,3 11,0 0,-1 -10,0 z"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       style="opacity:0.09899998;fill:url(#linearGradient4399);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 0.9104132,1040.3633 7.0895868,-0 1,-2 12,0 0,11.6563 -10.385049,0 z"
+       id="path4383"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccccc" />
+    <path
+       style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient8603);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 2.9121094,1036.3622 c -0.5057292,0 -0.9121094,0.446 -0.9121094,1 l 0,1 c 0,-0.554 0.4063802,-1 0.9121094,-1 l 16.0878906,0 c 0.505729,0 0.912109,0.446 0.912109,1 l 0,-1 c 0,-0.554 -0.40638,-1 -0.912109,-1 z"
+       id="rect8607"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="sscsscsss" />
+    <path
+       style="fill:#000000;color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="M 20.992188 8 L 20.912109 18.505859 C 20.912109 18.808059 20.667496 19.015859 20.412109 19.005859 L 1.4023438 18.996094 C 1.1547582 18.996094 0.91015625 18.771853 0.91015625 18.501953 L 0.91015625 19.501953 C 0.91015625 19.771853 1.1547582 19.996094 1.4023438 19.996094 L 20.412109 20.005859 C 20.667496 20.015859 20.912109 19.808059 20.912109 19.505859 L 21 8 L 20.992188 8 z "
+       transform="translate(0,1030.3622)"
+       id="path4164" />
+  </g>
+</svg>
Binary file eric6/icons/default/microbitDevice.png has changed
Binary file eric6/icons/default/micropython.png has changed
Binary file eric6/icons/default/micropython48.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/icons/default/question.svg	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
+  <defs id="defs3051">
+    <style type="text/css" id="current-color-scheme">
+      .ColorScheme-Text {
+        color:#232629;
+      }
+      </style>
+  </defs>
+ <path 
+    style="fill:currentColor;fill-opacity:1;stroke:none" 
+    d="M 10.96875 3 C 9.21782 3 7.56187 3.4216019 6 4.2636719 L 6.7773438 6.0507812 C 7.5582637 5.6672613 8.2600456 5.3933025 8.8847656 5.2265625 C 9.5177356 5.0598325 10.162692 4.9765625 10.820312 4.9765625 C 11.806753 4.9765625 12.563734 5.1968119 13.089844 5.6386719 C 13.615944 6.0805419 13.878906 6.7136725 13.878906 7.5390625 C 13.878906 7.9809325 13.822111 8.369625 13.707031 8.703125 C 13.591951 9.036605 13.394724 9.369635 13.115234 9.703125 C 12.835754 10.036615 12.247563 10.586476 11.351562 11.353516 C 10.251483 12.356846 9.10046 14.139 9 16 L 11 16 L 10.994141 15.96875 C 10.994141 15.21007 11.125612 14.601138 11.388672 14.142578 C 11.659952 13.675688 12.201805 13.087576 13.015625 12.378906 C 14.010295 11.536836 14.673153 10.903726 15.001953 10.478516 C 15.338993 10.053316 15.589506 9.6041363 15.753906 9.1289062 C 15.918406 8.6536762 16 8.1071944 16 7.4902344 C 16 6.0728944 15.55227 4.97119 14.65625 4.1875 C 13.76024 3.39546 12.53061 3 10.96875 3 z M 9 17 L 9 19 L 11 19 L 11 17 L 9 17 z "
+    class="ColorScheme-Text"
+    />  
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/icons/default/start.svg	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
+  <defs id="defs3051">
+    <style type="text/css" id="current-color-scheme">
+      .ColorScheme-Text {
+        color:#232629;
+      }
+      </style>
+  </defs>
+ <path
+    style="fill:currentColor;fill-opacity:1;stroke:none"
+    d="m 4 4 0 14 L 18 11 Z"
+    class="ColorScheme-Text"
+    />
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/icons/default/terminal.svg	Sun Jul 07 18:48:17 2019 +0200
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg id="svg2987" width="16px" height="16px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs id="defs2989">
+  <linearGradient id="linearGradient2880" x1="16.143" x2="16.143" y1="4" y2="44" gradientTransform="matrix(.23078 0 0 .15386 2.4612 4.8074)" gradientUnits="userSpaceOnUse">
+   <stop id="stop2225-6-4-7-2" style="stop-color:#fff" offset="0"/>
+   <stop id="stop2229-2-5-5-8" style="stop-color:#fff;stop-opacity:0" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient2883" x1="16.626" x2="20.055" y1="15.298" y2="24.628" gradientTransform="matrix(.30476 0 0 .32156 .68572 1.0807)" gradientUnits="userSpaceOnUse">
+   <stop id="stop2687-1-9-0-2" style="stop-color:#fff" offset="0"/>
+   <stop id="stop2689-5-4-3-1" style="stop-color:#fff;stop-opacity:0" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient2886" x1="16" x2="16" y1="27.045" y2="16" gradientTransform="matrix(.34286 0 0 .36364 -.42808 -.81818)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient3680-6"/>
+  <linearGradient id="linearGradient3680-6">
+   <stop id="stop3682-4" style="stop-color:#dcdcdc" offset="0"/>
+   <stop id="stop3684-8" style="stop-color:#fff" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient2890" x1="20" x2="20" y1="28" y2="26" gradientTransform="matrix(.375 0 0 .375 -.74978 -.5)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient3680-6"/>
+  <linearGradient id="linearGradient2894" x1="12.579" x2="12.213" y1="2.9165" y2="47.279" gradientTransform="matrix(.28855 0 0 .25608 1.0743 2.6116)" gradientUnits="userSpaceOnUse">
+   <stop id="stop2240-1-6-7-0" style="stop-color:#fff" offset="0"/>
+   <stop id="stop2242-7-3-7-2" style="stop-color:#fff;stop-opacity:0" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient2897" x1="23.071" x2="23.071" y1="36.047" y2="33.296" gradientTransform="matrix(.33032 0 0 .32624 .074248 1.9649)" gradientUnits="userSpaceOnUse">
+   <stop id="stop2225-6-4-7" style="stop-color:#fff" offset="0"/>
+   <stop id="stop2229-2-5-5" style="stop-color:#fff;stop-opacity:0" offset="1"/>
+  </linearGradient>
+  <radialGradient id="radialGradient2900" cx="7.4957" cy="8.4498" r="20" gradientTransform="matrix(0 .47178 -.86826 -1.9907e-8 15.337 1.0829)" gradientUnits="userSpaceOnUse">
+   <stop id="stop3790-0-0" style="stop-color:#505050" offset="0"/>
+   <stop id="stop3792-0-2" style="stop-color:#141414" offset="1"/>
+  </radialGradient>
+  <linearGradient id="linearGradient2902" x1="16.143" x2="16.143" y1="4" y2="44" gradientTransform="matrix(.28207 0 0 .20514 1.2304 3.5766)" gradientUnits="userSpaceOnUse">
+   <stop id="stop3796-3-0" style="stop-color:#323232" offset="0"/>
+   <stop id="stop3798-8-6" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient2983" x1="24" x2="24" y1="7.96" y2="43.865" gradientTransform="matrix(.3333 0 0 .32429 .00075427 .06858)" gradientUnits="userSpaceOnUse">
+   <stop id="stop4324-9-7" style="stop-color:#f0f0f0" offset="0"/>
+   <stop id="stop2860-4-4" style="stop-color:#d7d7d8" offset=".085525"/>
+   <stop id="stop2862-5-9" style="stop-color:#b2b2b3" offset=".92166"/>
+   <stop id="stop4326-1-1" style="stop-color:#979798" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient2985" x1="10.014" x2="10.014" y1="44.96" y2="2.8765" gradientTransform="matrix(.31912 0 0 .29298 .34112 1.4648)" gradientUnits="userSpaceOnUse">
+   <stop id="stop4334-7-6" style="stop-color:#595959" offset="0"/>
+   <stop id="stop4336-8-0" style="stop-color:#b3b3b3" offset="1"/>
+  </linearGradient>
+ </defs>
+ <metadata id="metadata2992">
+  <rdf:RDF>
+   <cc:Work rdf:about="">
+    <dc:format>image/svg+xml</dc:format>
+    <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+    <dc:title/>
+   </cc:Work>
+  </rdf:RDF>
+ </metadata>
+ <g id="layer1">
+  <rect id="rect2551-5-8" x=".50107" y="2.5011" width="14.998" height="11.998" rx="1" ry="1" style="fill-rule:evenodd;fill:url(#linearGradient2983);stroke-linecap:round;stroke-linejoin:round;stroke-width:1.0021;stroke:url(#linearGradient2985)"/>
+  <rect id="rect1314-3-3" x="2.5" y="4.5" width="11" height="8" rx="0" ry="0" style="color:#000000;fill:url(#radialGradient2900);stroke-linecap:round;stroke-linejoin:round;stroke:url(#linearGradient2902)"/>
+  <rect id="rect2221-3-8" x="1.501" y="3.5011" width="12.998" height="9.9979" rx="0" ry="0" style="fill:none;opacity:.4;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.0021;stroke:url(#linearGradient2897)"/>
+  <rect id="rect2556-8-5" x="1.5019" y="3.5019" width="12.996" height="9.9963" style="fill:none;opacity:.8;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.0037;stroke:url(#linearGradient2894)"/>
+  <path id="path3651-2" d="m9.0002 10v-0.75h-3v0.75h3z" style="fill:url(#linearGradient2890)"/>
+  <path id="path3653-7" d="m3.6862 9-0.68571-0.72727 1.5429-1.2727-1.5429-1.2727 0.68571-0.72727 2.3143 2-2.3143 2z" style="fill:url(#linearGradient2886)"/>
+  <path id="path3333-3-0" d="m1.6667 3c-0.36824 0-0.66667 0.31488-0.66667 0.70342v5.145c9.545e-4 0.043283 0.018837 0.084214 0.049602 0.11286 0.030769 0.028643 0.071495 0.04238 0.1123 0.037874l13.714-2.2911c0.070547-0.011738 0.12282-0.075385 0.12381-0.15073v-2.8539c0-0.38854-0.29843-0.70342-0.66667-0.70342h-12.667z" style="fill-rule:evenodd;fill:url(#linearGradient2883);opacity:.2"/>
+  <rect id="rect1314-3-3-9" x="3.5" y="5.5" width="9" height="6" rx="0" ry="0" style="color:#000000;fill:none;opacity:.1;stroke-linecap:round;stroke-linejoin:round;stroke:url(#linearGradient2880)"/>
+ </g>
+</svg>

eric ide

mercurial