[Python] pqyt6 - How to insert word-wrap in svg content

Discussão em 'Python' iniciado por Stack, Setembro 5, 2025.

  1. Stack

    Stack Membro Participativo

    I'm creating pyqt6 app where I can replace normal fonts/text with svg fonts(.svg files like a.svg, b.svg etc).

    My issue is with word-wrap. In normal mode(svg mode is disabled) QTextEdit correctly moves a word to nex line if it does not fit completely in the line. But in svg mode it does not behave like that. It breaks word and pushes its some characters to the next line instead of moving the whole word to the next line.

    I tried replacing space(' ') with '\u200B' or ' ' + '\u200B'. But nothing works. Enter works as expected.

    Below is the relevant code:

    NON_SVG_CHARS = {' ', '\t', '\u2029', '\r', '\n'}


    class SvgTextObject(QObject, QTextObjectInterface):
    def __init__(self, char_path, parent=None):
    QObject.__init__(self, parent)
    QTextObjectInterface.__init__(self)
    self.char_path = char_path
    self.svg_renderer_cache = {}
    self.char_properties = {}
    self.normalized_svg_sizes = {}

    def intrinsicSize(self, doc, pos, fmt):

    char_name = fmt.stringProperty(SVGSettings.SVG_TEXT_FORMAT)

    format_id = fmt.property(SVGSettings.SVG_INSTANCE_ID)
    properties = self.getProperties(format_id)

    normalized_size = self.getNormalizedSize(char_name)
    if not normalized_size.isValid():
    return QSizeF()

    font_size = properties.get(SVGSettings.PropertyStrings.FONT_SIZE, SVGSettings.FontSize.DEFAULT)
    letter_width_percent = properties.get(SVGSettings.PropertyStrings.LETTER_WIDTH, 100.0)
    letter_height_percent = properties.get(SVGSettings.PropertyStrings.LETTER_HEIGHT, 100.0)
    letter_spacing = properties.get(SVGSettings.PropertyStrings.LETTER_SPACING, 0.0)


    width_scale_factor = (100.0 + letter_width_percent) / 100.0
    height_scale_factor = (100.0 + letter_height_percent) / 100.0


    base_scale = font_size / normalized_size.height()
    width = normalized_size.width() * base_scale * width_scale_factor
    height = normalized_size.height() * base_scale * height_scale_factor

    #Add spacing to width for layout purposes
    if pos > 0:
    prev_char = doc.characterAt(pos - 1)
    if not prev_char.isspace() and prev_char != QChar('\n'):
    width += letter_spacing
    return QSizeF(width, height)


    def drawObject(self, painter: QPainter, rect, doc, pos, fmt):

    painter.save()

    char_name = fmt.stringProperty(SVGSettings.SVG_TEXT_FORMAT)
    format_id = fmt.property(SVGSettings.SVG_INSTANCE_ID)
    properties = self.getProperties(format_id)

    letter_slant_value = properties.get(SVGSettings.PropertyStrings.LETTER_SLANTING, 0.0)
    letter_base_offset = properties.get(SVGSettings.PropertyStrings.LETTER_BASE_OFFSET, 0.0)
    letter_spacing = properties.get(SVGSettings.PropertyStrings.LETTER_SPACING, 0.0)

    normalized_size = self.getNormalizedSize(char_name)
    if not normalized_size.isValid():
    painter.restore()
    return

    font_size = properties.get(SVGSettings.PropertyStrings.FONT_SIZE, SVGSettings.FontSize.DEFAULT)
    letter_width_percent = properties.get(SVGSettings.PropertyStrings.LETTER_WIDTH, 100.0)
    letter_height_percent = properties.get(SVGSettings.PropertyStrings.LETTER_HEIGHT, 100.0)


    width_scale_factor = (100.0 + letter_width_percent) / 100.0
    height_scale_factor = (100.0 + letter_height_percent) / 100.0

    # Calculate scales and offsets based on the font size and character properties
    base_scale = font_size / normalized_size.height()
    final_scale_x = base_scale * width_scale_factor
    final_scale_y = base_scale * height_scale_factor


    painter.translate(rect.x(), rect.y())


    current_x_offset = 0.0
    if pos > 0:
    prev_char = doc.characterAt(pos - 1)
    if not prev_char.isspace() and prev_char != QChar('\n'):
    current_x_offset += letter_spacing

    current_y_offset = letter_base_offset


    intrinsic_height = self.intrinsicSize(doc, pos, fmt).height()
    scaled_svg_height = normalized_size.height() * final_scale_y
    extra_height_space = intrinsic_height - scaled_svg_height
    current_y_offset += extra_height_space / 2

    painter.translate(current_x_offset, current_y_offset)


    if letter_slant_value != 0.0:
    transform = painter.transform()
    transform.shear(letter_slant_value / 100.0, 0)
    painter.setTransform(transform)

    painter.scale(final_scale_x, final_scale_y)


    renderer = self.svg_renderer_cache.get(char_name)
    if renderer and renderer.isValid():
    renderer.render(painter, QRectF(0, 0, normalized_size.width(), normalized_size.height()))

    painter.restore()


    class CustomTextEdit(QGraphicsRectItem):

    def __init__(self, properties_provider=None, svg_font_directory=None, x=20, y=50, w=200, h=100):
    super().__init__(x, y, w, h)


    self.svg_font_directory = svg_font_directory

    self.svg_enabled = True


    self.text = EditableText(self, properties_provider)
    self.text.setReadOnly(True)
    self.text.pasteRequested.connect(self._handle_paste_request)


    self.text.document().contentsChange.connect(self.handle_contents_change)



    # self.text.textChanged.connect(self.handle_contents_change)


    # Register the custom SVG text object with the document's layout
    self.svg_object = SvgTextObject(self.svg_font_directory) # SVG directory
    self.text.document().documentLayout().registerHandler(SVGSettings.SVG_TEXT_FORMAT, self.svg_object)


    def handle_contents_change(self, position, chars_removed, chars_added):
    # check if replacing chars with svg chars is enabled
    if not self.svg_enabled:
    return

    if self.text._is_pasting:
    return

    # We only care about single-character additions
    if chars_removed == 0 and chars_added == 1:
    doc = self.text.document()
    new_char = doc.characterAt(position)

    if new_char in SVGSettings.NON_SVG_CHARS:
    return

    # already converted to unicode
    if new_char == '\uFFFC':
    return

    cursor = self.text.textCursor()
    self.text.document().blockSignals(True) # Block signals for safety

    cursor.beginEditBlock()

    cursor.setPosition(position)
    cursor.setPosition(position + 1, QTextCursor.MoveMode.KeepAnchor)

    svg_char_format = QTextCharFormat()
    svg_char_format.setObjectType(SVGSettings.SVG_TEXT_FORMAT)
    svg_char_format.setProperty(SVGSettings.SVG_TEXT_FORMAT, new_char)

    instance_id = str(uuid.uuid4())
    svg_char_format.setProperty(SVGSettings.SVG_INSTANCE_ID, instance_id)

    # Retrieve properties and set them before insertion
    properties = {}
    current_properties = self.text.properties_provider.get_current_properties()
    for prop_name, slider_values in current_properties.items():
    settings_class = SVGSettings.SLIDER_MAPPING.get(prop_name)
    if settings_class:
    step_size = settings_class.STEP
    properties[prop_name] = get_random_value_with_step(slider_values, step_size)
    else:
    properties[prop_name] = slider_values

    self.svg_object.setRandomProperties(instance_id, properties)

    cursor.insertText("\uFFFC", svg_char_format)

    cursor.endEditBlock()
    self.text.document().blockSignals(False) # Unblock signals


    Please, help me solve this issue.

    Thank you.

    Continue reading...

Compartilhe esta Página