Commit e160e455 authored by dmMaze's avatar dmMaze
Browse files

Support copy&paste selected text blocks

parent f961c462
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -286,6 +286,15 @@ class TextBlock(object):
            return self.default_stroke_width
        return 0

    def adjust_pos(self, dx: int, dy: int):
        self.xyxy[0] += dx
        self.xyxy[1] += dy
        self.xyxy[2] += dx
        self.xyxy[3] += dy
        if self._bounding_rect is not None:
            self._bounding_rect[0] += dx
            self._bounding_rect[1] += dy

def sort_textblk_list(blk_list: List[TextBlock], im_w: int, im_h: int) -> List[TextBlock]:
    if len(blk_list) == 0:
        return blk_list
+37 −3
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ from typing import List, Union, Tuple

from qtpy.QtWidgets import QMenu, QGraphicsScene, QGraphicsView, QGraphicsRectItem, QGraphicsItem, QScrollBar, QGraphicsPixmapItem, QGraphicsSceneMouseEvent, QGraphicsSceneContextMenuEvent, QRubberBand
from qtpy.QtCore import Qt, QDateTime, QRectF, QPointF, QPoint, Signal, QSizeF, QEvent
from qtpy.QtGui import QPixmap, QHideEvent, QKeyEvent, QWheelEvent, QResizeEvent, QPainter, QPen, QPainterPath
from qtpy.QtGui import QPixmap, QHideEvent, QKeyEvent, QWheelEvent, QResizeEvent, QPainter, QPen, QPainterPath, QCursor

try:
    from qtpy.QtWidgets import QUndoStack, QUndoCommand
@@ -59,6 +59,10 @@ class CustomGV(QGraphicsView):
                if self.canvas.handle_ctrlv():
                    e.accept()
                    return
            if e.key() == Qt.Key.Key_C:
                if self.canvas.handle_ctrlc():
                    e.accept()
                    return

        return super().keyPressEvent(e)

@@ -84,6 +88,8 @@ class Canvas(QGraphicsScene):
    finish_painting = Signal(StrokeImgItem)
    finish_erasing = Signal(StrokeImgItem)
    delete_textblks = Signal()
    copy_textblks = Signal(QPointF)
    paste_textblks = Signal(QPointF)
    format_textblks = Signal()
    layout_textblks = Signal()

@@ -188,6 +194,8 @@ class Canvas(QGraphicsScene):
        self.saved_textundo_step = 0
        self.saved_drawundo_step = 0

        self.clipboard_blks: List[TextBlock] = []

    def textEditMode(self) -> bool:
        return self.editor_index == 1

@@ -380,9 +388,28 @@ class Canvas(QGraphicsScene):
        if self.editing_textblkitem is not None and self.editing_textblkitem.isEditing():
            return False

        if len(self.selected_text_items()) > 0:
            self.paste2selected_textitems.emit()
        else:
            self.paste_textblks.emit(self.scene_cursor_pos())

        return True

    def handle_ctrlc(self):
        if not self.textEditMode():
            return False        
        if self.editing_textblkitem is not None and self.editing_textblkitem.isEditing():
            return False

        if len(self.selected_text_items()) > 0:
            self.copy_textblks.emit(self.scene_cursor_pos())
        
        return True

    def scene_cursor_pos(self):
        origin = self.gv.mapFromGlobal(QCursor.pos())
        return self.gv.mapToScene(origin)

    def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
        btn = event.button()
        if btn == Qt.MouseButton.MiddleButton:
@@ -507,14 +534,21 @@ class Canvas(QGraphicsScene):
        self.textblock_mode = mode

    def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
        if len(self.selectedItems()) != 0:
        if self.textEditMode():
            menu = QMenu()
            copy_act = menu.addAction(self.tr("Copy"))
            paste_act = menu.addAction(self.tr("Paste"))
            delete_act = menu.addAction(self.tr("Delete"))
            menu.addSeparator()
            format_act = menu.addAction(self.tr("Apply font formatting"))
            layout_act = menu.addAction(self.tr("Auto layout"))
            rst = menu.exec_(event.screenPos())
            if rst == delete_act:
                self.delete_textblks.emit()
            elif rst == copy_act:
                self.copy_textblks.emit(event.scenePos())
            elif rst == paste_act:
                self.paste_textblks.emit(event.scenePos())
            elif rst == format_act:
                self.format_textblks.emit()
            elif rst == layout_act:
+70 −1
Original line number Diff line number Diff line

from typing import List, Union, Tuple
import numpy as np
import copy

from qtpy.QtWidgets import QApplication
from qtpy.QtCore import QObject, QRectF, Qt, Signal
from qtpy.QtCore import QObject, QRectF, Qt, Signal, QPointF
from qtpy.QtGui import QTextCursor, QFontMetrics, QFont, QTextCharFormat
try:
    from qtpy.QtWidgets import QUndoCommand
@@ -137,6 +138,25 @@ class DeleteBlkItemsCommand(QUndoCommand):
            self.sw.updateCounterText()


class PasteBlkItemsCommand(QUndoCommand):
    def __init__(self, blk_list: List[TextBlkItem], pwidget_list: List[TransPairWidget], ctrl, parent=None):
        super().__init__(parent)
        self.op_counter = 0
        self.blk_list = blk_list
        for blkitem in blk_list:
            blkitem.setSelected(True)
        self.pwidget_list = pwidget_list
        self.ctrl:SceneTextManager = ctrl

    def redo(self):
        if self.op_counter == 0:
            self.op_counter += 1
            return
        self.ctrl.recoverTextblkItemList(self.blk_list, self.pwidget_list)

    def undo(self):
        self.ctrl.deleteTextblkItemList(self.blk_list, self.pwidget_list)

class SceneTextManager(QObject):
    new_textblk = Signal(int)
    def __init__(self, 
@@ -151,6 +171,8 @@ class SceneTextManager(QObject):
        self.canvas.end_create_textblock.connect(self.onEndCreateTextBlock)
        self.canvas.paste2selected_textitems.connect(self.on_paste2selected_textitems)
        self.canvas.delete_textblks.connect(self.onDeleteBlkItems)
        self.canvas.copy_textblks.connect(self.onCopyBlkItems)
        self.canvas.paste_textblks.connect(self.onPasteBlkItems)
        self.canvas.format_textblks.connect(self.onFormatTextblks)
        self.canvas.layout_textblks.connect(self.onAutoLayoutTextblks)
        self.txtblkShapeControl = canvas.txtblkShapeControl
@@ -383,6 +405,53 @@ class SceneTextManager(QObject):
        if len(selected_blks) > 0:
            self.canvas.push_undo_command(DeleteBlkItemsCommand(selected_blks, self))

    def onCopyBlkItems(self, pos: QPointF):
        selected_blks = self.get_selected_blkitems()
        if len(selected_blks) == 0 and self.txtblkShapeControl.blk_item is not None:
            selected_blks.append(self.txtblkShapeControl.blk_item)

        if len(selected_blks) == 0:            
            return

        self.canvas.clipboard_blks.clear()
        if self.canvas.text_change_unsaved():
            self.updateTextBlkList()

        if pos is None:
            pos = selected_blks[0].blk.xyxy
            pos_x, pos_y = pos[0], pos[1]
        else:
            pos_x, pos_y = pos.x(), pos.y()
            pos_x = int(pos_x / self.canvas.scale_factor)
            pos_y = int(pos_y / self.canvas.scale_factor)

        for blkitems in selected_blks:
            blk = copy.deepcopy(blkitems.blk)
            blk.adjust_pos(-pos_x, -pos_y)
            self.canvas.clipboard_blks.append(blk)


    def onPasteBlkItems(self, pos: QPointF):
        if pos is None:
            pos_x, pos_y = 0, 0
        else:
            pos_x, pos_y = pos.x(), pos.y()
            pos_x = int(pos_x / self.canvas.scale_factor)
            pos_y = int(pos_y / self.canvas.scale_factor)
        blkitem_list, pair_widget_list = [], []
        for blk in self.canvas.clipboard_blks:
            blk = copy.deepcopy(blk)
            blk.adjust_pos(pos_x, pos_y)
            blkitem = self.addTextBlock(blk)
            pairw = self.pairwidget_list[-1]
            blkitem_list.append(blkitem)
            pair_widget_list.append(pairw)
        if len(blkitem_list) > 0:
            self.canvas.clearSelection()

            self.canvas.push_undo_command(PasteBlkItemsCommand(blkitem_list, pair_widget_list, self))
        pass

    def onFormatTextblks(self):
        self.apply_fontformat(self.formatpanel.global_format)