Example #1
0
    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)
Example #2
0
 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)
Example #3
0
 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)
Example #4
0
    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)
Example #5
0
 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)
Example #6
0
 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)
Example #7
0
 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)
Example #8
0
    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)
            )
Example #9
0
 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
Example #10
0
 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)
Example #11
0
 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
Example #12
0
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)
Example #13
0
 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()
Example #14
0
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()
Example #15
0
    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)
Example #16
0
    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)
Example #17
0
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 {}
Example #18
0
 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()
Example #19
0
    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
Example #20
0
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