Commit 5aeb9602 authored by dmMaze's avatar dmMaze
Browse files

bug fixes and optimization for vtextlayout

parent 8404b3ff
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -152,10 +152,12 @@ def main():
    from qtpy.QtWidgets import QApplication, QStyleFactory
    from qtpy.QtCore import QTranslator, QLocale, Qt
    from qtpy.QtGui import QIcon, QFontDatabase, QGuiApplication, QFont
    from qtpy import API

    from ui import constants as C
    from ui import config as program_config
    C.DEFAULT_DISPLAY_LANG = QLocale.system().name()
    C.USE_PYSIDE6 = API == 'pyside6'
    if qtpy.API_NAME[-1] == '6':
        C.FLAG_QT6 = True
    else:
@@ -252,5 +254,4 @@ def prepare_environment():
        importlib.reload(site)

if __name__ == '__main__':

    main()
+3 −1
Original line number Diff line number Diff line
@@ -73,3 +73,5 @@ for p in os.listdir(TRANSLATE_DIR):
            DISPLAY_LANGUAGE_MAP[lang] = lang

DEFAULT_DISPLAY_LANG = 'English'

USE_PYSIDE6 = False
 No newline at end of file
+113 −49
Original line number Diff line number Diff line
import sys
import pkg_resources
ON_MACOS = sys.platform == 'darwin'

from qtpy.QtCore import Qt, QRectF, QPointF, Signal, QSizeF, QSize
from qtpy.QtGui import QTextCharFormat, QTextDocument, QPixmap, QImage, QTransform, QPalette, QPainter, QTextFrame, QTextBlock, QAbstractTextDocumentLayout, QTextLayout, QFont, QFontMetrics, QTextOption, QTextLine, QTextFormat
from qtpy import QT_VERSION
TEXTLAYOUT_QTVERSION = pkg_resources.parse_version(QT_VERSION) > pkg_resources.parse_version('6.4.2')

import cv2
import numpy as np
@@ -101,14 +104,14 @@ class CharFontFormat:

    @cached_property
    def br(self) -> QRectF:
        return get_punc_rect('', self.family, self.size, self.weight, self.font.italic())[1]
        # return get_punc_rect('', self.family, self.size, self.weight, self.font.italic())[1]
        _, br1 = get_punc_rect('', self.family, self.size, self.weight, self.font.italic())
        _, br2 = get_punc_rect('', self.family, self.size, self.weight, self.font.italic())
        return QRectF(br2.left(), br2.top(), br1.right() - br2.left(), br2.height())

    @cached_property
    def tbr(self) -> QRectF:
        return get_punc_rect('', self.family, self.size, self.weight, self.font.italic())[0]
        # return get_punc_rect('', self.family, self.size, self.weight, self.font.italic())[0]
        br1, _ = get_punc_rect('', self.family, self.size, self.weight, self.font.italic())
        br2, _ = get_punc_rect('', self.family, self.size, self.weight, self.font.italic())
        return QRectF(br2.left(), br2.top(), br1.right() - br2.left(), br2.height())
@@ -134,12 +137,12 @@ class CharFontFormat:
    def size(self) -> float:
        return self.font.pointSizeF()

    def punc_actual_rect(self, line: QTextLine, char: str, cache=False) -> List[int]:
    def punc_actual_rect(self, line: QTextLine, char: str, cache=False, stroke_width=0) -> List[int]:
        if cache:
            line = LruIgnoreArg(line=line)
            ar = punc_actual_rect_cached(line, char, self.family, self.size, self.weight, self.font.italic(), self.stroke_width)
            ar = punc_actual_rect_cached(line, char, self.family, self.size, self.weight, self.font.italic(), stroke_width)
        else:
            ar =  punc_actual_rect(line, self.family, self.size, self.weight, self.font.italic(), self.stroke_width)
            ar =  punc_actual_rect(line, self.family, self.size, self.weight, self.font.italic(), stroke_width)
        return ar


@@ -176,6 +179,9 @@ class SceneTextLayout(QAbstractTextDocumentLayout):

        self._doc_text: str = ''
        
        self._is_painting_stroke = False
        self._draw_offset = []

    def setMaxSize(self, max_width: int, max_height: int, relayout=True):
        self.max_height = max_height
        self.max_width = max_width
