290 lines
12 KiB
Python
290 lines
12 KiB
Python
#!/opt/homebrew/bin/python3
|
|
# -*- coding:utf-8 -*-
|
|
|
|
from PyQt6.QtCore import *
|
|
from PyQt6.Qsci import QsciLexerPython, QsciScintilla, QsciAPIs,QsciCommand
|
|
from PyQt6.QtWidgets import *
|
|
from PyQt6.QtGui import QFont, QColor, QKeySequence, QShortcut,QIcon
|
|
import keyword
|
|
from common import MarkdownViewer
|
|
import time
|
|
|
|
class highlight(QsciLexerPython):
|
|
def __init__(self, parent):
|
|
super().__init__(parent)
|
|
font = QFont()
|
|
font.setFamily('Courier')
|
|
font.setPointSize(12)
|
|
font.setFixedPitch(True)
|
|
self.setFont(font)
|
|
self.setColor(QColor(0, 0, 0))
|
|
self.setPaper(QColor(255, 255, 255))
|
|
self.setColor(QColor("#00FF00"), QsciLexerPython.ClassName)
|
|
self.setColor(QColor("#B0171F"), QsciLexerPython.Keyword)
|
|
self.setColor(QColor("#3CB371"), QsciLexerPython.Comment)
|
|
self.setColor(QColor("#FF00FF"), QsciLexerPython.Number)
|
|
self.setColor(QColor("#0000FF"), QsciLexerPython.DoubleQuotedString)
|
|
self.setColor(QColor("#0000FF"), QsciLexerPython.SingleQuotedString)
|
|
self.setColor(QColor("#288B22"), QsciLexerPython.TripleSingleQuotedString)
|
|
self.setColor(QColor("#288B22"), QsciLexerPython.TripleDoubleQuotedString)
|
|
self.setColor(QColor("#0000FF"), QsciLexerPython.FunctionMethodName)
|
|
self.setColor(QColor("#191970"), QsciLexerPython.Operator)
|
|
self.setColor(QColor("#000000"), QsciLexerPython.Identifier)
|
|
self.setColor(QColor("#3CB371"), QsciLexerPython.CommentBlock)
|
|
self.setColor(QColor("#0000FF"), QsciLexerPython.UnclosedString)
|
|
self.setColor(QColor("#FFFF00"), QsciLexerPython.HighlightedIdentifier)
|
|
self.setColor(QColor("#FF8000"), QsciLexerPython.Decorator)
|
|
self.setFont(QFont('Courier', 12, weight=QFont.Weight.Bold), 5)
|
|
self.setFont(QFont('Courier', 12, italic=True), QsciLexerPython.Comment)
|
|
|
|
class CommentCommand(QsciCommand):
|
|
def __init__(self, editor):
|
|
super().__init__(editor)
|
|
|
|
def execute(self):
|
|
editor = self.editor()
|
|
line_from, index_from, line_to, index_to = editor.getSelection()
|
|
|
|
# 如果没有选中文本,就注释当前行
|
|
if line_from < 0 or line_to < 0:
|
|
line_from, line_to = editor.getCursorPosition()
|
|
|
|
for line in range(line_from, line_to + 1):
|
|
text = editor.text(line)
|
|
if text.startswith('#'):
|
|
editor.setSelection(line, 0, line, 1)
|
|
editor.removeSelectedText()
|
|
else:
|
|
editor.insertAt('#', line, 0)
|
|
|
|
class CodeDialog(QDialog):
|
|
|
|
def __init__(self, title='指令脚本编辑'):
|
|
super().__init__()
|
|
self.mkviewer = MarkdownViewer()
|
|
font = QFont()
|
|
self.oldTime = 0
|
|
font.setFamily('Courier')
|
|
font.setPointSize(12)
|
|
font.setFixedPitch(True)
|
|
self.setFont(font)
|
|
self.editor = QsciScintilla()
|
|
self.editor.setFont(font)
|
|
# layout = QVBoxLayout()
|
|
# layout.addWidget(self.editor)
|
|
|
|
# 设置窗口标题和大小
|
|
self.setWindowTitle(title)
|
|
|
|
screen = QApplication.primaryScreen() # 获取主屏幕
|
|
screen_size = screen.size() # 获取屏幕大小
|
|
|
|
self.original_size = (1200, 900)
|
|
# 计算缩放比例
|
|
|
|
scale_x = screen_size.width() / 1920
|
|
scale_y = screen_size.height() / 1080
|
|
width = int(1200 * scale_x)
|
|
height = int(900 * scale_y)
|
|
self.setFixedWidth(width)
|
|
self.setFixedHeight(height)
|
|
self.helpType = "instruction"
|
|
# 创建自定义标题栏
|
|
self.title_bar = QFrame(self)
|
|
self.title_bar.setFixedHeight(30)
|
|
self.title_bar.setStyleSheet(" QWidget QPushButton {\
|
|
subcontrol-origin: content; /* 设置子部件的原点为content */\
|
|
color: rgb(255, 255, 255); \
|
|
border: none; /* 去掉按钮的边框 */\
|
|
}\
|
|
QWidget{\
|
|
background-color: qlineargradient(spread:pad, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(191, 205, 220, 255), stop:1 rgba(214, 227, 241, 255));\
|
|
}")
|
|
self.title_bar.mousePressEvent = self.toolbar_mousePressEvent
|
|
self.title_bar.mouseMoveEvent = self.toolbar_mouseMoveEvent
|
|
self.title_bar.mouseReleaseEvent = self.toolbar_mouseReleaseEvent
|
|
# 标题栏布局
|
|
title_layout = QHBoxLayout(self.title_bar)
|
|
title_layout.setContentsMargins(0, 0, 0, 0)
|
|
# 添加系统图标
|
|
icon_label = QLabel(self.title_bar)
|
|
icon_label.setPixmap(QIcon(':/resource/logo.ico').pixmap(20, 20)) # 设置图标尺寸
|
|
title_layout.addWidget(icon_label)
|
|
# 添加标题文本
|
|
title_label = QLabel(title, self.title_bar)
|
|
title_layout.addWidget(title_label)
|
|
|
|
title_layout.addStretch(1)
|
|
# 添加帮助按钮
|
|
help_button = QPushButton( self.title_bar)
|
|
help_button.setIcon(QIcon(":/resource/help.png"))
|
|
help_button.setToolTip("帮助")
|
|
help_button.clicked.connect(self.showHelp)
|
|
help_button.setFixedSize(50, 30) # 设置按钮宽度为50像素
|
|
title_layout.addWidget(help_button)
|
|
# 添加关闭按钮
|
|
close_button = QPushButton(self.title_bar)
|
|
close_button.setIcon(QIcon(":/resource/w_close.png"))
|
|
close_button.setFixedSize(50, 30)
|
|
close_button.clicked.connect(self.cancelClick)
|
|
title_layout.addWidget(close_button)
|
|
|
|
|
|
# 主窗口布局
|
|
main_layout = QVBoxLayout(self)
|
|
main_layout.addWidget(self.title_bar)
|
|
main_layout.addWidget(self.editor)
|
|
|
|
main_layout.setContentsMargins(1, 1, 1, 1)
|
|
main_layout.setSpacing(0)
|
|
rowlayout = QHBoxLayout()
|
|
btnOk = QPushButton("确认")
|
|
btnCancel = QPushButton("取消")
|
|
btnOk.clicked.connect(self.okClick )
|
|
btnCancel.clicked.connect(self.cancelClick )
|
|
rowlayout.addWidget(btnOk)
|
|
rowlayout.addWidget(btnCancel)
|
|
main_layout.addLayout(rowlayout)
|
|
|
|
self.editor.setUtf8(True)
|
|
self.editor.setMarginsFont(font)
|
|
self.editor.setMarginWidth(0, len(str(len(self.editor.text().split('\n')))) * 20)
|
|
self.editor.setMarginLineNumbers(0, True)
|
|
self.editor.setEdgeColumn(80)
|
|
self.editor.setEdgeColor(QColor(0, 0, 0))
|
|
self.setWindowFlags(Qt.WindowType.FramelessWindowHint|Qt.WindowType.WindowCloseButtonHint|Qt.WindowType.WindowContextHelpButtonHint)
|
|
self.editor.setBraceMatching(QsciScintilla.BraceMatch.StrictBraceMatch)
|
|
self.editor.setIndentationsUseTabs(False)
|
|
self.editor.setIndentationWidth(4)
|
|
self.editor.setTabIndents(True)
|
|
self.editor.setAutoIndent(True)
|
|
self.editor.setBackspaceUnindents(True)
|
|
self.editor.setTabWidth(4)
|
|
self.editor.setCaretLineVisible(True)
|
|
self.editor.setCaretLineBackgroundColor(QColor('#FFFFCD'))
|
|
self.editor.setIndentationGuides(True)
|
|
self.editor.setFolding(QsciScintilla.FoldStyle.PlainFoldStyle)
|
|
self.editor.setMarginWidth(2, 12)
|
|
self.editor.markerDefine(QsciScintilla.MarkerSymbol.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPEN)
|
|
self.editor.markerDefine(QsciScintilla.MarkerSymbol.Plus, QsciScintilla.SC_MARKNUM_FOLDER)
|
|
self.editor.markerDefine(QsciScintilla.MarkerSymbol.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
|
|
self.editor.markerDefine(QsciScintilla.MarkerSymbol.Plus, QsciScintilla.SC_MARKNUM_FOLDEREND)
|
|
self.editor.setMarkerBackgroundColor(QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEREND)
|
|
self.editor.setMarkerForegroundColor(QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEREND)
|
|
self.editor.setMarkerBackgroundColor(QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
|
|
self.editor.setMarkerForegroundColor(QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
|
|
self.editor.setAutoCompletionSource(QsciScintilla.AutoCompletionSource.AcsAll)
|
|
self.editor.setAutoCompletionCaseSensitivity(True)
|
|
self.editor.setAutoCompletionReplaceWord(False)
|
|
self.editor.setAutoCompletionThreshold(1)
|
|
self.editor.setAutoCompletionUseSingle(QsciScintilla.AutoCompletionUseSingle.AcusExplicit)
|
|
self.lexer = highlight(self.editor)
|
|
self.editor.setLexer(self.lexer)
|
|
self.mod = False
|
|
self.context = ""
|
|
self.__api = QsciAPIs(self.lexer)
|
|
autocompletions = keyword.kwlist + ["abs", "all", "any", "basestring", "bool",
|
|
"callable", "chr", "classmethod", "cmp", "compile",
|
|
"complex", "delattr", "dict", "dir", "divmod",
|
|
"enumerate", "eval", "execfile", "exit", "file",
|
|
"filter", "float", "frozenset", "getattr", "globals",
|
|
"hasattr", "hex", "id", "int", "isinstance",
|
|
"issubclass", "iter", "len", "list", "locals", "map",
|
|
"max", "min", "object", "oct", "open", "ord", "pow",
|
|
"property", "range", "reduce", "repr", "reversed",
|
|
"round", "set", "setattr", "slice", "sorted",
|
|
"staticmethod", "str", "sum", "super", "tuple", "type",
|
|
"vars", "zip", 'print',
|
|
'log', 'send', 'start', 'finish']
|
|
for ac in autocompletions:
|
|
self.__api.add(ac)
|
|
self.__api.prepare()
|
|
self.editor.autoCompleteFromAll()
|
|
self.name = ''
|
|
self.editor.textChanged.connect(self.changed)
|
|
|
|
# 设置快捷键
|
|
self.comment_shortcut = QShortcut(QKeySequence('Ctrl+k'), self)
|
|
self.comment_shortcut.activated.connect(self.comment_code)
|
|
|
|
def toolbar_mousePressEvent(self, event):
|
|
if event.button() == Qt.MouseButton.LeftButton:
|
|
self.oldPos = event.globalPosition()
|
|
|
|
def toolbar_mouseMoveEvent(self, event):
|
|
if self.oldPos:
|
|
delta = event.globalPosition() - self.oldPos
|
|
new_pos = self.pos() + QPoint(delta.toPoint())
|
|
self.move(new_pos)
|
|
self.oldPos = event.globalPosition()
|
|
|
|
def toolbar_mouseReleaseEvent(self, event):
|
|
if event.button() == Qt.MouseButton.LeftButton:
|
|
self.oldPos = None
|
|
|
|
def showHelp(self):
|
|
if self.helpType == "instruction":
|
|
self.mkviewer.showMarkdown("help.md")
|
|
elif self.helpType == "task":
|
|
self.mkviewer.showMarkdown("help_task.md")
|
|
|
|
def comment_code(self):
|
|
line_from, index_from, line_to, index_to = self.editor.getSelection()
|
|
|
|
# 如果没有选中文本,就注释当前行
|
|
if line_from < 0 or line_to < 0:
|
|
line = self.editor.getCursorPosition()[0]
|
|
text = self.editor.text(line)
|
|
if text.startswith('#'):
|
|
self.editor.setSelection(line, 0, line, 1)
|
|
self.editor.removeSelectedText()
|
|
else:
|
|
self.editor.insertAt('#', line, 0)
|
|
else:
|
|
for line in range(line_from, line_to + 1):
|
|
text = self.editor.text(line)
|
|
if text.startswith('#'):
|
|
self.editor.setSelection(line, 0, line, 1)
|
|
self.editor.removeSelectedText()
|
|
else:
|
|
self.editor.insertAt('#', line, 0)
|
|
|
|
def okClick(self):
|
|
self.context = self.editor.text()
|
|
self.close()
|
|
|
|
def cancelClick(self):
|
|
self.context = ""
|
|
self.close()
|
|
|
|
def changed(self):
|
|
self.mod = True
|
|
self.editor.setMarginWidth(0, len(str(len(self.editor.text().split('\n')))) * 20)
|
|
|
|
def getValue(self):
|
|
return self.editor.text()
|
|
|
|
def closeEvent(self, event):
|
|
event.accept()
|
|
|
|
@pyqtSlot(str, result=str)
|
|
def showEditor(self,text):
|
|
self.editor.setText(text)
|
|
self.exec()
|
|
result = self.getValue() # 获取子窗口返回的值
|
|
self.editor.setText("")
|
|
# if result == "":
|
|
# return text
|
|
# else:
|
|
return result
|
|
|
|
def showEditDlg(self, text, htype="instruction"):
|
|
self.helpType = htype
|
|
self.editor.setText(text)
|
|
self.exec()
|
|
result = self.context # 获取子窗口返回的值
|
|
self.editor.setText("")
|
|
# if result == "":
|
|
# return text
|
|
# else:
|
|
return result |