- moved some graphical classes out of Tool Shell to GUIElements.py where they belong
- when selecting an object on canvas by single click, it's name is displayed in status bar. When nothing is selected a blank message (nothing) it's displayed - in Move Tool I've added the type of object that was moved in the status bar message - color coded the status bar bullet to blue for selection - the name of the selected objects are displayed in the status bar color coded: green for Gerber objects, Brown for Excellon, Red for Geometry and Blue for CNCJobs.
This commit is contained in:
@@ -1700,7 +1700,7 @@ class App(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def shell_message(self, msg, show=False, error=False, warning=False, success=False):
|
def shell_message(self, msg, show=False, error=False, warning=False, success=False, selected=False):
|
||||||
"""
|
"""
|
||||||
Shows a message on the FlatCAM Shell
|
Shows a message on the FlatCAM Shell
|
||||||
|
|
||||||
@@ -1720,8 +1720,10 @@ class App(QtCore.QObject):
|
|||||||
else:
|
else:
|
||||||
if success:
|
if success:
|
||||||
self.shell.append_success(msg + "\n")
|
self.shell.append_success(msg + "\n")
|
||||||
else:
|
if success:
|
||||||
self.shell.append_output(msg + "\n")
|
self.shell.append_selected(msg + "\n")
|
||||||
|
else:
|
||||||
|
self.shell.append_output(msg + "\n")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
log.debug("shell_message() is called before Shell Class is instantiated. The message is: %s", str(msg))
|
log.debug("shell_message() is called before Shell Class is instantiated. The message is: %s", str(msg))
|
||||||
|
|
||||||
@@ -1894,13 +1896,19 @@ class App(QtCore.QObject):
|
|||||||
|
|
||||||
elif level.lower() == "error_notcl":
|
elif level.lower() == "error_notcl":
|
||||||
self.shell_message(msg, error=True, show=False)
|
self.shell_message(msg, error=True, show=False)
|
||||||
|
|
||||||
elif level.lower() == "warning_notcl":
|
elif level.lower() == "warning_notcl":
|
||||||
self.shell_message(msg, warning=True, show=False)
|
self.shell_message(msg, warning=True, show=False)
|
||||||
|
|
||||||
elif level.lower() == "success":
|
elif level.lower() == "success":
|
||||||
self.shell_message(msg, success=True, show=False)
|
self.shell_message(msg, success=True, show=False)
|
||||||
|
|
||||||
|
elif level.lower() == "selected":
|
||||||
|
self.shell_message(msg, selected=True, show=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.shell_message(msg, show=False)
|
self.shell_message(msg, show=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.ui.fcinfo.set_status(str(msg), level="info")
|
self.ui.fcinfo.set_status(str(msg), level="info")
|
||||||
|
|
||||||
@@ -4440,6 +4448,9 @@ class App(QtCore.QObject):
|
|||||||
# and as a convenience move the focus to the Project tab because Selected tab is now empty
|
# and as a convenience move the focus to the Project tab because Selected tab is now empty
|
||||||
self.ui.notebook.setCurrentWidget(self.ui.project_tab)
|
self.ui.notebook.setCurrentWidget(self.ui.project_tab)
|
||||||
|
|
||||||
|
# delete any text in the status bar, implicitly the last object name that was selected
|
||||||
|
self.inform.emit("")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# case when there is only an object under the click and we toggle it
|
# case when there is only an object under the click and we toggle it
|
||||||
if len(objects_under_the_click_list) == 1:
|
if len(objects_under_the_click_list) == 1:
|
||||||
@@ -4448,6 +4459,20 @@ class App(QtCore.QObject):
|
|||||||
# create the selection box around the selected object
|
# create the selection box around the selected object
|
||||||
curr_sel_obj = self.collection.get_active()
|
curr_sel_obj = self.collection.get_active()
|
||||||
self.draw_selection_shape(curr_sel_obj)
|
self.draw_selection_shape(curr_sel_obj)
|
||||||
|
|
||||||
|
if curr_sel_obj.kind == 'gerber':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('green', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'excellon':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('brown', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'cncjob':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('blue', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'geometry':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('red', str(curr_sel_obj.options['name'])))
|
||||||
|
|
||||||
elif self.collection.get_active().options['name'] not in objects_under_the_click_list:
|
elif self.collection.get_active().options['name'] not in objects_under_the_click_list:
|
||||||
self.collection.set_all_inactive()
|
self.collection.set_all_inactive()
|
||||||
self.delete_selection_shape()
|
self.delete_selection_shape()
|
||||||
@@ -4455,9 +4480,25 @@ class App(QtCore.QObject):
|
|||||||
# create the selection box around the selected object
|
# create the selection box around the selected object
|
||||||
curr_sel_obj = self.collection.get_active()
|
curr_sel_obj = self.collection.get_active()
|
||||||
self.draw_selection_shape(curr_sel_obj)
|
self.draw_selection_shape(curr_sel_obj)
|
||||||
|
|
||||||
|
if curr_sel_obj.kind == 'gerber':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('green', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'excellon':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('brown', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'cncjob':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('blue', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'geometry':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('red', str(curr_sel_obj.options['name'])))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.collection.set_all_inactive()
|
self.collection.set_all_inactive()
|
||||||
self.delete_selection_shape()
|
self.delete_selection_shape()
|
||||||
|
self.inform.emit("")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# If there is no selected object
|
# If there is no selected object
|
||||||
# make active the first element of the overlapped objects list
|
# make active the first element of the overlapped objects list
|
||||||
@@ -4482,6 +4523,19 @@ class App(QtCore.QObject):
|
|||||||
# create the selection box around the selected object
|
# create the selection box around the selected object
|
||||||
self.draw_selection_shape(curr_sel_obj)
|
self.draw_selection_shape(curr_sel_obj)
|
||||||
|
|
||||||
|
if curr_sel_obj.kind == 'gerber':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('green', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'excellon':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('brown', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'cncjob':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('blue', str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'geometry':
|
||||||
|
self.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
|
||||||
|
('red', str(curr_sel_obj.options['name'])))
|
||||||
|
|
||||||
# for obj in self.collection.get_list():
|
# for obj in self.collection.get_list():
|
||||||
# obj.plot()
|
# obj.plot()
|
||||||
# curr_sel_obj.plot(color=self.FC_dark_blue, face_color=self.FC_light_blue)
|
# curr_sel_obj.plot(color=self.FC_dark_blue, face_color=self.FC_light_blue)
|
||||||
|
|||||||
@@ -4016,9 +4016,11 @@ class FlatCAMInfoBar(QtWidgets.QWidget):
|
|||||||
|
|
||||||
layout.addStretch()
|
layout.addStretch()
|
||||||
|
|
||||||
def set_text_(self, text):
|
def set_text_(self, text, color=None):
|
||||||
self.text.setText(text)
|
self.text.setText(text)
|
||||||
self.text.setToolTip(text)
|
self.text.setToolTip(text)
|
||||||
|
if color:
|
||||||
|
self.text.setStyleSheet('color: %s' % str(color))
|
||||||
|
|
||||||
def set_status(self, text, level="info"):
|
def set_status(self, text, level="info"):
|
||||||
level = str(level)
|
level = str(level)
|
||||||
@@ -4029,9 +4031,11 @@ class FlatCAMInfoBar(QtWidgets.QWidget):
|
|||||||
self.pmap = QtGui.QPixmap('share/greenlight12.png')
|
self.pmap = QtGui.QPixmap('share/greenlight12.png')
|
||||||
elif level == "WARNING" or level == "WARNING_NOTCL":
|
elif level == "WARNING" or level == "WARNING_NOTCL":
|
||||||
self.pmap = QtGui.QPixmap('share/yellowlight12.png')
|
self.pmap = QtGui.QPixmap('share/yellowlight12.png')
|
||||||
|
elif level == "selected" or level == "SELECTED":
|
||||||
|
self.pmap = QtGui.QPixmap('share/bluelight12.png')
|
||||||
else:
|
else:
|
||||||
self.pmap = QtGui.QPixmap('share/graylight12.png')
|
self.pmap = QtGui.QPixmap('share/graylight12.png')
|
||||||
|
|
||||||
self.icon.setPixmap(self.pmap)
|
|
||||||
self.set_text_(text)
|
self.set_text_(text)
|
||||||
|
self.icon.setPixmap(self.pmap)
|
||||||
# end of file
|
# end of file
|
||||||
|
|||||||
161
GUIElements.py
161
GUIElements.py
@@ -1,14 +1,18 @@
|
|||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||||
|
from PyQt5.QtWidgets import QTextEdit, QCompleter, QAction
|
||||||
|
from PyQt5.QtGui import QColor, QKeySequence, QPalette, QTextCursor
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
import html
|
||||||
|
|
||||||
log = logging.getLogger('base')
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
EDIT_SIZE_HINT = 70
|
EDIT_SIZE_HINT = 70
|
||||||
|
|
||||||
|
|
||||||
class RadioSet(QtWidgets.QWidget):
|
class RadioSet(QtWidgets.QWidget):
|
||||||
activated_custom = QtCore.pyqtSignal()
|
activated_custom = QtCore.pyqtSignal()
|
||||||
|
|
||||||
@@ -1218,3 +1222,158 @@ class Dialog_box(QtWidgets.QWidget):
|
|||||||
|
|
||||||
self.location, self.ok = dialog_box.getText(self, title, label)
|
self.location, self.ok = dialog_box.getText(self, title, label)
|
||||||
|
|
||||||
|
|
||||||
|
class _BrowserTextEdit(QTextEdit):
|
||||||
|
|
||||||
|
def __init__(self, version):
|
||||||
|
QTextEdit.__init__(self)
|
||||||
|
self.menu = None
|
||||||
|
self.version = version
|
||||||
|
|
||||||
|
def contextMenuEvent(self, event):
|
||||||
|
self.menu = self.createStandardContextMenu(event.pos())
|
||||||
|
clear_action = QAction("Clear", self)
|
||||||
|
clear_action.setShortcut(QKeySequence(Qt.Key_Delete)) # it's not working, the shortcut
|
||||||
|
self.menu.addAction(clear_action)
|
||||||
|
clear_action.triggered.connect(self.clear)
|
||||||
|
self.menu.exec_(event.globalPos())
|
||||||
|
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
QTextEdit.clear(self)
|
||||||
|
text = "FlatCAM %s (c)2014-2019 Juan Pablo Caram (Type help to get started)\n\n" % self.version
|
||||||
|
text = html.escape(text)
|
||||||
|
text = text.replace('\n', '<br/>')
|
||||||
|
self.moveCursor(QTextCursor.End)
|
||||||
|
self.insertHtml(text)
|
||||||
|
|
||||||
|
|
||||||
|
class _ExpandableTextEdit(QTextEdit):
|
||||||
|
"""
|
||||||
|
Class implements edit line, which expands themselves automatically
|
||||||
|
"""
|
||||||
|
|
||||||
|
historyNext = pyqtSignal()
|
||||||
|
historyPrev = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, termwidget, *args):
|
||||||
|
QTextEdit.__init__(self, *args)
|
||||||
|
self.setStyleSheet("font: 9pt \"Courier\";")
|
||||||
|
self._fittedHeight = 1
|
||||||
|
self.textChanged.connect(self._fit_to_document)
|
||||||
|
self._fit_to_document()
|
||||||
|
self._termWidget = termwidget
|
||||||
|
|
||||||
|
self.completer = MyCompleter()
|
||||||
|
|
||||||
|
self.model = QtCore.QStringListModel()
|
||||||
|
self.completer.setModel(self.model)
|
||||||
|
self.set_model_data(keyword_list=[])
|
||||||
|
self.completer.insertText.connect(self.insertCompletion)
|
||||||
|
|
||||||
|
def set_model_data(self, keyword_list):
|
||||||
|
self.model.setStringList(keyword_list)
|
||||||
|
|
||||||
|
def insertCompletion(self, completion):
|
||||||
|
tc = self.textCursor()
|
||||||
|
extra = (len(completion) - len(self.completer.completionPrefix()))
|
||||||
|
tc.movePosition(QTextCursor.Left)
|
||||||
|
tc.movePosition(QTextCursor.EndOfWord)
|
||||||
|
tc.insertText(completion[-extra:])
|
||||||
|
self.setTextCursor(tc)
|
||||||
|
self.completer.popup().hide()
|
||||||
|
|
||||||
|
def focusInEvent(self, event):
|
||||||
|
if self.completer:
|
||||||
|
self.completer.setWidget(self)
|
||||||
|
QTextEdit.focusInEvent(self, event)
|
||||||
|
|
||||||
|
def keyPressEvent(self, event):
|
||||||
|
"""
|
||||||
|
Catch keyboard events. Process Enter, Up, Down
|
||||||
|
"""
|
||||||
|
if event.matches(QKeySequence.InsertParagraphSeparator):
|
||||||
|
text = self.toPlainText()
|
||||||
|
if self._termWidget.is_command_complete(text):
|
||||||
|
self._termWidget.exec_current_command()
|
||||||
|
return
|
||||||
|
elif event.matches(QKeySequence.MoveToNextLine):
|
||||||
|
text = self.toPlainText()
|
||||||
|
cursor_pos = self.textCursor().position()
|
||||||
|
textBeforeEnd = text[cursor_pos:]
|
||||||
|
|
||||||
|
if len(textBeforeEnd.split('\n')) <= 1:
|
||||||
|
self.historyNext.emit()
|
||||||
|
return
|
||||||
|
elif event.matches(QKeySequence.MoveToPreviousLine):
|
||||||
|
text = self.toPlainText()
|
||||||
|
cursor_pos = self.textCursor().position()
|
||||||
|
text_before_start = text[:cursor_pos]
|
||||||
|
# lineCount = len(textBeforeStart.splitlines())
|
||||||
|
line_count = len(text_before_start.split('\n'))
|
||||||
|
if len(text_before_start) > 0 and \
|
||||||
|
(text_before_start[-1] == '\n' or text_before_start[-1] == '\r'):
|
||||||
|
line_count += 1
|
||||||
|
if line_count <= 1:
|
||||||
|
self.historyPrev.emit()
|
||||||
|
return
|
||||||
|
elif event.matches(QKeySequence.MoveToNextPage) or \
|
||||||
|
event.matches(QKeySequence.MoveToPreviousPage):
|
||||||
|
return self._termWidget.browser().keyPressEvent(event)
|
||||||
|
|
||||||
|
tc = self.textCursor()
|
||||||
|
if event.key() == Qt.Key_Tab and self.completer.popup().isVisible():
|
||||||
|
self.completer.insertText.emit(self.completer.getSelected())
|
||||||
|
self.completer.setCompletionMode(QCompleter.PopupCompletion)
|
||||||
|
return
|
||||||
|
|
||||||
|
QTextEdit.keyPressEvent(self, event)
|
||||||
|
tc.select(QTextCursor.WordUnderCursor)
|
||||||
|
cr = self.cursorRect()
|
||||||
|
|
||||||
|
if len(tc.selectedText()) > 0:
|
||||||
|
self.completer.setCompletionPrefix(tc.selectedText())
|
||||||
|
popup = self.completer.popup()
|
||||||
|
popup.setCurrentIndex(self.completer.completionModel().index(0, 0))
|
||||||
|
|
||||||
|
cr.setWidth(self.completer.popup().sizeHintForColumn(0)
|
||||||
|
+ self.completer.popup().verticalScrollBar().sizeHint().width())
|
||||||
|
self.completer.complete(cr)
|
||||||
|
else:
|
||||||
|
self.completer.popup().hide()
|
||||||
|
|
||||||
|
def sizeHint(self):
|
||||||
|
"""
|
||||||
|
QWidget sizeHint impelemtation
|
||||||
|
"""
|
||||||
|
hint = QTextEdit.sizeHint(self)
|
||||||
|
hint.setHeight(self._fittedHeight)
|
||||||
|
return hint
|
||||||
|
|
||||||
|
def _fit_to_document(self):
|
||||||
|
"""
|
||||||
|
Update widget height to fit all text
|
||||||
|
"""
|
||||||
|
documentsize = self.document().size().toSize()
|
||||||
|
self._fittedHeight = documentsize.height() + (self.height() - self.viewport().height())
|
||||||
|
self.setMaximumHeight(self._fittedHeight)
|
||||||
|
self.updateGeometry()
|
||||||
|
|
||||||
|
def insertFromMimeData(self, mime_data):
|
||||||
|
# Paste only plain text.
|
||||||
|
self.insertPlainText(mime_data.text())
|
||||||
|
|
||||||
|
|
||||||
|
class MyCompleter(QCompleter):
|
||||||
|
insertText = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QCompleter.__init__(self)
|
||||||
|
self.setCompletionMode(QCompleter.PopupCompletion)
|
||||||
|
self.highlighted.connect(self.setHighlighted)
|
||||||
|
|
||||||
|
def setHighlighted(self, text):
|
||||||
|
self.lastSelected = text
|
||||||
|
|
||||||
|
def getSelected(self):
|
||||||
|
return self.lastSelected
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ CAD program, and create G-Code for Isolation routing.
|
|||||||
- added some new icons in the help menu and reorganized this menu
|
- added some new icons in the help menu and reorganized this menu
|
||||||
- added a new function and the shortcut 'leftquote' (left of Key 1) for toggle of the notebook section
|
- added a new function and the shortcut 'leftquote' (left of Key 1) for toggle of the notebook section
|
||||||
- changed the Shortcut list shortcut key to F3
|
- changed the Shortcut list shortcut key to F3
|
||||||
|
- moved some graphical classes out of Tool Shell to GUIElements.py where they belong
|
||||||
|
- when selecting an object on canvas by single click, it's name is displayed in status bar. When nothing is selected a blank message (nothing) it's displayed
|
||||||
|
- in Move Tool I've added the type of object that was moved in the status bar message
|
||||||
|
- color coded the status bar bullet to blue for selection
|
||||||
|
- the name of the selected objects are displayed in the status bar color coded: green for Gerber objects, Brown for Excellon, Red for Geometry and Blue for CNCJobs.
|
||||||
|
|
||||||
|
|
||||||
6.02.2019
|
6.02.2019
|
||||||
|
|
||||||
|
|||||||
@@ -139,12 +139,13 @@ class ToolMove(FlatCAMTool):
|
|||||||
proc.done()
|
proc.done()
|
||||||
# delete the selection bounding box
|
# delete the selection bounding box
|
||||||
self.delete_shape()
|
self.delete_shape()
|
||||||
|
self.app.inform.emit('[success]%s object was moved ...' %
|
||||||
|
str(sel_obj.kind).capitalize())
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': job_move, 'params': [self]})
|
self.app.worker_task.emit({'fcn': job_move, 'params': [self]})
|
||||||
|
|
||||||
self.clicked_move = 0
|
self.clicked_move = 0
|
||||||
self.toggle()
|
self.toggle()
|
||||||
self.app.inform.emit("[success]Object was moved ...")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|||||||
@@ -6,165 +6,12 @@
|
|||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
|
# from PyQt5.QtCore import pyqtSignal
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QTextCursor
|
||||||
|
from PyQt5.QtWidgets import QVBoxLayout, QWidget
|
||||||
|
from GUIElements import _BrowserTextEdit, _ExpandableTextEdit
|
||||||
import html
|
import html
|
||||||
from PyQt5.QtCore import pyqtSignal
|
|
||||||
from PyQt5.QtCore import Qt, QStringListModel
|
|
||||||
from PyQt5.QtGui import QColor, QKeySequence, QPalette, QTextCursor
|
|
||||||
from PyQt5.QtWidgets import QLineEdit, QSizePolicy, QTextEdit, QVBoxLayout, QWidget, QCompleter, QAction
|
|
||||||
|
|
||||||
class _BrowserTextEdit(QTextEdit):
|
|
||||||
|
|
||||||
def __init__(self, version):
|
|
||||||
QTextEdit.__init__(self)
|
|
||||||
self.menu = None
|
|
||||||
self.version = version
|
|
||||||
|
|
||||||
def contextMenuEvent(self, event):
|
|
||||||
self.menu = self.createStandardContextMenu(event.pos())
|
|
||||||
clear_action = QAction("Clear", self)
|
|
||||||
clear_action.setShortcut(QKeySequence(Qt.Key_Delete)) # it's not working, the shortcut
|
|
||||||
self.menu.addAction(clear_action)
|
|
||||||
clear_action.triggered.connect(self.clear)
|
|
||||||
self.menu.exec_(event.globalPos())
|
|
||||||
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
QTextEdit.clear(self)
|
|
||||||
text = "FlatCAM %s (c)2014-2019 Juan Pablo Caram (Type help to get started)\n\n" % self.version
|
|
||||||
text = html.escape(text)
|
|
||||||
text = text.replace('\n', '<br/>')
|
|
||||||
self.moveCursor(QTextCursor.End)
|
|
||||||
self.insertHtml(text)
|
|
||||||
|
|
||||||
class _ExpandableTextEdit(QTextEdit):
|
|
||||||
"""
|
|
||||||
Class implements edit line, which expands themselves automatically
|
|
||||||
"""
|
|
||||||
|
|
||||||
historyNext = pyqtSignal()
|
|
||||||
historyPrev = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, termwidget, *args):
|
|
||||||
QTextEdit.__init__(self, *args)
|
|
||||||
self.setStyleSheet("font: 9pt \"Courier\";")
|
|
||||||
self._fittedHeight = 1
|
|
||||||
self.textChanged.connect(self._fit_to_document)
|
|
||||||
self._fit_to_document()
|
|
||||||
self._termWidget = termwidget
|
|
||||||
|
|
||||||
self.completer = MyCompleter()
|
|
||||||
|
|
||||||
self.model = QStringListModel()
|
|
||||||
self.completer.setModel(self.model)
|
|
||||||
self.set_model_data(keyword_list=[])
|
|
||||||
self.completer.insertText.connect(self.insertCompletion)
|
|
||||||
|
|
||||||
def set_model_data(self, keyword_list):
|
|
||||||
self.model.setStringList(keyword_list)
|
|
||||||
|
|
||||||
def insertCompletion(self, completion):
|
|
||||||
tc = self.textCursor()
|
|
||||||
extra = (len(completion) - len(self.completer.completionPrefix()))
|
|
||||||
tc.movePosition(QTextCursor.Left)
|
|
||||||
tc.movePosition(QTextCursor.EndOfWord)
|
|
||||||
tc.insertText(completion[-extra:])
|
|
||||||
self.setTextCursor(tc)
|
|
||||||
self.completer.popup().hide()
|
|
||||||
|
|
||||||
def focusInEvent(self, event):
|
|
||||||
if self.completer:
|
|
||||||
self.completer.setWidget(self)
|
|
||||||
QTextEdit.focusInEvent(self, event)
|
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
|
||||||
"""
|
|
||||||
Catch keyboard events. Process Enter, Up, Down
|
|
||||||
"""
|
|
||||||
if event.matches(QKeySequence.InsertParagraphSeparator):
|
|
||||||
text = self.toPlainText()
|
|
||||||
if self._termWidget.is_command_complete(text):
|
|
||||||
self._termWidget.exec_current_command()
|
|
||||||
return
|
|
||||||
elif event.matches(QKeySequence.MoveToNextLine):
|
|
||||||
text = self.toPlainText()
|
|
||||||
cursor_pos = self.textCursor().position()
|
|
||||||
textBeforeEnd = text[cursor_pos:]
|
|
||||||
|
|
||||||
if len(textBeforeEnd.split('\n')) <= 1:
|
|
||||||
self.historyNext.emit()
|
|
||||||
return
|
|
||||||
elif event.matches(QKeySequence.MoveToPreviousLine):
|
|
||||||
text = self.toPlainText()
|
|
||||||
cursor_pos = self.textCursor().position()
|
|
||||||
text_before_start = text[:cursor_pos]
|
|
||||||
# lineCount = len(textBeforeStart.splitlines())
|
|
||||||
line_count = len(text_before_start.split('\n'))
|
|
||||||
if len(text_before_start) > 0 and \
|
|
||||||
(text_before_start[-1] == '\n' or text_before_start[-1] == '\r'):
|
|
||||||
line_count += 1
|
|
||||||
if line_count <= 1:
|
|
||||||
self.historyPrev.emit()
|
|
||||||
return
|
|
||||||
elif event.matches(QKeySequence.MoveToNextPage) or \
|
|
||||||
event.matches(QKeySequence.MoveToPreviousPage):
|
|
||||||
return self._termWidget.browser().keyPressEvent(event)
|
|
||||||
|
|
||||||
tc = self.textCursor()
|
|
||||||
if event.key() == Qt.Key_Tab and self.completer.popup().isVisible():
|
|
||||||
self.completer.insertText.emit(self.completer.getSelected())
|
|
||||||
self.completer.setCompletionMode(QCompleter.PopupCompletion)
|
|
||||||
return
|
|
||||||
|
|
||||||
QTextEdit.keyPressEvent(self, event)
|
|
||||||
tc.select(QTextCursor.WordUnderCursor)
|
|
||||||
cr = self.cursorRect()
|
|
||||||
|
|
||||||
if len(tc.selectedText()) > 0:
|
|
||||||
self.completer.setCompletionPrefix(tc.selectedText())
|
|
||||||
popup = self.completer.popup()
|
|
||||||
popup.setCurrentIndex(self.completer.completionModel().index(0, 0))
|
|
||||||
|
|
||||||
cr.setWidth(self.completer.popup().sizeHintForColumn(0)
|
|
||||||
+ self.completer.popup().verticalScrollBar().sizeHint().width())
|
|
||||||
self.completer.complete(cr)
|
|
||||||
else:
|
|
||||||
self.completer.popup().hide()
|
|
||||||
|
|
||||||
def sizeHint(self):
|
|
||||||
"""
|
|
||||||
QWidget sizeHint impelemtation
|
|
||||||
"""
|
|
||||||
hint = QTextEdit.sizeHint(self)
|
|
||||||
hint.setHeight(self._fittedHeight)
|
|
||||||
return hint
|
|
||||||
|
|
||||||
def _fit_to_document(self):
|
|
||||||
"""
|
|
||||||
Update widget height to fit all text
|
|
||||||
"""
|
|
||||||
documentsize = self.document().size().toSize()
|
|
||||||
self._fittedHeight = documentsize.height() + (self.height() - self.viewport().height())
|
|
||||||
self.setMaximumHeight(self._fittedHeight)
|
|
||||||
self.updateGeometry()
|
|
||||||
|
|
||||||
def insertFromMimeData(self, mime_data):
|
|
||||||
# Paste only plain text.
|
|
||||||
self.insertPlainText(mime_data.text())
|
|
||||||
|
|
||||||
|
|
||||||
class MyCompleter(QCompleter):
|
|
||||||
insertText = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
QCompleter.__init__(self)
|
|
||||||
self.setCompletionMode(QCompleter.PopupCompletion)
|
|
||||||
self.highlighted.connect(self.setHighlighted)
|
|
||||||
|
|
||||||
def setHighlighted(self, text):
|
|
||||||
self.lastSelected = text
|
|
||||||
|
|
||||||
def getSelected(self):
|
|
||||||
return self.lastSelected
|
|
||||||
|
|
||||||
|
|
||||||
class TermWidget(QWidget):
|
class TermWidget(QWidget):
|
||||||
@@ -234,7 +81,7 @@ class TermWidget(QWidget):
|
|||||||
"""
|
"""
|
||||||
Convert text to HTML for inserting it to browser
|
Convert text to HTML for inserting it to browser
|
||||||
"""
|
"""
|
||||||
assert style in ('in', 'out', 'err', 'warning', 'success')
|
assert style in ('in', 'out', 'err', 'warning', 'success', 'selected')
|
||||||
|
|
||||||
text = html.escape(text)
|
text = html.escape(text)
|
||||||
text = text.replace('\n', '<br/>')
|
text = text.replace('\n', '<br/>')
|
||||||
@@ -247,6 +94,8 @@ class TermWidget(QWidget):
|
|||||||
text = '<span style="font-weight: bold; color: rgb(244, 182, 66);">%s</span>' % text
|
text = '<span style="font-weight: bold; color: rgb(244, 182, 66);">%s</span>' % text
|
||||||
elif style == 'success':
|
elif style == 'success':
|
||||||
text = '<span style="font-weight: bold; color: rgb(8, 68, 0);">%s</span>' % text
|
text = '<span style="font-weight: bold; color: rgb(8, 68, 0);">%s</span>' % text
|
||||||
|
elif style == 'selected':
|
||||||
|
text = '<span style="font-weight: bold; color: rgb(0, 8, 255);">%s</span>' % text
|
||||||
else:
|
else:
|
||||||
text = '<span>%s</span>' % text # without span <br/> is ignored!!!
|
text = '<span>%s</span>' % text # without span <br/> is ignored!!!
|
||||||
|
|
||||||
@@ -313,6 +162,11 @@ class TermWidget(QWidget):
|
|||||||
"""
|
"""
|
||||||
self._append_to_browser('success', text)
|
self._append_to_browser('success', text)
|
||||||
|
|
||||||
|
def append_selected(self, text):
|
||||||
|
"""Appent text to output widget
|
||||||
|
"""
|
||||||
|
self._append_to_browser('selected', text)
|
||||||
|
|
||||||
def append_warning(self, text):
|
def append_warning(self, text):
|
||||||
"""Appent text to output widget
|
"""Appent text to output widget
|
||||||
"""
|
"""
|
||||||
@@ -352,6 +206,7 @@ class TermWidget(QWidget):
|
|||||||
self._edit.setPlainText(self._history[self._historyIndex])
|
self._edit.setPlainText(self._history[self._historyIndex])
|
||||||
self._edit.moveCursor(QTextCursor.End)
|
self._edit.moveCursor(QTextCursor.End)
|
||||||
|
|
||||||
|
|
||||||
class FCShell(TermWidget):
|
class FCShell(TermWidget):
|
||||||
def __init__(self, sysShell, version, *args):
|
def __init__(self, sysShell, version, *args):
|
||||||
TermWidget.__init__(self, version, *args)
|
TermWidget.__init__(self, version, *args)
|
||||||
|
|||||||
BIN
share/bluelight12.png
Normal file
BIN
share/bluelight12.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 313 B |
Reference in New Issue
Block a user