11 import time |
11 import time |
12 import os |
12 import os |
13 import functools |
13 import functools |
14 |
14 |
15 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QPoint, QEvent |
15 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QPoint, QEvent |
16 from PyQt5.QtGui import QColor, QKeySequence, QTextCursor, QBrush |
16 from PyQt5.QtGui import QColor, QKeySequence, QTextCursor, QBrush, QClipboard |
17 from PyQt5.QtWidgets import ( |
17 from PyQt5.QtWidgets import ( |
18 QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy, |
18 QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy, |
19 QTextEdit, QToolButton, QDialog |
19 QTextEdit, QToolButton, QDialog |
20 ) |
20 ) |
21 |
21 |
277 r'(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])') |
277 r'(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])') |
278 |
278 |
279 self.__populateDeviceTypeComboBox() |
279 self.__populateDeviceTypeComboBox() |
280 |
280 |
281 self.replEdit.installEventFilter(self) |
281 self.replEdit.installEventFilter(self) |
|
282 # Hack to intercept middle button paste |
|
283 self.__origReplEditMouseReleaseEvent = self.replEdit.mouseReleaseEvent |
|
284 self.replEdit.mouseReleaseEvent = self.__replEditMouseReleaseEvent |
282 |
285 |
283 self.replEdit.customContextMenuRequested.connect( |
286 self.replEdit.customContextMenuRequested.connect( |
284 self.__showContextMenu) |
287 self.__showContextMenu) |
285 self.__ui.preferencesChanged.connect(self.__handlePreferencesChanged) |
288 self.__ui.preferencesChanged.connect(self.__handlePreferencesChanged) |
286 self.__ui.preferencesChanged.connect( |
289 self.__ui.preferencesChanged.connect( |
627 """ |
630 """ |
628 self.replEdit.clear() |
631 self.replEdit.clear() |
629 self.__interface.isConnected() and self.__interface.write(b"\r") |
632 self.__interface.isConnected() and self.__interface.write(b"\r") |
630 |
633 |
631 @pyqtSlot() |
634 @pyqtSlot() |
632 def __paste(self): |
635 def __paste(self, mode=QClipboard.Mode.Clipboard): |
633 """ |
636 """ |
634 Private slot to perform a paste operation. |
637 Private slot to perform a paste operation. |
|
638 |
|
639 @param mode paste mode (defaults to QClipboard.Mode.Clipboard) |
|
640 @type QClipboard.Mode (optional) |
635 """ |
641 """ |
636 # add support for paste by mouse middle button |
642 # add support for paste by mouse middle button |
637 clipboard = QApplication.clipboard() |
643 clipboard = QApplication.clipboard() |
638 if clipboard: |
644 if clipboard: |
639 pasteText = clipboard.text() |
645 pasteText = clipboard.text(mode=mode) |
640 if pasteText: |
646 if pasteText: |
641 pasteText = pasteText.replace('\n\r', '\r') |
647 pasteText = pasteText.replace('\n\r', '\r') |
642 pasteText = pasteText.replace('\n', '\r') |
648 pasteText = pasteText.replace('\n', '\r') |
643 self.__interface.isConnected() and self.__interface.write( |
649 self.__interface.isConnected() and self.__interface.write( |
644 pasteText.encode("utf-8")) |
650 pasteText.encode("utf-8")) |
679 (not Globals.isMacPlatform() and |
685 (not Globals.isMacPlatform() and |
680 evt.modifiers() == Qt.ControlModifier)): |
686 evt.modifiers() == Qt.ControlModifier)): |
681 if Qt.Key_A <= key <= Qt.Key_Z: |
687 if Qt.Key_A <= key <= Qt.Key_Z: |
682 # devices treat an input of \x01 as Ctrl+A, etc. |
688 # devices treat an input of \x01 as Ctrl+A, etc. |
683 msg = bytes([1 + key - Qt.Key_A]) |
689 msg = bytes([1 + key - Qt.Key_A]) |
684 elif (evt.modifiers() == Qt.ControlModifier | Qt.ShiftModifier or |
690 elif ( |
685 (Globals.isMacPlatform() and |
691 evt.modifiers() == (Qt.ControlModifier | Qt.ShiftModifier) or |
686 evt.modifiers() == Qt.ControlModifier)): |
692 (Globals.isMacPlatform() and |
|
693 evt.modifiers() == Qt.ControlModifier) |
|
694 ): |
687 if key == Qt.Key_C: |
695 if key == Qt.Key_C: |
688 self.replEdit.copy() |
696 self.replEdit.copy() |
689 msg = b'' |
697 msg = b'' |
690 elif key == Qt.Key_V: |
698 elif key == Qt.Key_V: |
691 self.__paste() |
699 self.__paste() |
694 tc = self.replEdit.textCursor() |
702 tc = self.replEdit.textCursor() |
695 tc.movePosition(QTextCursor.EndOfLine) |
703 tc.movePosition(QTextCursor.EndOfLine) |
696 self.replEdit.setTextCursor(tc) |
704 self.replEdit.setTextCursor(tc) |
697 self.__interface.isConnected() and self.__interface.write(msg) |
705 self.__interface.isConnected() and self.__interface.write(msg) |
698 return True |
706 return True |
699 |
|
700 else: |
707 else: |
701 # standard event processing |
708 # standard event processing |
702 return super(MicroPythonWidget, self).eventFilter(obj, evt) |
709 return super(MicroPythonWidget, self).eventFilter(obj, evt) |
|
710 |
|
711 def __replEditMouseReleaseEvent(self, evt): |
|
712 """ |
|
713 Private method handling mouse release events for the replEdit widget. |
|
714 |
|
715 Note: this is a hack because QTextEdit does not allow filtering of |
|
716 QEvent.MouseButtonRelease. To make middle button paste work, we had |
|
717 to intercept the protected event method (some kind of reimplementing |
|
718 it). |
|
719 |
|
720 @param evt reference to the event object |
|
721 @type QMouseEvent |
|
722 """ |
|
723 if evt.button() == Qt.MiddleButton: |
|
724 self.__paste(mode=QClipboard.Mode.Selection) |
|
725 msg = b'' |
|
726 if self.__interface.isConnected(): |
|
727 self.__interface.write(msg) |
|
728 evt.accept() |
|
729 else: |
|
730 self.__origReplEditMouseReleaseEvent(evt) |
703 |
731 |
704 def __processData(self, data): |
732 def __processData(self, data): |
705 """ |
733 """ |
706 Private slot to process bytes received from the device. |
734 Private slot to process bytes received from the device. |
707 |
735 |