@@ -324,83 +330,68 @@ class VerticalTextDocumentLayout(SceneTextLayout):
                        line_pos.setX(x_shift + line_pos.x())
                        line.setPosition(line_pos)
                    block = block.next()
        self.updateDrawOffsets()
        self.documentSizeChanged.emit(QSizeF(self.max_width, self.max_height))

    def draw(self, painter: QPainter, context: QAbstractTextDocumentLayout.PaintContext) -> None:
    def updateDrawOffsets(self):
        if self._is_painting_stroke and len(self._draw_offset) > 0:
            return
        self._draw_offset.clear()
        doc = self.document()
        painter.save()
        block = doc.firstBlock()
        cursor_block = None
        context_sel = context.selections
        has_selection = False
        selection = None
        if len(context_sel) > 0:
            has_selection = True
            selection = context_sel[0]

        while block.isValid():
            blpos, bllen = block.position(), block.length()
            blk_no = block.blockNumber()
            _draw_offsets = []
            self._draw_offset.append(_draw_offsets)

            layout = block.layout()
            blk_text = block.text()
            blk_text_len = len(blk_text)
            blk_no = block.blockNumber()
            line_spaces_lst = self.line_spaces_lst[blk_no]
            
            if context.cursorPosition >= blpos and context.cursorPosition < blpos + bllen:
                cursor_block = block
            line_spaces_lst = self.line_spaces_lst[blk_no]

            for ii in range(layout.lineCount()):
                xy_offsets = [0, 0]
                _draw_offsets.append(xy_offsets)

                line = layout.lineAt(ii)
                if line.textLength() == 0:
                    continue
                num_rspaces, num_lspaces, _, line_pos  = line_spaces_lst[ii]
                char_idx = min(line_pos + num_lspaces, blk_text_len - 1)
                if char_idx < 0:
                    line.draw(painter, QPointF(0, 0))
                    continue

                char = blk_text[char_idx]
                cfmt = self.get_char_fontfmt(blk_no, char_idx)
                fm = cfmt.font_metrics
                selected = False
                if has_selection:
                    sel_start = selection.cursor.selectionStart() - blpos 
                    sel_end = selection.cursor.selectionEnd() - blpos
                    if char_idx < sel_end and char_idx >= sel_start:
                        selected = True
                
                # natral_shifted = max(line.naturalTextWidth() - cfmt.br.width(), 0)
                natral_shifted = 0
                if char in PUNSET_VERNEEDROTATE:
                    char = blk_text[char_idx]
                    line_x, line_y = line.x(), line.y()

                    y_x = line_y - line_x
                    y_p_x = line_y + line_x
                    transform = QTransform(0, 1, 0, -1, 0, 0, y_p_x, y_x, 1)
                    inv_transform = QTransform(0, -1, 0, 1, 0, 0, -y_x, y_p_x, 1)
                    painter.setTransform(transform, True)
                    pun_tbr, pun_br = cfmt.punc_rect(char)
                    hight_comp = pun_tbr.width() - pun_br.width()

                    if char.isalpha():
                        xoff = 0
                        pun_top = cfmt.punc_rect('f')[0].top()
                        yoff = -pun_top - fm.ascent() - cfmt.br.width()
                        hight_comp = 0
                    elif char in PUNSET_NONBRACKET:
                        xoff = pun_tbr.width() - pun_br.width()
                        non_bracket_br = cfmt.punc_actual_rect(line, char, cache=True)
                        yoff =  -non_bracket_br[1] - non_bracket_br[3]
                        if self.punc_align_center:
                            yoff = yoff - (cfmt.br.width() - non_bracket_br[3] + cfmt.tbr.left()) / 2
                        else:
                            yoff = yoff - (cfmt.br.width() - non_bracket_br[3] + cfmt.tbr.left()) / 2
                    else:   # () ()
                        non_bracket_br = cfmt.punc_actual_rect(line, char, cache=True)
                        xoff = -non_bracket_br[0]
                        if TEXTLAYOUT_QTVERSION:
                            yoff =  -non_bracket_br[3] - (cfmt.br.width() - non_bracket_br[3]) / 2
                        else:
                        non_bracket_br = cfmt.punc_actual_rect(line, char=char, cache=False)
                            yoff = -non_bracket_br[1] - non_bracket_br[3] - (cfmt.br.width() - non_bracket_br[3]) / 2

                    self.line_draw(painter, line, hight_comp,  yoff, selected, selection)
                    painter.setTransform(inv_transform, True)

                elif char in PUNSET_PAUSEORSTOP:
                    pun_tbr, pun_br = cfmt.punc_rect(char)
                    if char in {'', '', '', ''}:
@@ -417,13 +408,80 @@ class VerticalTextDocumentLayout(SceneTextLayout):
                        xoff += (cfmt.br.width() - pun_tbr.width()) / 2
                    else:
                        xoff += cfmt.br.width() - pun_tbr.width()
                    self.line_draw(painter, line, xoff, yoff, selected, selection)

                else:
                    if num_lspaces > 0:
                        natral_shifted = num_lspaces * cfmt.space_width
                    yoff = min(cfmt.br.top() - cfmt.tbr.top(), -cfmt.tbr.top() - fm.ascent())
                    self.line_draw(painter, line, -natral_shifted, yoff + natral_shifted, selected, selection)
                    empty_spacing = num_lspaces * cfmt.space_width
                    if TEXTLAYOUT_QTVERSION:
                        xshift = max(line.naturalTextWidth() - cfmt.br.width(), 0)
                    else:
                        xshift = empty_spacing
                        
                    xoff = -xshift
                    yoff = min(cfmt.br.top() - cfmt.tbr.top(), -cfmt.tbr.top() - fm.ascent()) + empty_spacing

                xy_offsets[0], xy_offsets[1] = xoff, yoff
            block = block.next()


    def draw(self, painter: QPainter, context: QAbstractTextDocumentLayout.PaintContext) -> None:
        doc = self.document()
        painter.save()
        block = doc.firstBlock()
        cursor_block = None
        context_sel = context.selections
        has_selection = False
        selection = None
        if len(context_sel) > 0:
            has_selection = True
            selection = context_sel[0]


        while block.isValid():
            blk_no = block.blockNumber()
            blpos, bllen = block.position(), block.length()
            layout = block.layout()
            blk_text = block.text()
            blk_text_len = len(blk_text)
            
            line_spaces_lst = self.line_spaces_lst[blk_no]

            if context.cursorPosition >= blpos and context.cursorPosition < blpos + bllen:
                cursor_block = block

            for ii in range(layout.lineCount()):
                line = layout.lineAt(ii)
                if line.textLength() == 0:
                    continue
                num_rspaces, num_lspaces, _, line_pos  = line_spaces_lst[ii]
                char_idx = min(line_pos + num_lspaces, blk_text_len - 1)
                if char_idx < 0:
                    line.draw(painter, QPointF(0, 0))
                    continue

                xoff, yoff = self._draw_offset[blk_no][ii]

                char = blk_text[char_idx]
                cfmt = self.get_char_fontfmt(blk_no, char_idx)
                fm = cfmt.font_metrics
                selected = False
                if has_selection:
                    sel_start = selection.cursor.selectionStart() - blpos 
                    sel_end = selection.cursor.selectionEnd() - blpos
                    if char_idx < sel_end and char_idx >= sel_start:
                        selected = True
                
                if char in PUNSET_VERNEEDROTATE:
                    line_x, line_y = line.x(), line.y()

                    y_x = line_y - line_x
                    y_p_x = line_y + line_x
                    transform = QTransform(0, 1, 0, -1, 0, 0, y_p_x, y_x, 1)
                    inv_transform = QTransform(0, -1, 0, 1, 0, 0, -y_x, y_p_x, 1)
                    painter.setTransform(transform, True)
                    self.line_draw(painter, line, xoff,  yoff, selected, selection)
                    painter.setTransform(inv_transform, True)
                else:
                    self.line_draw(painter, line, xoff, yoff, selected, selection)

            block = block.next()

@@ -456,7 +514,13 @@ class VerticalTextDocumentLayout(SceneTextLayout):
                painter.setCompositionMode(QPainter.CompositionMode.RasterOp_NotDestination)
                painter.fillRect(QRectF(x, y, fm.height(), 2), painter.pen().brush())
                if self.has_selection == has_selection:
                    if C.USE_PYSIDE6:
                        self.update.emit()
                    else:
                        self.update.emit(QRectF(x, y, fm.height(), 2))
                else:
                    if C.USE_PYSIDE6:
                        self.update.emit()
                    else:
                        self.update.emit(QRectF(0, 0, self.max_width, self.max_height))
            self.has_selection = has_selection  # update this flag when drawing the cursor
+7 −3
Original line number Diff line number Diff line
@@ -17,11 +17,12 @@ from .canvas import Canvas
from .textedit_area import TransTextEdit, SourceTextEdit, TransPairWidget, SelectTextMiniMenu, TextEditListScrollArea, QVBoxLayout, Widget
from .misc import FontFormat, pt2px
from .textedit_commands import propagate_user_edit, TextEditCommand, ReshapeItemCommand, MoveBlkItemsCommand, AutoLayoutCommand, ApplyFontformatCommand, ApplyEffectCommand, RotateItemCommand, TextItemEditCommand, TextEditCommand, PageReplaceOneCommand, PageReplaceAllCommand, MultiPasteCommand, ResetAngleCommand
from .fontformatpanel import FontFormatPanel
from .config import pcfg
from . import constants as C
from utils.imgproc_utils import extract_ballon_region, rotate_polygons, get_block_mask
from utils.text_processing import seg_text, is_cjk
from utils.text_layout import layout_text
from .fontformatpanel import FontFormatPanel
from .config import pcfg


class CreateItemCommand(QUndoCommand):
@@ -486,6 +487,9 @@ class SceneTextManager(QObject):
            self.hovering_transwidget.setHoverEffect(False)
        self.hovering_transwidget = edit
        if edit is not None:
            if C.USE_PYSIDE6:
                self.textEditList.ensureWidgetVisible(edit, ymargin=edit.geometry().height())
            else:
                self.textEditList.ensureWidgetVisible(edit, yMargin=edit.geometry().height())
            edit.setHoverEffect(True)

+2 −0
Original line number Diff line number Diff line
@@ -150,8 +150,10 @@ class TextBlkItem(QGraphicsTextItem):
        doc = self.document().clone()
        doc.setDocumentMargin(self.padding())
        layout = VerticalTextDocumentLayout(doc) if self.is_vertical else HorizontalTextDocumentLayout(doc)
        layout._draw_offset = self.layout._draw_offset
        layout.line_spacing = self.line_spacing
        layout.letter_spacing = self.letter_spacing
        layout._is_painting_stroke = True
        rect = self.rect()
        layout.setMaxSize(rect.width(), rect.height(), False)
        doc.setDocumentLayout(layout)