Commit 7246e241 authored by dmMaze's avatar dmMaze
Browse files

sync page search with textitem deletion

parent dd196b18
Loading
Loading
Loading
Loading
+79 −8
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@ from typing import List, Union

from qtpy.QtWidgets import QTextEdit, QScrollArea, QGraphicsDropShadowEffect, QVBoxLayout, QFrame, QApplication
from qtpy.QtCore import Signal, Qt, QSize, QEvent
from qtpy.QtGui import QColor, QFocusEvent, QInputMethodEvent, QKeyEvent
from qtpy.QtGui import QColor, QFocusEvent, QInputMethodEvent, QKeyEvent, QTextCursor
try:
    from qtpy.QtWidgets import QUndoCommand
except:
@@ -19,10 +19,12 @@ class SourceTextEdit(QTextEdit):
    hover_leave = Signal(int)
    focus_in = Signal(int)
    user_edited = Signal()
    user_edited_verbose = Signal(int, str, bool)
    ensure_scene_visible = Signal()
    redo_signal = Signal()
    undo_signal = Signal()
    push_undo_stack = Signal()
    push_undo_stack = Signal(int)
    text_changed = Signal()

    def __init__(self, idx, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
@@ -31,24 +33,70 @@ class SourceTextEdit(QTextEdit):
        self.setMinimumHeight(50)
        self.document().contentsChanged.connect(self.on_content_changed)
        self.document().documentLayout().documentSizeChanged.connect(self.adjustSize)
        self.document().contentsChange.connect(self.on_content_changing)
        self.setAcceptRichText(False)
        self.setAttribute(Qt.WidgetAttribute.WA_InputMethodEnabled, True)
        self.old_undo_steps = self.document().availableUndoSteps()
        self.in_redo_undo = False
        self.change_from: int = 0
        self.change_removed: int = 0
        self.change_added: int = 0
        self.input_method_from = -1
        self.input_method_text = ''
        self.text_content_changed = False
        self.high_lighting = False

    def on_content_changing(self, from_: int, removed: int, added: int):
        if not self.pre_editing:
            self.text_content_changed = True
        if self.hasFocus() and not self.pre_editing:
            self.change_from = from_
            self.change_added = added
    

    def adjustSize(self):
        h = self.document().documentLayout().documentSize().toSize().height()
        self.setFixedHeight(max(h, 50))

    def on_content_changed(self):
        if self.text_content_changed:
            self.text_content_changed = False
            if not self.high_lighting:
                self.text_changed.emit()
        if self.hasFocus() and not self.pre_editing:
            self.user_edited.emit()

            if not self.in_redo_undo:

                change_from = self.change_from
                added_text = ''
                input_method_used = False
                if self.input_method_from != -1:
                    added_text = self.input_method_text
                    change_from = self.input_method_from
                    input_method_used = True
        
                elif self.change_added > 0:
                    len_text = len(self.toPlainText())
                    cursor = self.textCursor()
                    
                    if self.change_added >  len_text:
                        self.change_added = 1
                        change_from = self.textCursor().position() - 1
                        input_method_used = True
                    cursor.setPosition(change_from)
                    cursor.setPosition(change_from + self.change_added, QTextCursor.MoveMode.KeepAnchor)
                    
                    added_text = cursor.selectedText()
                self.user_edited_verbose.emit(change_from, added_text, input_method_used)
                

                undo_steps = self.document().availableUndoSteps()
                if undo_steps != self.old_undo_steps:
                new_steps = undo_steps - self.old_undo_steps
                if new_steps > 0:
                    self.old_undo_steps = undo_steps
                    self.push_undo_stack.emit()
                    self.push_undo_stack.emit(new_steps)


    def setHoverEffect(self, hover: bool):
        try:
@@ -84,11 +132,17 @@ class SourceTextEdit(QTextEdit):
        return super().focusOutEvent(event)

    def inputMethodEvent(self, e: QInputMethodEvent) -> None:
        cursor = self.textCursor()
        
        if e.preeditString() == '':
            self.pre_editing = False
            self.input_method_text = e.commitString()
        else:
            if self.pre_editing is False:
                self.input_method_from = cursor.selectionStart()
            self.pre_editing = True
        return super().inputMethodEvent(e)
        self.input_method_event = e
        super().inputMethodEvent(e)

    def keyPressEvent(self, e: QKeyEvent) -> None:
        if e.modifiers() == Qt.KeyboardModifier.ControlModifier:
@@ -114,6 +168,10 @@ class SourceTextEdit(QTextEdit):
        self.in_redo_undo = False
        self.old_undo_steps = self.document().availableUndoSteps()

    def block_all_signals(self, block: bool):
        self.blockSignals(block)
        self.document().blockSignals(block)
        
class TransTextEdit(SourceTextEdit):
    pass

@@ -177,17 +235,30 @@ class TextPanel(Widget):


class TextEditCommand(QUndoCommand):
    def __init__(self, edit: Union[SourceTextEdit, TransTextEdit]) -> None:
    def __init__(self, edit: Union[SourceTextEdit, TransTextEdit], blkitem: TextBlkItem, num_steps: int) -> None:
        super().__init__()
        self.edit = edit
        self.blkitem = blkitem
        self.op_counter = -1
        self.change_from = edit.change_from
        self.change_added = edit.change_added
        self.change_removed = edit.change_removed
        self.num_steps = min(num_steps, 2)
        if edit.input_method_from == -1:
            self.num_steps = 1
        else:
            edit.input_method_from = -1

    def redo(self):
        self.op_counter += 1
        if self.op_counter <= 0:
            return
        for _ in range(self.num_steps):
            self.edit.redo()
        self.blkitem.document().redo()

    def undo(self):
        for _ in range(self.num_steps):
            self.edit.undo()
        self.blkitem.document().undo()
+103 −12
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ import numpy as np

from qtpy.QtWidgets import QApplication
from qtpy.QtCore import QObject, QRectF, Qt, Signal
from qtpy.QtGui import QTextCursor, QFontMetrics, QFont, QTextCharFormat
from qtpy.QtGui import QTextCursor, QFontMetrics, QFont, QTextCharFormat, QInputMethodEvent
try:
    from qtpy.QtWidgets import QUndoCommand
except:
@@ -15,6 +15,7 @@ from .canvas import Canvas
from .imgtranspanel import TextPanel, TransTextEdit, SourceTextEdit, TransPairWidget, TextEditCommand
from .fontformatpanel import set_textblk_fontsize
from .misc import FontFormat, ProgramConfig, pt2px
from .search_replace_widgets import SearchWidget

from utils.imgproc_utils import extract_ballon_region
from utils.text_processing import seg_text, is_cjk
@@ -186,19 +187,90 @@ class CreateItemCommand(QUndoCommand):
class DeleteBlkItemsCommand(QUndoCommand):
    def __init__(self, blk_list: List[TextBlkItem], ctrl, parent=None):
        super().__init__(parent)
        self.op_counter = -1
        self.blk_list = []
        self.pwidget_list = []
        self.pwidget_list: List[TransPairWidget] = []
        self.ctrl: SceneTextManager = ctrl
        self.sw = self.ctrl.canvas.search_widget

        self.search_rstedit_list: List[SourceTextEdit] = []
        self.search_counter_list = []
        self.highlighter_list = []
        self.old_counter_sum = self.sw.counter_sum
        self.sw_changed = False
        
        for blkitem in blk_list:
            if isinstance(blkitem, TextBlkItem):
            if not isinstance(blkitem, TextBlkItem):
                continue
            self.blk_list.append(blkitem)
                self.pwidget_list.append(ctrl.pairwidget_list[blkitem.idx])
            pw: TransPairWidget = ctrl.pairwidget_list[blkitem.idx]
            self.pwidget_list.append(pw)

            rst_idx = self.sw.get_result_edit_index(pw.e_trans)
            if rst_idx != -1:
                self.sw_changed = True
                highlighter = self.sw.highlighter_list.pop(rst_idx)
                counter = self.sw.search_counter_list.pop(rst_idx)
                self.sw.counter_sum -= counter
                if self.sw.current_edit == pw.e_trans:
                    highlighter.set_current_start(-1)
                self.search_rstedit_list.append(self.sw.search_rstedit_list.pop(rst_idx))
                self.search_counter_list.append(counter)
                self.highlighter_list.append(highlighter)

            rst_idx = self.sw.get_result_edit_index(pw.e_source)
            if rst_idx != -1:
                self.sw_changed = True
                highlighter = self.sw.highlighter_list.pop(rst_idx)
                counter = self.sw.search_counter_list.pop(rst_idx)
                self.sw.counter_sum -= counter
                if self.sw.current_edit == pw.e_trans:
                    highlighter.set_current_start(-1)
                self.search_rstedit_list.append(self.sw.search_rstedit_list.pop(rst_idx))
                self.search_counter_list.append(counter)
                self.highlighter_list.append(highlighter)

        self.new_counter_sum = self.sw.counter_sum
        if self.sw_changed:
            if self.sw.counter_sum > 0:
                self.sw.setCurrentEditor(self.sw.search_rstedit_list[0])
            else:
                self.sw.setCurrentEditor(None)

        self.ctrl.deleteTextblkItemList(self.blk_list, self.pwidget_list)

    def redo(self):
        self.op_counter += 1
        if self.op_counter <= 0:
            return

        self.ctrl.deleteTextblkItemList(self.blk_list, self.pwidget_list)
        if self.sw_changed:
            self.sw.counter_sum = self.new_counter_sum
            for edit in self.search_rstedit_list:
                idx = self.sw.get_result_edit_index(edit)
                if idx != -1:
                    self.sw.search_rstedit_list.pop(idx)
                    self.sw.search_counter_list.pop(idx)
                    self.sw.highlighter_list.pop(idx)
            if self.sw.counter_sum > 0:
                self.sw.setCurrentEditor(self.sw.search_rstedit_list[0])
            else:
                self.sw.setCurrentEditor(None)


    def undo(self):
        self.ctrl.recoverTextblkItemList(self.blk_list, self.pwidget_list)
        if self.sw_changed:
            self.sw.counter_sum = self.old_counter_sum
            for edit in self.search_rstedit_list:
                self.sw.search_rstedit_list += self.search_rstedit_list
                self.sw.search_counter_list += self.search_counter_list
                self.sw.highlighter_list += self.highlighter_list
            if self.sw.counter_sum > 0:
                self.sw.setCurrentEditor(self.sw.search_rstedit_list[0])
            else:
                self.sw.setCurrentEditor(None)

    def mergeWith(self, command: QUndoCommand):
        blk_list = command.blk_list
@@ -343,7 +415,7 @@ class SceneTextManager(QObject):

        pair_widget.e_trans.setPlainText(blk_item.toPlainText())
        pair_widget.e_trans.focus_in.connect(self.onTransWidgetHoverEnter)
        pair_widget.e_trans.user_edited.connect(self.onTransWidgetUserEdited)
        pair_widget.e_trans.user_edited_verbose.connect(self.onTransWidgetUserEditedVerbose)
        pair_widget.e_trans.ensure_scene_visible.connect(self.on_ensure_textitem_svisible)
        pair_widget.e_trans.push_undo_stack.connect(self.on_push_edit_stack)
        pair_widget.e_trans.redo_signal.connect(self.canvasUndoStack.redo)
@@ -386,12 +458,14 @@ class SceneTextManager(QObject):
        self.txtblkShapeControl.setBlkItem(None)

    def recoverTextblkItem(self, blkitem: TextBlkItem, p_widget: TransPairWidget):
        # recovered order is different from before
        blkitem.idx = len(self.textblk_item_list)
        p_widget.idx = len(self.pairwidget_list)
        self.textblk_item_list.append(blkitem)
        blkitem.setParentItem(self.canvas.textLayer)
        self.pairwidget_list.append(p_widget)
        self.textEditList.addPairWidget(p_widget)
        self.updateTextBlkItemIdx()

    def recoverTextblkItemList(self, blkitem_list: List[TextBlkItem], p_widget_list: List[TransPairWidget]):
        for blkitem, p_widget in zip(blkitem_list, p_widget_list):
@@ -709,12 +783,27 @@ class SceneTextManager(QObject):
        self.canvas.gv.ensureVisible(blk_item)
        self.txtblkShapeControl.setBlkItem(blk_item)

    def onTransWidgetUserEdited(self):
    def onTransWidgetUserEditedVerbose(self, pos: int, added_text: str, input_method_used: bool):
        edit: TransTextEdit = self.sender()
        idx = edit.idx
        blk_item = self.textblk_item_list[idx]
        blk_item.setTextInteractionFlags(Qt.NoTextInteraction)
        blk_item.setPlainText(self.pairwidget_list[idx].e_trans.toPlainText())
        if blk_item.isEditing():
            blk_item.setTextInteractionFlags(Qt.TextInteractionFlag.NoTextInteraction)

        ori_count = blk_item.document().characterCount()
        new_count = edit.document().characterCount()
        removed = ori_count + len(added_text) - new_count
        # if not input_method_used:

        cursor = blk_item.textCursor()
        cursor.setPosition(pos)
        if removed > 0:
            cursor.setPosition(pos + removed, QTextCursor.MoveMode.KeepAnchor)
        if input_method_used:
            cursor.beginEditBlock()
        cursor.insertText((added_text))
        if input_method_used:
            cursor.endEditBlock()
        self.canvas.setProjSaveState(True)

    def onGlobalFormatChanged(self):
@@ -788,8 +877,10 @@ class SceneTextManager(QObject):
        self.canvas.gv.ensureVisible(self.textblk_item_list[edit.idx])
        self.txtblkShapeControl.setBlkItem(self.textblk_item_list[edit.idx])

    def on_push_edit_stack(self):
        self.canvasUndoStack.push(TextEditCommand(self.sender()))
    def on_push_edit_stack(self, num_steps: int):
        edit: Union[TransTextEdit, SourceTextEdit] = self.sender()
        blkitem = self.textblk_item_list[edit.idx]
        self.canvasUndoStack.push(TextEditCommand(self.sender(), blkitem, num_steps))


def get_text_size(fm: QFontMetrics, text: str) -> Tuple[int, int]:
+162 −79

File changed.

Preview size limit exceeded, changes collapsed.

+5 −5
Original line number Diff line number Diff line
@@ -313,7 +313,7 @@ class TextBlkItem(QGraphicsTextItem):
        if valid_layout:
            rect = self.rect() if self.layout is not None else None
        
        self.setTextInteractionFlags(Qt.NoTextInteraction)
        self.setTextInteractionFlags(Qt.TextInteractionFlag.NoTextInteraction)
        doc = self.document()
        html = doc.toHtml()
        doc_margin = doc.documentMargin()
@@ -420,7 +420,7 @@ class TextBlkItem(QGraphicsTextItem):
    def startEdit(self) -> None:
        self.pre_editing = False
        self.setCacheMode(QGraphicsItem.CacheMode.NoCache)
        self.setTextInteractionFlags(Qt.TextEditorInteraction)
        self.setTextInteractionFlags(Qt.TextInteractionFlag.TextEditorInteraction)
        self.setFocus()
        self.begin_edit.emit(self.idx)

@@ -429,12 +429,12 @@ class TextBlkItem(QGraphicsTextItem):
        cursor = self.textCursor()
        cursor.clearSelection()
        self.setTextCursor(cursor)
        self.setTextInteractionFlags(Qt.NoTextInteraction)
        self.setTextInteractionFlags(Qt.TextInteractionFlag.NoTextInteraction)
        self.setCacheMode(QGraphicsItem.CacheMode.DeviceCoordinateCache)
        self.setFocus()

    def isEditing(self) -> bool:
        return self.textInteractionFlags() == Qt.TextEditorInteraction
        return self.textInteractionFlags() == Qt.TextInteractionFlag.TextEditorInteraction
    
    def mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent) -> None:    
        self.startEdit()
@@ -442,7 +442,7 @@ class TextBlkItem(QGraphicsTextItem):
        
    def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
        if not self.bound_checking or \
            self.textInteractionFlags() == Qt.TextEditorInteraction:
            self.textInteractionFlags() == Qt.TextInteractionFlag.TextEditorInteraction:
            super().mouseMoveEvent(event)
        else:
            b_rect = self.boundingRect()