def pixmap(cursor, num_lines=6, scale=0.8):
    """Return a QPixmap displaying the selected lines of the document.

    If the cursor has no selection, num_lines are drawn.

    By default the text is drawn 0.8 * the normal font size. You can change
    that by supplying the scale parameter.

    """
    block = cursor.document().findBlock(cursor.selectionStart())
    c2 = QTextCursor(block)
    if cursor.hasSelection():
        c2.setPosition(cursor.selectionEnd(), QTextCursor.KeepAnchor)
        c2.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
    else:
        c2.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor, num_lines)

    data = textformats.formatData('editor')
    doc = QTextDocument()
    font = QFont(data.font)
    font.setPointSizeF(font.pointSizeF() * scale)
    doc.setDefaultFont(font)
    doc.setPlainText(c2.selection().toPlainText())
    if metainfo.info(cursor.document()).highlighting:
        highlighter.highlight(doc, state=tokeniter.state(block))
    size = doc.size().toSize() + QSize(8, -4)
    pix = QPixmap(size)
    pix.fill(data.baseColors['background'])
    doc.drawContents(QPainter(pix))
    return pix
Beispiel #2
0
    def set_gui(self, qfont: QFont):
        self.setText(qfont.family() + " " +
                     _format_font_size(qfont.pointSizeF()))

        preview_font = QFont(qfont)
        preview_font.setPointSizeF(self.font().pointSizeF())
        self.setFont(preview_font)
Beispiel #3
0
def pixmap(cursor, num_lines=6, scale=0.8):
    """Return a QPixmap displaying the selected lines of the document.
    
    If the cursor has no selection, num_lines are drawn.
    
    By default the text is drawn 0.8 * the normal font size. You can change
    that by supplying the scale parameter.
    
    """
    block = cursor.document().findBlock(cursor.selectionStart())
    c2 = QTextCursor(block)
    if cursor.hasSelection():
        c2.setPosition(cursor.selectionEnd(), QTextCursor.KeepAnchor)
        c2.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
    else:
        c2.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor,
                        num_lines)

    data = textformats.formatData('editor')
    doc = QTextDocument()
    font = QFont(data.font)
    font.setPointSizeF(font.pointSizeF() * scale)
    doc.setDefaultFont(font)
    doc.setPlainText(c2.selection().toPlainText())
    if metainfo.info(cursor.document()).highlighting:
        highlighter.highlight(doc, state=tokeniter.state(block))
    size = doc.size().toSize() + QSize(8, -4)
    pix = QPixmap(size)
    pix.fill(data.baseColors['background'])
    doc.drawContents(QPainter(pix))
    return pix
Beispiel #4
0
 def setDefaultFont(self, font: QFont):
     super(NewLexer, self).setDefaultFont(font)
     m = 0
     for v in lexer.__bases__[-1].__dict__.values():
         if type(v) == int and v > m:
             m = v
     for i in range(m):
         style_font: QFont = self.font(i)
         style_font.setFamily(font.family())
         style_font.setPointSizeF(font.pointSizeF())
         self.setFont(style_font, i)
Beispiel #5
0
def get_optimal_font(family_font: str, w, h, text: str) -> QFont:
    font = QFont(family_font)
    font.setStyleHint(QFont.Courier, QFont.PreferAntialias)
    metrics = QFontMetrics(font)

    # SOURCE: https://github.com/gil9red/SimplePyScripts/blob/add91e36e1ee59b3956b9fafdcffc9f4ff10ed3d/qt__pyqt__pyside__pyqode/pyqt__QPainter__draw_table.py#L98
    factor = w / metrics.boundingRect(0, 0, w, h, Qt.AlignCenter, text).width()
    if factor < 1 or factor > 1.25:
        font.setPointSizeF(font.pointSizeF() * factor)

    return font
Beispiel #6
0
    def __init__(self, str, x, y, size, w, fontname):
        super().__init__()
        font = QFont(fontname)

        fontMetrics = QFontMetrics(font)
        scale = float(fontMetrics.width(str)) / w
        font.setPointSizeF(font.pointSizeF() / scale)

        self.setFont(font)
        self.setPos(x - w / 2, y - fontMetrics.height())
        self.setPlainText(str)
Beispiel #7
0
 def loadSettings(self):
     s = QSettings()
     s.beginGroup("log")
     font = QFont(s.value("fontfamily", "monospace", str))
     font.setPointSizeF(s.value("fontsize", 9.0, float))
     with qutil.signalsBlocked(self.fontChooser, self.fontSize):
         self.fontChooser.setCurrentFont(font)
         self.fontSize.setValue(font.pointSizeF())
     self.showlog.setChecked(s.value("show_on_start", True, bool))
     self.rawview.setChecked(s.value("rawview", True, bool))
     self.hideauto.setChecked(s.value("hide_auto_engrave", False, bool))
