def __init__(self, parent): super(NCEditor, self).__init__(parent) # Set the default font. if system() == "Windows": font_name = "Courier New" else: font_name = "Mono" self.font = QFont(font_name) self.font.setFixedPitch(True) self.font.setPointSize(14) self.setFont(self.font) self.setMarginsFont(self.font) self.setUtf8(True) self.setEolMode(QsciScintilla.EolUnix) # Margin 0 is used for line numbers. font_metrics = QFontMetrics(self.font) self.setMarginsFont(self.font) self.setMarginWidth(0, font_metrics.width("0000") + 4) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("#cccccc")) # Current line visible with special background color. self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#ffe4e4")) # Don't want to see the horizontal scrollbar at all. self.setWrapMode(QsciScintilla.WrapWord) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Keyword indicator [1] self.indicatorDefine(QsciScintilla.BoxIndicator, 1) self.cursorPositionChanged.connect(self.__catch_word)
def drawLink(self, name: str, points: Tuple[int]): """Draw linkage function. The link color will be the default color. """ color = colorQt('Blue') pen = QPen(color) pen.setWidth(self.linkWidth) self.painter.setPen(pen) brush = QColor(226, 219, 190) brush.setAlphaF(0.70) self.painter.setBrush(brush) qpoints = tuple( QPointF(self.Point[i][0] * self.zoom, self.Point[i][1] * -self.zoom) for i in points if self.Point[i] and not isnan(self.Point[i][0])) if len(qpoints) == len(points): self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) if self.showPointMark and name != 'ground' and qpoints: pen.setColor(Qt.darkGray) self.painter.setPen(pen) self.painter.setFont(QFont('Arial', self.fontSize)) text = "[{}]".format(name) cenX = sum(self.Point[i][0] for i in points if self.Point[i]) cenY = sum(self.Point[i][1] for i in points if self.Point[i]) cenX *= self.zoom / len(points) cenY *= -self.zoom / len(points) self.painter.drawText(QPointF(cenX, cenY), text)
def __drawSlvsRanges(self): """Draw solving range.""" pen = QPen() self.painter.setFont(QFont("Arial", self.fontSize + 5)) pen.setWidth(5) for i, (tag, rect) in enumerate(self.ranges.items()): range_color = QColor(colorNum(i + 1)) range_color.setAlpha(30) self.painter.setBrush(range_color) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) cx = rect.x() * self.zoom cy = rect.y() * -self.zoom if rect.width(): self.painter.drawRect( QRectF(cx, cy, rect.width() * self.zoom, rect.height() * self.zoom)) else: self.painter.drawEllipse(QPointF(cx, cy), 3, 3) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) self.painter.drawText(QPointF(cx + 6, cy - 6), tag) self.painter.setBrush(Qt.NoBrush)
def __draw_link(self, name: str, points: List[int]): """Draw link function. The link color will be the default color. """ color = color_qt('Blue') pen = QPen(color) pen.setWidth(self.link_width) self.painter.setPen(pen) brush = QColor(226, 219, 190) brush.setAlphaF(0.70) self.painter.setBrush(brush) qpoints = tuple( QPointF(self.pos[i][0], -self.pos[i][1]) * self.zoom for i in points if self.pos[i] and (not isnan(self.pos[i][0])) ) if len(qpoints) == len(points): self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) if self.show_point_mark and (name != 'ground') and qpoints: pen.setColor(Qt.darkGray) self.painter.setPen(pen) self.painter.setFont(QFont('Arial', self.font_size)) text = f"[{name}]" cen_x = sum(self.pos[i][0] for i in points if self.pos[i]) cen_y = sum(self.pos[i][1] for i in points if self.pos[i]) self.painter.drawText(QPointF(cen_x, -cen_y) * self.zoom / len(points), text)
def drawPoint(self, i: int, cx, cy, fix: bool, color: QColor ): """Draw a joint.""" pen = QPen(color) pen.setWidth(2) self.painter.setPen(pen) x = cx*self.zoom y = cy*-self.zoom if fix: bottom = y + 20 width = 10 #Draw a triangle below. self.painter.drawPolygon( QPointF(x, y), QPointF(x - width, bottom), QPointF(x + width, bottom) ) self.painter.drawEllipse(QPointF(x, y), width, width) else: self.painter.drawEllipse(QPointF(x, y), 5, 5) if not self.showPointMark: return pen.setColor(Qt.darkGray) pen.setWidth(2) self.painter.setPen(pen) self.painter.setFont(QFont("Arial", self.fontSize)) text = "[{}]".format(i) if type(i)==str else "[Point{}]".format(i) if self.showDimension: text += ":({:.02f}, {:.02f})".format(cx, cy) self.painter.drawText(QPointF(x+6, y-6), text)
def __init__(self, Title, axisX, axisY, parent=None): super(DataChart, self).__init__(parent) self.setTitle(Title) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) legend = self.legend() legend.setAlignment(Qt.AlignBottom) legend.setFont(QFont(legend.font().family(), 12, QFont.Medium)) self.addAxis(axisX, Qt.AlignBottom) self.addAxis(axisY, Qt.AlignLeft)
def __init__(self, title: str, axis_x: QValueAxis, axis_y: QValueAxis): """Input title and two axis, QChart class has no parent.""" super(DataChart, self).__init__() self.setTitle(title) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) legend = self.legend() legend.setAlignment(Qt.AlignBottom) legend.setFont(QFont(legend.font().family(), 12, QFont.Medium)) self.addAxis(axis_x, Qt.AlignBottom) self.addAxis(axis_y, Qt.AlignLeft)
def paintEvent(self, event): """Using a QPainter under 'self', so just change QPen or QBrush before painting. """ self.painter.begin(self) self.painter.fillRect(event.rect(), QBrush(Qt.white)) # Translation self.painter.translate(self.ox, self.oy) # Background if not self.background.isNull(): rect = self.background.rect() self.painter.setOpacity(self.background_opacity) img_origin: QPointF = self.background_offset * self.zoom self.painter.drawImage( QRectF(img_origin, QSizeF( rect.width() * self.background_scale * self.zoom, rect.height() * self.background_scale * self.zoom )), self.background, QRectF(rect) ) self.painter.setOpacity(1) # Show frame. pen = QPen(Qt.blue) pen.setWidth(1) self.painter.setPen(pen) self.painter.setFont(QFont("Arial", self.font_size)) # Draw origin lines. pen.setColor(Qt.gray) self.painter.setPen(pen) x_l = -self.ox x_r = self.width() - self.ox self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0)) y_t = self.height() - self.oy y_b = -self.oy self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t)) def indexing(v): """Draw tick.""" return int(v / self.zoom - v / self.zoom % 5) for x in range(indexing(x_l), indexing(x_r) + 1, 5): self.painter.drawLine( QPointF(x, 0) * self.zoom, QPointF(x * self.zoom, -10 if x % 10 == 0 else -5) ) for y in range(indexing(y_b), indexing(y_t) + 1, 5): self.painter.drawLine( QPointF(0, y) * self.zoom, QPointF(10 if y % 10 == 0 else 5, y * self.zoom) )
def paintEvent(self, event): """Drawing functions.""" width = self.width() height = self.height() if ((self.width_old is not None) and ((self.width_old != width) or (self.height_old != height))): self.ox += (width - self.width_old) / 2 self.oy += (height - self.height_old) / 2 super(DynamicCanvas, self).paintEvent(event) self.painter.setFont(QFont('Arial', self.fontSize)) if self.freemove != FreeMode.NoFreeMove: #Draw a colored frame for free move mode. pen = QPen() if self.freemove == FreeMode.Translate: pen.setColor(QColor(161, 105, 229)) elif self.freemove == FreeMode.Rotate: pen.setColor(QColor(219, 162, 6)) elif self.freemove == FreeMode.Reflect: pen.setColor(QColor(79, 249, 193)) pen.setWidth(8) self.painter.setPen(pen) self.__drawFrame() #Draw links except ground. for vlink in self.Links[1:]: self.__drawLink(vlink) #Draw path. if self.Path.show != -2: self.__drawPath() #Draw solving path. if self.showTargetPath: self.__drawSlvsRanges() self._BaseCanvas__drawTargetPath() #Draw points. for i, vpoint in enumerate(self.Points): self.__drawPoint(i, vpoint) #Rectangular selection if self.Selector.RectangularSelection: pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) self.painter.drawRect( QRectF(QPointF(self.Selector.x, self.Selector.y), QPointF(self.Selector.sx, self.Selector.sy))) self.painter.end() #Record the widget size. self.width_old = width self.height_old = height
def __draw_arrow( self, x1: float, y1: float, x2: float, y2: float, *, zoom: bool = False, text: str = '' ): """Front point -> Back point""" if zoom: x1 *= self.zoom y1 *= self.zoom x2 *= self.zoom y2 *= self.zoom a = atan2(y2 - y1, x2 - x1) x1 = (x1 + x2) / 2 - 7.5 * cos(a) y1 = (y1 + y2) / 2 - 7.5 * sin(a) first_point = QPointF(x1, y1) self.painter.drawLine(first_point, QPointF( x1 + 15 * cos(a + radians(20)), y1 + 15 * sin(a + radians(20)) )) self.painter.drawLine(first_point, QPointF( x1 + 15 * cos(a - radians(20)), y1 + 15 * sin(a - radians(20)) )) if not text: return # Font font = self.painter.font() font_copy = QFont(font) font.setBold(True) font.setPointSize(font.pointSize() + 8) self.painter.setFont(font) # Color pen = self.painter.pen() color = pen.color() pen.setColor(color.darker()) self.painter.setPen(pen) self.painter.drawText(first_point, text) pen.setColor(color) self.painter.setPen(pen) self.painter.setFont(font_copy)
def paintEvent(self, event): """Drawing functions.""" width = self.width() height = self.height() if self.width_old != width or self.height_old != height: self.ox += (width - self.width_old) / 2 self.oy += (height - self.height_old) / 2 super(DynamicCanvas, self).paintEvent(event) self.painter.setFont(QFont('Arial', self.fontSize)) if self.freemove: #Draw a colored frame for free move mode. pen = QPen() if self.freemove == 1: pen.setColor(QColor(161, 105, 229)) elif self.freemove == 2: pen.setColor(QColor(219, 162, 6)) elif self.freemove == 3: pen.setColor(QColor(79, 249, 193)) pen.setWidth(8) self.painter.setPen(pen) self.drawFrame() if self.Selector.RectangularSelection: pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) self.painter.drawRect( QRectF(QPointF(self.Selector.x, self.Selector.y), QPointF(self.Selector.sx, self.Selector.sy))) #Draw links. for vlink in self.Link[1:]: self.drawLink(vlink) #Draw path. if self.Path.show > -2: self.drawPath() #Draw solving path. if self.showTargetPath: self.drawSlvsRanges() self.drawTargetPath() #Draw points. for i, vpoint in enumerate(self.Point): self.drawPoint(i, vpoint) self.painter.end() self.width_old = width self.height_old = height
class NCEditor(QsciScintilla): """NC code editor.""" def __init__(self, parent): super(NCEditor, self).__init__(parent) # Set the default font. if system() == "Windows": font_name = "Courier New" else: font_name = "Mono" self.font = QFont(font_name) self.font.setFixedPitch(True) self.font.setPointSize(14) self.setFont(self.font) self.setMarginsFont(self.font) self.setUtf8(True) self.setEolMode(QsciScintilla.EolUnix) # Margin 0 is used for line numbers. font_metrics = QFontMetrics(self.font) self.setMarginsFont(self.font) self.setMarginWidth(0, font_metrics.width("0000") + 4) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("#cccccc")) # Current line visible with special background color. self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#ffe4e4")) # Don't want to see the horizontal scrollbar at all. self.setWrapMode(QsciScintilla.WrapWord) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Keyword indicator [1] self.indicatorDefine(QsciScintilla.BoxIndicator, 1) self.cursorPositionChanged.connect(self.__catch_word) @pyqtSlot(int, int) def __catch_word(self, line: int, index: int): """Catch and indicate current word.""" self.__clear_indicator_all(1) pos = self.positionFromLineIndex(line, index) _, _, word = self.__word_at_pos(pos) word = r'\b' + word + r'\b' for m in re.finditer(word.encode('utf-8'), self.text().encode('utf-8'), re.IGNORECASE): self.fillIndicatorRange(*self.lineIndexFromPosition(m.start()), *self.lineIndexFromPosition(m.end()), 1) def __word_at_pos(self, pos: int) -> Tuple[int, int, str]: """Return pos of current word.""" return (self.SendScintilla(QsciScintilla.SCI_WORDSTARTPOSITION, pos, True), self.SendScintilla(QsciScintilla.SCI_WORDENDPOSITION, pos, True), self.wordAtLineIndex(*self.getCursorPosition())) def __clear_indicator_all(self, indicator: int): """Clear all indicators.""" self.clearIndicatorRange(0, 0, *self.lineIndexFromPosition(self.length()), indicator)
def paintEvent(self, event): """Draw the structure.""" width = self.width() height = self.height() self.ox = width / 2 self.oy = height / 2 sq_w = 240 if width <= height: self.zoom = width / sq_w else: self.zoom = height / sq_w super(PreviewCanvas, self).paintEvent(event) self.__drawLimit(sq_w) pen = QPen() pen.setWidth(RADIUS) self.painter.setPen(pen) self.painter.setBrush(QBrush(QColor(226, 219, 190, 150))) #Links for link in self.G.nodes: if link == self.grounded: continue points = [] #Points that is belong with the link. for num, edge in edges_view(self.G): if link in edge: if num in self.same: num = self.same[num] x, y = self.pos[num] points.append((x * self.zoom, y * -self.zoom)) #Customize points. for name, link_ in self.cus.items(): if link == link_: x, y = self.pos[int(name.replace('P', ''))] points.append((x * self.zoom, y * -self.zoom)) self.painter.drawPolygon(*convex_hull(points)) self.painter.setFont(QFont("Arial", self.fontSize)) #Nodes for node, (x, y) in self.pos.items(): if node in self.same: continue x *= self.zoom y *= -self.zoom if node in (self.Driver, self.Target): if node == self.Driver: pen.setColor(colorQt('Red')) elif node == self.Target: pen.setColor(colorQt('Yellow')) self.painter.setPen(pen) self.painter.drawEllipse(QPointF(x, y), RADIUS, RADIUS) if self.getStatus(node): color = colorQt('Dark-Magenta') else: color = colorQt('Green') pen.setColor(color) self.painter.setPen(pen) self.painter.setBrush(QBrush(color)) self.painter.drawEllipse(QPointF(x, y), RADIUS, RADIUS) pen.setColor(colorQt('Black')) self.painter.setPen(pen) #Solutions if self.showSolutions: solutions = self.get_solutions() if solutions: for expr in solutions.split(';'): self._BaseCanvas__drawSolution( io.strbefore(expr, '['), io.strbetween(expr, '[', ']').split(','), io.strbetween(expr, '(', ')'), self.pos) #Text of node. pen.setColor(Qt.black) self.painter.setPen(pen) for node, (x, y) in self.pos.items(): if node in self.same: continue self.painter.drawText( QPointF(x * self.zoom + 2 * RADIUS, y * -self.zoom), 'P{}'.format(node)) self.painter.end()
class TextEditor(QsciScintilla): """QScintilla text editor.""" word_changed = Signal() def __init__(self, parent: QWidget): """UI settings.""" super(TextEditor, self).__init__(parent) # Set the default font. if system() == "Linux": font_name = "DejaVu Sans Mono" elif system() == "Windows": font_name = "Courier New" elif system() == "Darwin": font_name = "Andale Mono" else: font_name = "Courier New" self.font = QFont(font_name) self.font.setFixedPitch(True) self.font.setPointSize(14) self.setFont(self.font) self.setMarginsFont(self.font) self.setUtf8(True) self.setEolMode(QsciScintilla.EolUnix) # Margin 0 is used for line numbers. font_metrics = QFontMetrics(self.font) self.setMarginsFont(self.font) self.setMarginWidth(0, font_metrics.width("0000") + 4) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("#cccccc")) # Brace matching. self.setBraceMatching(QsciScintilla.SloppyBraceMatch) # Current line visible with special background color. self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#ffe4e4")) # Set lexer. self.lexer_option = "Markdown" self.set_highlighter("Markdown") self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, font_name.encode('utf-8')) # Don't want to see the horizontal scrollbar at all. self.setWrapMode(QsciScintilla.WrapWord) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Auto completion. self.setAutoCompletionCaseSensitivity(True) self.setAutoCompletionSource(QsciScintilla.AcsDocument) self.setAutoCompletionThreshold(2) # Edge mode. self.setEdgeMode(QsciScintilla.EdgeNone) self.setEdgeColumn(80) self.setEdgeColor(Qt.blue) # Indentations. self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setTabWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setIndentationGuides(True) # Widget size. self.setMinimumSize(400, 450) # Remove trailing blanks. self.__no_trailing_blanks = True # Spell checker indicator [0] self.indicatorDefine(QsciScintilla.SquiggleIndicator, 0) # Keyword indicator [1] self.indicatorDefine(QsciScintilla.BoxIndicator, 1) self.cursorPositionChanged.connect(self.__catch_word) self.word = "" # Undo redo self.__set_command(QsciCommand.Redo, Qt.ControlModifier | Qt.ShiftModifier | Qt.Key_Z) def __set_command(self, command_type: int, shortcut: int): """Set editor shortcut to replace the default setting.""" commands: QsciCommandSet = self.standardCommands() command = commands.boundTo(shortcut) if command is not None: command.setKey(0) command: QsciCommand = commands.find(command_type) command.setKey(shortcut) @Slot(int, int) def __catch_word(self, line: int, index: int): """Catch and indicate current word.""" self.__clear_indicator_all(1) pos = self.positionFromLineIndex(line, index) _, _, self.word = self.__word_at_pos(pos) for m in _finditer(r'\b' + self.word + r'\b', self.text(), re.IGNORECASE): self.fillIndicatorRange( *self.lineIndexFromPosition(m.start()), *self.lineIndexFromPosition(m.end()), 1 ) @Slot(str) def set_highlighter(self, option: str): """Set highlighter by list.""" self.lexer_option = option lexer = QSCI_HIGHLIGHTERS[option]() lexer.setDefaultFont(self.font) self.setLexer(lexer) @Slot(bool) def setEdgeMode(self, option: bool): """Set edge mode option.""" super(TextEditor, self).setEdgeMode( QsciScintilla.EdgeLine if option else QsciScintilla.EdgeNone ) def setSelection(self, p1: int, p2: int, p3: Optional[int] = None, p4: Optional[int] = None): if p3 is p4 is None: line1, index1 = self.lineIndexFromPosition(p1) line2, index2 = self.lineIndexFromPosition(p2) super(TextEditor, self).setSelection(line1, index1, line2, index2) else: super(TextEditor, self).setSelection(p1, p2, p3, p4) @Slot(bool) def set_remove_trailing_blanks(self, option: bool): """Set remove trailing blanks during 'setText' method.""" self.__no_trailing_blanks = option def wheelEvent(self, event): """Mouse wheel event.""" if QApplication.keyboardModifiers() != Qt.ControlModifier: super(TextEditor, self).wheelEvent(event) return if event.angleDelta().y() >= 0: self.zoomIn() else: self.zoomOut() def contextMenuEvent(self, event): """Custom context menu.""" # Spell refactor. menu: QMenu = self.createStandardContextMenu() menu.addSeparator() correction_action = QAction("&Refactor Words", self) correction_action.triggered.connect(self.__refactor) menu.addAction(correction_action) menu.exec(self.mapToGlobal(event.pos())) def __replace_all(self, word: str, replace_word: str): """Replace the word for all occurrence.""" found = self.findFirst(word, False, False, True, True) while found: self.replace(replace_word) found = self.findNext() def __word_at_pos(self, pos: int) -> Tuple[int, int, str]: """Return the start and end pos of current word.""" return ( self.SendScintilla(QsciScintilla.SCI_WORDSTARTPOSITION, pos, True), self.SendScintilla(QsciScintilla.SCI_WORDENDPOSITION, pos, True), self.wordAtLineIndex(*self.getCursorPosition()) ) @Slot() def __refactor(self): """Refactor words.""" pos = self.positionFromLineIndex(*self.getCursorPosition()) start, end, words = self.__word_at_pos(pos) if not words: return # Camel case. word = words for m in _finditer(r'[A-Za-z][a-z]+', words): if m.start() < pos - start < m.end(): word = m.group(0) break answer, ok = QInputDialog.getItem( self, "Spell correction", f"Refactor word: \"{word}\"", _spell.candidates(word) ) if ok: self.__replace_all(words, words.replace(word, answer)) def __cursor_move_next(self): """Move text cursor to next character.""" line, index = self.getCursorPosition() self.setCursorPosition(line, index + 1) def __cursor_next_char(self) -> str: """Next character of cursor.""" pos = self.positionFromLineIndex(*self.getCursorPosition()) if pos + 1 > self.length(): return "" return self.text(pos, pos + 1) def keyPressEvent(self, event): """Input key event.""" key = event.key() selected_text = self.selectedText() # Commas and parentheses. parentheses = list(_parentheses) commas = list(_commas) if self.lexer_option in {"Python", "C++"}: parentheses.extend(_parentheses_code) if self.lexer_option in {"Markdown", "HTML"}: parentheses.extend(_parentheses_html) commas.extend(_commas_markdown) # Skip the closed parentheses. for k1, k2, t0, t1 in parentheses: if key == k2: if self.__cursor_next_char() == t1: self.__cursor_move_next() return # Wrap the selected text. if selected_text: if len(selected_text) == 1 and not selected_text.isalnum(): pass elif selected_text[0].isalnum() == selected_text[-1].isalnum(): for k1, k2, t0, t1 in parentheses: if key == k1: self.replaceSelectedText(t0 + selected_text + t1) self.word_changed.emit() return line, _ = self.getCursorPosition() doc_pre = self.text(line) super(TextEditor, self).keyPressEvent(event) doc_post = self.text(line) if doc_pre != doc_post: self.word_changed.emit() self.__spell_check_line() # Remove leading spaces when create newline. if key in {Qt.Key_Return, Qt.Key_Enter}: if len(doc_pre) - len(doc_pre.lstrip(" ")) == 0: line, _ = self.getCursorPosition() doc_post = self.text(line) while 0 < len(doc_post) - len(doc_post.lstrip(" ")): self.unindent(line) doc_post = self.text(line) return # Auto close of parentheses. if not (selected_text or self.__cursor_next_char().isalnum()): for k1, k2, t0, t1 in parentheses: if key == k1: self.insert(t1) return # Add space for commas. for co in commas: if key == co and self.__cursor_next_char() != " ": self.insert(" ") self.__cursor_move_next() return def __clear_indicator_all(self, indicator: int): """Clear all indicators.""" line, index = self.lineIndexFromPosition(self.length()) self.clearIndicatorRange(0, 0, line, index, indicator) def spell_check_all(self): """Spell check for all text.""" self.__clear_indicator_all(0) for start, end in _spell_check(self.text()): line1, index1 = self.lineIndexFromPosition(start) line2, index2 = self.lineIndexFromPosition(end) self.fillIndicatorRange(line1, index1, line2, index2, 0) def __clear_line_indicator(self, line: int, indicator: int): """Clear all indicators.""" self.clearIndicatorRange(line, 0, line, self.lineLength(line), indicator) def __spell_check_line(self): """Spell check for current line.""" line, index = self.getCursorPosition() self.__clear_line_indicator(line, 0) for start, end in _spell_check(self.text(line)): self.fillIndicatorRange(line, start, line, end, 0) def remove_trailing_blanks(self): """Remove trailing blanks in text editor.""" scroll_bar: QScrollBar = self.verticalScrollBar() pos = scroll_bar.sliderPosition() line, index = self.getCursorPosition() doc = "" for line_str in self.text().splitlines(): doc += line_str.rstrip() + '\n' self.selectAll() self.replaceSelectedText(doc) self.setCursorPosition(line, self.lineLength(line) - 1) scroll_bar.setSliderPosition(pos) def setText(self, doc: str): """Remove trailing blanks in text editor.""" super(TextEditor, self).setText(doc) if self.__no_trailing_blanks: self.remove_trailing_blanks() self.spell_check_all()
def __init__(self, parent: QWidget): """UI settings.""" super(TextEditor, self).__init__(parent) #Set the default font. if platform.system().lower() == "windows": font_name = "Courier New" else: font_name = "Mono" self.font = QFont(font_name) self.font.setFixedPitch(True) self.font.setPointSize(14) self.setFont(self.font) self.setMarginsFont(self.font) self.setUtf8(True) #Margin 0 is used for line numbers. fontmetrics = QFontMetrics(self.font) self.setMarginsFont(self.font) self.setMarginWidth(0, fontmetrics.width("0000") + 4) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("#cccccc")) #Brace matching. self.setBraceMatching(QsciScintilla.SloppyBraceMatch) #Current line visible with special background color. self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#ffe4e4")) #Set lexer. lexer = QsciLexerCustomPython() lexer.setDefaultFont(self.font) self.setLexer(lexer) self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, font_name.encode('utf-8')) #Don't want to see the horizontal scrollbar at all. self.setWrapMode(QsciScintilla.WrapWord) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) #Auto completion. self.setAutoCompletionCaseSensitivity(True) self.setAutoCompletionSource(QsciScintilla.AcsDocument) self.setAutoCompletionThreshold(1) #Edge mode. self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(Qt.blue) #Indentations. self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setTabWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setIndentationGuides(True) #Indicator. self.indicatorDefine(QsciScintilla.BoxIndicator, 0) self.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, 0) self.cursorPositionChanged.connect(self.__catchWords) #Widget size. self.setMinimumSize(400, 450)
def __init__(self, parent: QWidget): """UI settings.""" super(TextEditor, self).__init__(parent) # Set the default font. if system() == "Linux": font_name = "DejaVu Sans Mono" elif system() == "Windows": font_name = "Courier New" elif system() == "Darwin": font_name = "Andale Mono" else: font_name = "Courier New" self.font = QFont(font_name) self.font.setFixedPitch(True) self.font.setPointSize(14) self.setFont(self.font) self.setMarginsFont(self.font) self.setUtf8(True) self.setEolMode(QsciScintilla.EolUnix) # Margin 0 is used for line numbers. font_metrics = QFontMetrics(self.font) self.setMarginsFont(self.font) self.setMarginWidth(0, font_metrics.width("0000") + 4) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("#cccccc")) # Brace matching. self.setBraceMatching(QsciScintilla.SloppyBraceMatch) # Current line visible with special background color. self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#ffe4e4")) # Set lexer. self.lexer_option = "Markdown" self.set_highlighter("Markdown") self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, font_name.encode('utf-8')) # Don't want to see the horizontal scrollbar at all. self.setWrapMode(QsciScintilla.WrapWord) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Auto completion. self.setAutoCompletionCaseSensitivity(True) self.setAutoCompletionSource(QsciScintilla.AcsDocument) self.setAutoCompletionThreshold(2) # Edge mode. self.setEdgeMode(QsciScintilla.EdgeNone) self.setEdgeColumn(80) self.setEdgeColor(Qt.blue) # Indentations. self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setTabWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setIndentationGuides(True) # Widget size. self.setMinimumSize(400, 450) # Remove trailing blanks. self.__no_trailing_blanks = True # Spell checker indicator [0] self.indicatorDefine(QsciScintilla.SquiggleIndicator, 0) # Keyword indicator [1] self.indicatorDefine(QsciScintilla.BoxIndicator, 1) self.cursorPositionChanged.connect(self.__catch_word) self.word = "" # Undo redo self.__set_command(QsciCommand.Redo, Qt.ControlModifier | Qt.ShiftModifier | Qt.Key_Z)
from core.libs import ( Graph, external_loop_layout, edges_view, ) from core.info import logger from .color import color_qt, color_num from .canvas import convex_hull Pos = Dict[int, Tuple[float, float]] engines: Tuple[str, ...] = ( "external loop", ) _font = QFont("Monospace") _font.setBold(True) _font.setStyleHint(QFont.TypeWriter) def engine_picker(g: Graph, engine: Union[str, Pos], node_mode: bool) -> Union[str, Pos]: """Generate a position dict.""" if type(engine) is not str: return engine if engine == "external loop": try: layout: Pos = external_loop_layout(g, node_mode, scale=30) except ValueError as error: logger.warn(error) return {}
def paintEvent(self, event): """Draw the structure.""" width = self.width() height = self.height() self.ox = width/2 self.oy = height/2 sq_w = 240 if width <= height: self.zoom = width / sq_w else: self.zoom = height / sq_w super(PreviewCanvas, self).paintEvent(event) self.drawLimit(sq_w) pen = QPen() pen.setWidth(self.r) self.painter.setPen(pen) self.painter.setBrush(QBrush(QColor(226, 219, 190, 150))) #Links for link in self.G.nodes: if link==self.grounded: continue points = [] #Points that is belong with the link. for num, edge in edges_view(self.G): if link in edge: if num in self.same: num = self.same[num] x, y = self.pos[num] points.append((x*self.zoom, y*-self.zoom)) #Customize points. for name, link_ in self.cus.items(): if link==link_: num = int(name.replace('P', '')) x, y = self.pos[num] points.append((x*self.zoom, y*-self.zoom)) self.painter.drawPolygon(*convex_hull(points)) self.painter.setFont(QFont("Arial", self.fontSize*1.5)) #Nodes for node, (x, y) in self.pos.items(): if node in self.same: continue x *= self.zoom y *= -self.zoom if node in (self.Driver, self.Target): if node==self.Driver: pen.setColor(colorQt('Red')) elif node==self.Target: pen.setColor(colorQt('Yellow')) self.painter.setPen(pen) self.painter.drawEllipse(QPointF(x, y), self.r, self.r) if self.getStatus(node): color = colorQt('Dark-Magenta') else: color = colorQt('Green') pen.setColor(color) self.painter.setPen(pen) self.painter.setBrush(QBrush(color)) self.painter.drawEllipse(QPointF(x, y), self.r, self.r) pen.setColor(colorQt('Black')) self.painter.setPen(pen) #Solutions if self.showSolutions: solutions = ';'.join(self.get_solutions()) if solutions: for func, args, target in triangle_expr(solutions): self.drawSolution(func, args, target) #Text of node. pen.setColor(Qt.black) self.painter.setPen(pen) for node, (x, y) in self.pos.items(): if node in self.same: continue name = 'P{}'.format(node) if self.name_dict: name = self.name_dict[name] self.painter.drawText(QPointF( x*self.zoom + 2*self.r, y*-self.zoom ), name) self.painter.end()
def paintEvent(self, event): """Drawing functions.""" width = self.width() height = self.height() if self.width_old is None: self.width_old = width if self.height_old is None: self.height_old = height if self.width_old != width or self.height_old != height: self.ox += (width - self.width_old) / 2 self.oy += (height - self.height_old) / 2 # 'self' is the instance of 'DynamicCanvas'. BaseCanvas.paintEvent(self, event) # Draw links except ground. for vlink in self.vlinks[1:]: self.__draw_link(vlink) # Draw path. if self.path.show != -2: self.__draw_path() # Draw solving path. if self.show_target_path: self.painter.setFont(QFont("Arial", self.font_size + 5)) self.draw_slvs_ranges() self.draw_target_path() self.painter.setFont(QFont("Arial", self.font_size)) # Draw points. for i, vpoint in enumerate(self.vpoints): self.__draw_point(i, vpoint) # Draw solutions. if self.select_mode == SelectMode.Solution: for i, expr in enumerate(self.exprs): func = expr[0] params = expr[1:-1] target = expr[-1] self.draw_solution(func, params, target, self.vpoints) if i in self.selections: pos, _ = self.solution_polygon(func, params, target, self.vpoints) pen = QPen() pen.setWidth(self.link_width + 3) pen.setColor(QColor(161, 16, 239)) self.painter.setPen(pen) self.painter.drawPolygon(QPolygonF(pos)) # Draw a colored frame for free move mode. if self.free_move != FreeMode.NoFreeMove: pen = QPen() if self.free_move == FreeMode.Translate: pen.setColor(QColor(161, 16, 229)) elif self.free_move == FreeMode.Rotate: pen.setColor(QColor(219, 162, 6)) elif self.free_move == FreeMode.Reflect: pen.setColor(QColor(79, 249, 193)) pen.setWidth(8) self.painter.setPen(pen) self.__draw_frame() # Rectangular selection if self.selector.picking: pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) self.painter.drawRect(self.selector.to_rect(self.zoom)) # Show FPS self.fps_updated.emit() self.painter.end() # Record the widget size. self.width_old = width self.height_old = height
class TextEditor(QsciScintilla): """QScintilla text editor.""" currtWordChanged = pyqtSignal(str) def __init__(self, parent: QWidget): """UI settings.""" super(TextEditor, self).__init__(parent) #Set the default font. if platform.system().lower() == "windows": font_name = "Courier New" else: font_name = "Mono" self.font = QFont(font_name) self.font.setFixedPitch(True) self.font.setPointSize(14) self.setFont(self.font) self.setMarginsFont(self.font) self.setUtf8(True) #Margin 0 is used for line numbers. fontmetrics = QFontMetrics(self.font) self.setMarginsFont(self.font) self.setMarginWidth(0, fontmetrics.width("0000") + 4) self.setMarginLineNumbers(0, True) self.setMarginsBackgroundColor(QColor("#cccccc")) #Brace matching. self.setBraceMatching(QsciScintilla.SloppyBraceMatch) #Current line visible with special background color. self.setCaretLineVisible(True) self.setCaretLineBackgroundColor(QColor("#ffe4e4")) #Set lexer. lexer = QsciLexerCustomPython() lexer.setDefaultFont(self.font) self.setLexer(lexer) self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, font_name.encode('utf-8')) #Don't want to see the horizontal scrollbar at all. self.setWrapMode(QsciScintilla.WrapWord) self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0) #Auto completion. self.setAutoCompletionCaseSensitivity(True) self.setAutoCompletionSource(QsciScintilla.AcsDocument) self.setAutoCompletionThreshold(1) #Edge mode. self.setEdgeMode(QsciScintilla.EdgeLine) self.setEdgeColumn(80) self.setEdgeColor(Qt.blue) #Indentations. self.setAutoIndent(True) self.setIndentationsUseTabs(False) self.setTabWidth(4) self.setTabIndents(True) self.setBackspaceUnindents(True) self.setIndentationGuides(True) #Indicator. self.indicatorDefine(QsciScintilla.BoxIndicator, 0) self.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, 0) self.cursorPositionChanged.connect(self.__catchWords) #Widget size. self.setMinimumSize(400, 450) def __currentWordPosition(self) -> Tuple[int, int]: """Return pos of current word.""" pos = self.positionFromLineIndex(*self.getCursorPosition()) return ( self.SendScintilla(QsciScintilla.SCI_WORDSTARTPOSITION, pos, True), self.SendScintilla(QsciScintilla.SCI_WORDENDPOSITION, pos, True), ) @pyqtSlot(int, int) def __catchWords(self, line: int, index: int): """Catch words that is same with current word.""" self.clearIndicatorRange(0, 0, *self.lineIndexFromPosition(self.length()), 0) wpos_start, wpos_end = self.__currentWordPosition() self.currtWordChanged.emit(self.text()[wpos_start:wpos_end]) self.fillIndicatorRange(*self.lineIndexFromPosition(wpos_start), *self.lineIndexFromPosition(wpos_end), 0) def wheelEvent(self, event): """Mouse wheel event.""" if QApplication.keyboardModifiers() != Qt.ControlModifier: super(TextEditor, self).wheelEvent(event) return if event.angleDelta().y() >= 0: self.zoomIn() else: self.zoomOut() def keyPressEvent(self, event): """Input key event.""" key = event.key() text = self.selectedText() #Commas and parentheses. parentheses = _parentheses commas = _commas #Wrap the selected text. if text: for match_key, t0, t1 in parentheses: if key == match_key: self.replaceSelectedText(t0 + text + t1) return super(TextEditor, self).keyPressEvent(event) #Auto close of parentheses. for match_key, t0, t1 in parentheses: if key == match_key: self.insert(t1) return #Add space for commas. for co in commas: if key == co: self.insert(" ") line, index = self.getCursorPosition() self.setCursorPosition(line, index + 1) return