Beispiel #8
0
 def loadSettings(self):
     s = QSettings()
     s.beginGroup("log")
     font = QFont(s.value("fontfamily", "monospace", str))
     font.setPointSizeF(s.value("fontsize", 9.0, float))
     with qutil.signalsBlocked(self.fontChooser, self.fontSize):
         self.fontChooser.setCurrentFont(font)
         self.fontSize.setValue(font.pointSizeF())
     self.showlog.setChecked(s.value("show_on_start", True, bool))
     self.rawview.setChecked(s.value("rawview", True, bool))
     self.hideauto.setChecked(s.value("hide_auto_engrave", False, bool))
Beispiel #9
0
 def render__label_qfont(self, qfont: QFont):
     self.cfg.render.label_font = attr.evolve(
         self.cfg.render.label_font,
         # Font file selection
         family=qfont.family(),
         bold=qfont.bold(),
         italic=qfont.italic(),
         # Font size
         size=qfont.pointSizeF(),
         # QFont implementation details
         toString=qfont.toString(),
     )
Beispiel #10
0
    def basic_font_metrics(self, font: QFont) -> BasicFontMetrics:
        """
        Calculates some commonly needed font metrics and returns them in a
        BasicFontMetrics tuple.
        """
        qMetric = QFontMetrics(font)
        info = BasicFontMetrics.make([
            font.pointSizeF(),
            qMetric.height(),
            qMetric.ascent(),
            qMetric.boundingRect("N").height(),
            qMetric.boundingRect("N").width(),
        ])

        LOG.diagnostic("GUI Font Family: %s" % font.family())
        LOG.diagnostic("GUI Font Point Size: %.2f" % info.points)
        LOG.diagnostic("GUI Font Pixel Size: %d" % info.pixels)
        LOG.diagnostic("GUI Base Icon Size: %d" % info.icon_size)
        LOG.diagnostic("Text 'N' Height: %d" % info.n_height)
        LOG.diagnostic("Text 'N' Width: %d" % info.n_width)
        return info
Beispiel #11
0
    def wheelEvent(self, event):
        """
        We catch wheelEvent if key modifier is CTRL to change font size.
        Note: this should be in a class specific for main textEditView (#TODO).
        """
        if event.modifiers() & Qt.ControlModifier:
            # Get the wheel angle.
            d = event.angleDelta().y() / 120

            # Update settings
            f = QFont()
            f.fromString(settings.textEditor["font"])
            f.setPointSizeF(f.pointSizeF() + d)
            settings.textEditor["font"] = f.toString()

            # Update font to all textEditView. Drastically.
            for w in F.mainWindow().findChildren(textEditView, QRegExp(".*")):
                w.loadFontSettings()

            # We tell the world that we accepted this event
            event.accept()
            return

        QTextEdit.wheelEvent(self, event)
Beispiel #12
0
    def wheelEvent(self, event):
        """
        We catch wheelEvent if key modifier is CTRL to change font size.
        Note: this should be in a class specific for main textEditView (#TODO).
        """
        if event.modifiers() & Qt.ControlModifier:
            # Get the wheel angle.
            d = event.angleDelta().y() / 120

            # Update settings
            f = QFont()
            f.fromString(settings.textEditor["font"])
            f.setPointSizeF(f.pointSizeF() + d)
            settings.textEditor["font"] = f.toString()

            # Update font to all textEditView. Drastically.
            for w in F.mainWindow().findChildren(textEditView, QRegExp(".*")):
                w.loadFontSettings()

            # We tell the world that we accepted this event
            event.accept()
            return

        QTextEdit.wheelEvent(self, event)
Beispiel #13
0
class TextShape(MarcShape):
    def __init__(self,
                 host_widget,
                 text,
                 location,
                 size,
                 font_name,
                 color,
                 styles="",
                 anchor_type=TextAnchorType.ANCHOR_BOTTOM_LEFT,
                 include_descent_in_height=True):
        # size either refers to the point size (relative to the view height)
        # or to the max width and max height in view coordinates
        """

        :param host_widget: the MarcPaintWidget in which this is being drawn
        :param text: The text to be written
        :param size: The size of the text to be written in view coordinates. Either a number, in which case this will be
        the height of the text, or a tuple of (width, height) in which case the text will be made as big as possible
        such that it fits in the bounding box.
        :param font_name: Font family name
        :param color: duh
        :param styles: "bold", "italic", or "bold italic"
        :param anchor_type: one of the TextAnchorTypes. Either determines the position of the draw location within the
        text if we are given a height only in the size parameter, or determines the position of the text in the bounding
        box if we are given a (width, height) tuple in the size parameter. Note that the location parameter defines the
        lower left corner of the bounding box.
        :param include_descent_in_height: determines whether we include the descent in the height of the letters, both
        for size and for anchoring purposes.
        """
        super().__init__(host_widget)
        self.text = text
        self.font_name = font_name
        self.color = tuple(int(k * 255) for k in color)
        self.size = (float(size[0]), float(size[1])) if hasattr(
            size, "__len__") else float(size)

        self.view_location = location

        self.anchor_type = anchor_type
        self.include_descent_in_height = include_descent_in_height

        # These two attributes need to be recalculated at every draw
        self.position = None
        self.font = None
        self.styles = styles.lower()

    def set_font_and_position(self):
        goal_view_font_height = self.size[1] if isinstance(
            self.size, tuple) else self.size
        goal_window_font_height = goal_view_font_height / self.host_widget.get_view_height(
        ) * self.host_widget.height()
        goal_view_font_width = self.size[0] if isinstance(
            self.size, tuple) else float("inf")
        goal_window_font_width = goal_view_font_width / self.host_widget.get_view_height(
        ) * self.host_widget.height()

        self.font = QFont(self.font_name, goal_window_font_height)

        if "italic" in self.styles:
            self.font.setItalic(True)
        if "bold" in self.styles:
            self.font.setBold(True)

        font_met = QFontMetricsF(self.font)
        bounding_rect = font_met.tightBoundingRect(self.text)
        effective_height = bounding_rect.height() if self.include_descent_in_height \
            else bounding_rect.height() - bounding_rect.bottom()
        resize_ratio = max(bounding_rect.width() / goal_window_font_width,
                           effective_height / goal_window_font_height)
        self.font.setPointSizeF(self.font.pointSizeF() / resize_ratio)

        # at this point, we should have the font at the right size to fill the desired height or bounding box
        # recalculate its metrics
        font_met = QFontMetricsF(self.font)
        bounding_rect = font_met.tightBoundingRect(self.text)
        assert isinstance(bounding_rect, QRectF)
        self.position = self.host_widget.view_to_window(self.view_location)

        if self.include_descent_in_height:
            x_zeroing_adjustment, y_zeroing_adjustment = -bounding_rect.left(
            ), -bounding_rect.bottom()
            effective_height = bounding_rect.height()
        else:
            x_zeroing_adjustment, y_zeroing_adjustment = -bounding_rect.left(
            ), 0
            effective_height = bounding_rect.height() - bounding_rect.bottom()

        if self.anchor_type in (TextAnchorType.ANCHOR_CENTER_TOP,
                                TextAnchorType.ANCHOR_TOP_LEFT,
                                TextAnchorType.ANCHOR_TOP_RIGHT):
            # top vertically
            if hasattr(self.size, "__len__"):
                y_anchoring_adjustment = effective_height - goal_window_font_height
            else:
                # point location
                y_anchoring_adjustment = effective_height
        elif self.anchor_type in (TextAnchorType.ANCHOR_CENTER,
                                  TextAnchorType.ANCHOR_CENTER_LEFT,
                                  TextAnchorType.ANCHOR_CENTER_RIGHT):
            # centered vertically
            if hasattr(self.size, "__len__"):
                y_anchoring_adjustment = (effective_height -
                                          goal_window_font_height) / 2
            else:
                # point location
                y_anchoring_adjustment = effective_height / 2
        else:
            # (default) bottom vertically
            y_anchoring_adjustment = 0

        if self.anchor_type in (TextAnchorType.ANCHOR_TOP_RIGHT,
                                TextAnchorType.ANCHOR_CENTER_RIGHT,
                                TextAnchorType.ANCHOR_BOTTOM_RIGHT):
            # right horizontally
            if hasattr(self.size, "__len__"):
                x_anchoring_adjustment = -bounding_rect.width(
                ) + goal_window_font_width
            else:
                # point location
                x_anchoring_adjustment = -bounding_rect.width()
        elif self.anchor_type in (TextAnchorType.ANCHOR_CENTER_TOP,
                                  TextAnchorType.ANCHOR_CENTER,
                                  TextAnchorType.ANCHOR_CENTER_BOTTOM):
            # center horizontally
            if hasattr(self.size, "__len__"):
                x_anchoring_adjustment = (-bounding_rect.width() +
                                          goal_window_font_width) / 2
            else:
                # point location
                x_anchoring_adjustment = -bounding_rect.width() / 2
        else:
            # (default) left horizontally
            x_anchoring_adjustment = 0

        self.position = self.position[0] + x_zeroing_adjustment + x_anchoring_adjustment, \
                        self.position[1] + y_zeroing_adjustment + y_anchoring_adjustment

    def paint(self):
        self.set_font_and_position()
        painter = QPainter(self.host_widget)
        painter.setPen(QColor(*self.color))
        painter.setFont(self.font)
        painter.drawText(self.position[0], self.position[1], self.text)
        painter.end()
        # Resets the OpenGL states we need for drawing
        self.host_widget.initializeGL()
Beispiel #14
0
class TextFormatData(object):
    """Encapsulates all settings in the Fonts & Colors page for a scheme."""
    def __init__(self, scheme):
        """Loads the data from scheme."""
        self.font = None
        self.baseColors = {}
        self.defaultStyles = {}
        self.allStyles = {}
        self._inherits = {}
        self.load(scheme)
        
    def load(self, scheme):
        """Load the settings for the scheme. Called on init."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # load font
        defaultfont = "Lucida Console" if os.name == "nt" else "monospace"
        self.font = QFont(s.value("fontfamily", defaultfont, str))
        self.font.setPointSizeF(s.value("fontsize", 10.0, float))
        
        # load base colors
        s.beginGroup("basecolors")
        for name in baseColors:
            if s.contains(name):
                self.baseColors[name] = QColor(s.value(name, "", str))
            else:
                self.baseColors[name] = baseColorDefaults[name]()
        s.endGroup()
        
        # get the list of supported styles from ly.colorize
        all_styles = ly.colorize.default_mapping()
        default_styles = set()
        for group, styles in all_styles:
            d = self._inherits[group] = {}
            for style in styles:
                if style.base:
                    default_styles.add(style.base)
                    d[style.name] = style.base
        
        default_scheme = ly.colorize.default_scheme
        
        # load default styles
        s.beginGroup("defaultstyles")
        for name in default_styles:
            self.defaultStyles[name] = f = QTextCharFormat()
            css = default_scheme[None].get(name)
            if css:
                css2fmt(css, f)
            s.beginGroup(name)
            self.loadTextFormat(f, s)
            s.endGroup()
        s.endGroup()
        
        # load specific styles
        s.beginGroup("allstyles")
        for group, styles in all_styles:
            self.allStyles[group]= {}
            s.beginGroup(group)
            for style in styles:
                self.allStyles[group][style.name] = f = QTextCharFormat()
                css = default_scheme[group].get(style.name)
                if css:
                    css2fmt(css, f)
                s.beginGroup(style.name)
                self.loadTextFormat(f, s)
                s.endGroup()
            s.endGroup()
        s.endGroup()
        
    def save(self, scheme):
        """Save the settings to the scheme."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)
        
        # save font
        s.setValue("fontfamily", self.font.family())
        s.setValue("fontsize", self.font.pointSizeF())
        
        # save base colors
        for name in baseColors:
            s.setValue("basecolors/"+name, self.baseColors[name].name())
        
        # save default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            s.beginGroup(name)
            self.saveTextFormat(self.defaultStyles[name], s)
            s.endGroup()
        s.endGroup()
        
        # save all specific styles
        s.beginGroup("allstyles")
        for group, styles in ly.colorize.default_mapping():
            s.beginGroup(group)
            for style in styles:
                s.beginGroup(style.name)
                self.saveTextFormat(self.allStyles[group][style.name], s)
                s.endGroup()
            s.endGroup()
        s.endGroup()

    def textFormat(self, group, name):
        """Return a QTextCharFormat() for the specified group and name."""
        inherit = self._inherits[group].get(name)
        f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat()
        f.merge(self.allStyles[group][name])
        return f
    
    def css_scheme(self):
        """Return a dictionary of css dictionaries representing this scheme.
        
        This can be fed to the ly.colorize.format_stylesheet() function.
        
        """
        scheme = {}
        # base/default styles
        d = scheme[None] = {}
        for name, fmt in self.defaultStyles.items():
            d[name] = fmt2css(fmt)
        # mode/group styles
        for mode, styles in self.allStyles.items():
            d = scheme[mode] = {}
            for name, fmt in styles.items():
                d[name] = fmt2css(fmt)
        return scheme
    
    def palette(self):
        """Return a basic palette with text, background, selection and selection background filled in."""
        p = QApplication.palette()
        p.setColor(QPalette.Text, self.baseColors['text'])
        p.setColor(QPalette.Base, self.baseColors['background'])
        p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext'])
        p.setColor(QPalette.Highlight, self.baseColors['selectionbackground'])
        return p
        
    def saveTextFormat(self, fmt, settings):
        """(Internal) Store one QTextCharFormat in the QSettings instance."""
        if fmt.hasProperty(QTextFormat.FontWeight):
            settings.setValue('bold', fmt.fontWeight() >= 70)
        else:
            settings.remove('bold')
        if fmt.hasProperty(QTextFormat.FontItalic):
            settings.setValue('italic', fmt.fontItalic())
        else:
            settings.remove('italic')
        if fmt.hasProperty(QTextFormat.TextUnderlineStyle):
            settings.setValue('underline', fmt.fontUnderline())
        else:
            settings.remove('underline')
        if fmt.hasProperty(QTextFormat.ForegroundBrush):
            settings.setValue('textColor', fmt.foreground().color().name())
        else:
            settings.remove('textColor')
        if fmt.hasProperty(QTextFormat.BackgroundBrush):
            settings.setValue('backgroundColor', fmt.background().color().name())
        else:
            settings.remove('backgroundColor')
        if fmt.hasProperty(QTextFormat.TextUnderlineColor):
            settings.setValue('underlineColor', fmt.underlineColor().name())
        else:
            settings.remove('underlineColor')
        
    def loadTextFormat(self, fmt, settings):
        """(Internal) Merge values from the QSettings instance into the QTextCharFormat."""
        if settings.contains('bold'):
            fmt.setFontWeight(QFont.Bold if settings.value('bold', False, bool) else QFont.Normal)
        if settings.contains('italic'):
            fmt.setFontItalic(settings.value('italic', False, bool))
        if settings.contains('underline'):
            fmt.setFontUnderline(settings.value('underline', False, bool))
        if settings.contains('textColor'):
            fmt.setForeground(QColor(settings.value('textColor', '' , str)))
        if settings.contains('backgroundColor'):
            fmt.setBackground(QColor(settings.value('backgroundColor', '' , str)))
        if settings.contains('underlineColor'):
            fmt.setUnderlineColor(QColor(settings.value('underlineColor', '' , str)))
    def drawLines(self, qp):
        pen = QPen(QColor('#eeeff7'), 2, Qt.SolidLine)
        qp.setPen(pen)

        font = QFont('Arial', 19)
        qp.setFont(font)

        # first - растояние первой линии от верха
        first = self.evh
        qp.drawLine(self.x(), first, self.width(), first)

        # Отрисовка главного заголовка настроек
        # Функция возвращающая верхнюю середину ширины окна для подзаголовка
        def getPosxTitle(name):
            wn = qp.fontMetrics().width(name)
            return (self.width() / 2) - (wn / 2)

        pos_x_title = getPosxTitle(self.listnames[0])

        # Условие описания уменьшения названия при уменьшении высоты
        if self.height() < self.parent().baseSize().height():
            fontsize = (first - font.pointSizeF()) / 1.6
            if self.height() <= 550:
                fontsize = 14

            font.setPointSizeF(fontsize)
            qp.setFont(font)
            pos_x_title = getPosxTitle(self.listnames[0])

        qp.drawText(pos_x_title, first / 1.55, self.listnames[0])

        # distance = 150 дистанция между остальными линиями
        distance = (self.height() - first) / 4
        i = 0
        '''leftIndent - маштабируемый отступ от левой стороны окна,
            для названий категорий настроек'''
        leftIndent = qp.viewport().width() / 9

        while first < self.height() and i < len(self.listnames[1:]):
            first += distance
            i += 1
            qp.setPen(QColor('#9fcdd0'))
            font.setPointSize(16)

            # ширина квадрата в котором написано название категории
            # widthrect = 240
            widthrect = 240

            # размер маленького шрифта
            smallfnt = 10

            if self.height() < self.parent().baseSize().height():
                if self.height() <= 550:
                    font.setPointSize(13)
                    widthrect = 220
                    smallfnt = 8
                else:
                    font.setPointSizeF(distance / font.pointSizeF() * 1.72)
            qp.setFont(font)

            # posvcen - вычисление маштабируемого отступа по выстое
            posvcen = lambda a: distance / a + qp.fontMetrics().height()
            if i == 2:
                qp.drawText(
                    leftIndent - 5, first - posvcen(1.55), widthrect, distance / 2,
                    Qt.TextWordWrap | Qt.AlignHCenter|Qt.AA_EnableHighDpiScaling, self.listnames[i])

                qp.setPen(QColor('#eeeff7'))
                # font.setPointSize(smallfnt)
                font.setPointSize(smallfnt)
                font.setItalic(True)
                qp.setFont(font)
                qp.drawText(
                    leftIndent, first - posvcen(2.15), 230, distance / 2,
                    Qt.TextWordWrap | Qt.AlignHCenter|Qt.AA_EnableHighDpiScaling, self.strtolist)
            else:
                font.setItalic(False)
                qp.setFont(font)
                qp.drawText(
                    leftIndent, first - posvcen(2), widthrect, distance / 2,
                    Qt.TextWordWrap | Qt.AlignHCenter|Qt.AA_EnableHighDpiScaling, self.listnames[i])
            # отрисовка линий
            if first >= self.height():
                continue
            else:
                qp.setPen(pen)
                qp.drawLine(self.rect().x(), first, self.width(), first)
Beispiel #16
0
class TextFormatData(object):
    """Encapsulates all settings in the Fonts & Colors page for a scheme."""
    def __init__(self, scheme):
        """Loads the data from scheme."""
        self.font = None
        self.baseColors = {}
        self.defaultStyles = {}
        self.allStyles = {}
        self._inherits = {}
        self.load(scheme)

    def load(self, scheme):
        """Load the settings for the scheme. Called on init."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)

        # load font
        defaultfont = "Lucida Console" if os.name == "nt" else "monospace"
        self.font = QFont(s.value("fontfamily", defaultfont, str))
        self.font.setPointSizeF(s.value("fontsize", 10.0, float))

        # load base colors
        s.beginGroup("basecolors")
        for name in baseColors:
            if s.contains(name):
                self.baseColors[name] = QColor(s.value(name, "", str))
            else:
                self.baseColors[name] = baseColorDefaults[name]()
        s.endGroup()

        # get the list of supported styles from ly.colorize
        all_styles = ly.colorize.default_mapping()
        default_styles = set()
        for group, styles in all_styles:
            d = self._inherits[group] = {}
            for style in styles:
                if style.base:
                    default_styles.add(style.base)
                    d[style.name] = style.base

        default_scheme = ly.colorize.default_scheme

        # load default styles
        s.beginGroup("defaultstyles")
        for name in default_styles:
            self.defaultStyles[name] = f = QTextCharFormat()
            css = default_scheme[None].get(name)
            if css:
                css2fmt(css, f)
            s.beginGroup(name)
            self.loadTextFormat(f, s)
            s.endGroup()
        s.endGroup()

        # load specific styles
        s.beginGroup("allstyles")
        for group, styles in all_styles:
            self.allStyles[group] = {}
            s.beginGroup(group)
            for style in styles:
                self.allStyles[group][style.name] = f = QTextCharFormat()
                css = default_scheme[group].get(style.name)
                if css:
                    css2fmt(css, f)
                s.beginGroup(style.name)
                self.loadTextFormat(f, s)
                s.endGroup()
            s.endGroup()
        s.endGroup()

    def save(self, scheme):
        """Save the settings to the scheme."""
        s = QSettings()
        s.beginGroup("fontscolors/" + scheme)

        # save font
        s.setValue("fontfamily", self.font.family())
        s.setValue("fontsize", self.font.pointSizeF())

        # save base colors
        for name in baseColors:
            s.setValue("basecolors/" + name, self.baseColors[name].name())

        # save default styles
        s.beginGroup("defaultstyles")
        for name in defaultStyles:
            s.beginGroup(name)
            self.saveTextFormat(self.defaultStyles[name], s)
            s.endGroup()
        s.endGroup()

        # save all specific styles
        s.beginGroup("allstyles")
        for group, styles in ly.colorize.default_mapping():
            s.beginGroup(group)
            for style in styles:
                s.beginGroup(style.name)
                self.saveTextFormat(self.allStyles[group][style.name], s)
                s.endGroup()
            s.endGroup()
        s.endGroup()

    def textFormat(self, group, name):
        """Return a QTextCharFormat() for the specified group and name."""
        inherit = self._inherits[group].get(name)
        f = QTextCharFormat(
            self.defaultStyles[inherit]) if inherit else QTextCharFormat()
        f.merge(self.allStyles[group][name])
        return f

    def css_scheme(self):
        """Return a dictionary of css dictionaries representing this scheme.
        
        This can be fed to the ly.colorize.format_stylesheet() function.
        
        """
        scheme = {}
        # base/default styles
        d = scheme[None] = {}
        for name, fmt in self.defaultStyles.items():
            d[name] = fmt2css(fmt)
        # mode/group styles
        for mode, styles in self.allStyles.items():
            d = scheme[mode] = {}
            for name, fmt in styles.items():
                d[name] = fmt2css(fmt)
        return scheme

    def palette(self):
        """Return a basic palette with text, background, selection and selection background filled in."""
        p = QApplication.palette()
        p.setColor(QPalette.Text, self.baseColors['text'])
        p.setColor(QPalette.Base, self.baseColors['background'])
        p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext'])
        p.setColor(QPalette.Highlight, self.baseColors['selectionbackground'])
        return p

    def saveTextFormat(self, fmt, settings):
        """(Internal) Store one QTextCharFormat in the QSettings instance."""
        if fmt.hasProperty(QTextFormat.FontWeight):
            settings.setValue('bold', fmt.fontWeight() >= 70)
        else:
            settings.remove('bold')
        if fmt.hasProperty(QTextFormat.FontItalic):
            settings.setValue('italic', fmt.fontItalic())
        else:
            settings.remove('italic')
        if fmt.hasProperty(QTextFormat.TextUnderlineStyle):
            settings.setValue('underline', fmt.fontUnderline())
        else:
            settings.remove('underline')
        if fmt.hasProperty(QTextFormat.ForegroundBrush):
            settings.setValue('textColor', fmt.foreground().color().name())
        else:
            settings.remove('textColor')
        if fmt.hasProperty(QTextFormat.BackgroundBrush):
            settings.setValue('backgroundColor',
                              fmt.background().color().name())
        else:
            settings.remove('backgroundColor')
        if fmt.hasProperty(QTextFormat.TextUnderlineColor):
            settings.setValue('underlineColor', fmt.underlineColor().name())
        else:
            settings.remove('underlineColor')

    def loadTextFormat(self, fmt, settings):
        """(Internal) Merge values from the QSettings instance into the QTextCharFormat."""
        if settings.contains('bold'):
            fmt.setFontWeight(QFont.Bold if settings.
                              value('bold', False, bool) else QFont.Normal)
        if settings.contains('italic'):
            fmt.setFontItalic(settings.value('italic', False, bool))
        if settings.contains('underline'):
            fmt.setFontUnderline(settings.value('underline', False, bool))
        if settings.contains('textColor'):
            fmt.setForeground(QColor(settings.value('textColor', '', str)))
        if settings.contains('backgroundColor'):
            fmt.setBackground(
                QColor(settings.value('backgroundColor', '', str)))
        if settings.contains('underlineColor'):
            fmt.setUnderlineColor(
                QColor(settings.value('underlineColor', '', str)))
Beispiel #17
0
class CharMap(QWidget):
    """A widget displaying a table of characters."""
    characterSelected = pyqtSignal(str)
    characterClicked = pyqtSignal(str)
    
    def __init__(self, parent=None):
        super(CharMap, self).__init__(parent)
        self._showToolTips = True
        self._showWhatsThis = True
        self._selected = -1
        self._column_count = 32
        self._square = 24
        self._range = (0, 0)
        self._font = QFont()
        
    def setRange(self, first, last):
        self._range = (first, last)
        self._selected = -1
        self.adjustSize()
        self.update()
    
    def range(self):
        return self._range
    
    def square(self):
        """Returns the width of one item (determined by font size)."""
        return self._square
    
    def select(self, charcode):
        """Selects the specified character (int or str)."""
        if not isinstance(charcode, int):
            charcode = ord(charcode)
        if not self._range[0] <= charcode <= self._range[1]:
            charcode = -1
        if self._selected != charcode:
            self._selected = charcode
            self.characterSelected.emit(chr(charcode))
            self.update()
    
    def character(self):
        """Returns the currently selected character, if any."""
        if self._selected != -1:
            return chr(self._selected)
    
    def setDisplayFont(self, font):
        self._font.setFamily(font.family())
        self.update()
    
    def displayFont(self):
        return QFont(self._font)
    
    def setDisplayFontSize(self, size):
        self._font.setPointSize(size)
        self._square = max(24, QFontMetrics(self._font).xHeight() * 3)
        self.adjustSize()
        self.update()
    
    def displayFontSize(self):
        return self._font.pointSize()
    
    def setDisplayFontSizeF(self, size):
        self._font.setPointSizeF(size)
        self._square = max(24, QFontMetrics(self._font).xHeight() * 3)
        self.adjustSize()
        self.update()
    
    def displayFontSizeF(self):
        return self._font.pointSizeF()
    
    def setColumnCount(self, count):
        """Sets how many columns should be used."""
        count = max(1, count)
        self._column_count = count
        self.adjustSize()
        self.update()
    
    def columnCount(self):
        return self._column_count
        
    def sizeHint(self):
        return self.sizeForColumnCount(self._column_count)

    def paintEvent(self, ev):
        rect = ev.rect()
        s = self._square
        rows = range(rect.top() // s, rect.bottom() // s + 1)
        cols = range(rect.left() // s, rect.right() // s + 1)
        
        painter = QPainter(self)
        painter.setPen(QPen(self.palette().color(QPalette.Window)))
        painter.setFont(self._font)
        metrics = QFontMetrics(self._font)
        
        # draw characters on white tiles
        tile = self.palette().color(QPalette.Base)
        selected_tile = self.palette().color(QPalette.Highlight)
        selected_tile.setAlpha(96)
        selected_box = self.palette().color(QPalette.Highlight)
        
        text_pen = QPen(self.palette().text().color())
        disabled_pen = QPen(self.palette().color(QPalette.Disabled, QPalette.Text))
        selection_pen = QPen(selected_box)
        for row in rows:
            for col in cols:
                char = row * self._column_count + col + self._range[0]
                if char > self._range[1]:
                    break
                printable = self.isprint(char)
                painter.setClipRect(col * s, row * s, s, s)
                if char == self._selected:
                    painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, selected_tile)
                    painter.setPen(selection_pen)
                    painter.drawRect(col * s, row * s, s - 1, s - 1)
                elif printable:
                    painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, tile)
                painter.setPen(text_pen if printable else disabled_pen)
                t = chr(char)
                x = col * s + s // 2 - metrics.width(t) // 2
                y = row * s + 4 + metrics.ascent()
                painter.drawText(x, y, t)
            else:
                continue
            break
    
    def sizeForColumnCount(self, count):
        """Returns the size the widget would have in a certain column count.
        
        This can be used in e.g. a resizable scroll area.
        
        """
        first, last = self._range
        rows = ((last - first) // count) + 1
        return QSize(count, rows) * self._square

    def columnCountForWidth(self, width):
        """Returns the number of columns that would fit into the given width."""
        return width // self._square

    def mousePressEvent(self, ev):
        charcode = self.charcodeAt(ev.pos())
        if charcode != -1 and self.isprint(charcode):
            self.select(charcode)
            if ev.button() != Qt.RightButton:
                self.characterClicked.emit(chr(charcode))
    
    def charcodeRect(self, charcode):
        """Returns the rectangular box around the given charcode, if any."""
        if self._range[0] <= charcode <= self._range[1]:
            row, col = divmod(charcode - self._range[0], self._column_count)
            s = self._square
            return QRect(col * s, row * s, s, s)
        
    def charcodeAt(self, position):
        row = position.y() // self._square
        col = position.x() // self._square
        if col <= self._column_count:
            charcode = self._range[0] + row * self._column_count + col
            if charcode <= self._range[1]:
                return charcode
        return -1

    def event(self, ev):
        if ev.type() == QEvent.ToolTip:
            if self._showToolTips:
                c = self.charcodeAt(ev.pos())
                if c:
                    text = self.getToolTipText(c)
                    if text:
                        rect = self.charcodeRect(c)
                        QToolTip.showText(ev.globalPos(), text, self, rect)
                        ev.accept()
                        return True
        elif ev.type() == QEvent.QueryWhatsThis:
            if self._showWhatsThis:
                ev.accept()
                return True
        elif ev.type() == QEvent.WhatsThis:
            ev.accept()
            if self._showWhatsThis:
                c = self.charcodeAt(ev.pos())
                text = self.getWhatsThisText(c) if c else None
                if text:
                    QWhatsThis.showText(ev.globalPos(), text, self)
                else:
                    QWhatsThis.leaveWhatsThisMode()
            return True
        return super(CharMap, self).event(ev)
    
    def getToolTipText(self, charcode):
        try:
            return unicodedata.name(chr(charcode))
        except ValueError:
            pass
    
    def getWhatsThisText(self, charcode):
        try:
            name = unicodedata.name(chr(charcode))
        except ValueError:
            return
        return whatsthis_html.format(
            self._font.family(), chr(charcode), name, charcode)
    
    def setShowToolTips(self, enabled):
        self._showToolTips = bool(enabled)
    
    def showToolTips(self):
        return self._showToolTips

    def setShowWhatsThis(self, enabled):
        self._showWhatsThis = bool(enabled)
    
    def showWhatsThis(self):
        return self._showWhatsThis

    def isprint(self, charcode):
        """Returns True if the given charcode is printable."""
        return isprint(charcode)