mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Image cropping
This commit is contained in:
parent
235b03951b
commit
3345efaacf
19 changed files with 1687 additions and 636 deletions
|
|
@ -4,6 +4,8 @@
|
|||
Added
|
||||
-----
|
||||
|
||||
* Image cropping (Go to "Transform -> Crop", or press Shift + C)
|
||||
Note that older version of BeeRef will display the images uncropped.
|
||||
* Show list of recent files on welcome screen
|
||||
* Keyboard shortcuts can now be configured via a settings file.
|
||||
Go to "Settings -> Open Settings Folder" and edit KeyboardSettings.ini
|
||||
|
|
|
|||
|
|
@ -145,6 +145,13 @@ actions = [
|
|||
'callback': 'on_action_arrange_vertical',
|
||||
'group': 'active_when_selection',
|
||||
},
|
||||
{
|
||||
'id': 'crop',
|
||||
'text': '&Crop',
|
||||
'shortcuts': ['Shift+C'],
|
||||
'callback': 'on_action_crop',
|
||||
'group': 'active_when_croppable',
|
||||
},
|
||||
{
|
||||
'id': 'flip_horizontally',
|
||||
'text': 'Flip &Horizontally',
|
||||
|
|
@ -196,6 +203,12 @@ actions = [
|
|||
'callback': 'on_action_reset_flip',
|
||||
'group': 'active_when_selection',
|
||||
},
|
||||
{
|
||||
'id': 'reset_crop',
|
||||
'text': 'Reset Cro&p',
|
||||
'callback': 'on_action_reset_crop',
|
||||
'group': 'active_when_selection',
|
||||
},
|
||||
{
|
||||
'id': 'reset_transforms',
|
||||
'text': 'Reset &All',
|
||||
|
|
|
|||
|
|
@ -73,12 +73,14 @@ menu_structure = [
|
|||
{
|
||||
'menu': '&Transform',
|
||||
'items': [
|
||||
'crop',
|
||||
'flip_horizontally',
|
||||
'flip_vertically',
|
||||
MENU_SEPARATOR,
|
||||
'reset_scale',
|
||||
'reset_rotation',
|
||||
'reset_flip',
|
||||
'reset_crop',
|
||||
'reset_transforms',
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -32,10 +32,9 @@ class InsertItems(QtGui.QUndoCommand):
|
|||
return
|
||||
if self.position:
|
||||
rect = self.scene.itemsBoundingRect(items=self.items)
|
||||
center = (rect.topLeft() + rect.bottomRight()) / 2
|
||||
for item in self.items:
|
||||
self.old_positions.append(item.pos())
|
||||
item.setPos(item.pos() + self.position - center)
|
||||
item.setPos(item.pos() + self.position - rect.center())
|
||||
self.scene.clearSelection()
|
||||
for item in self.items:
|
||||
self.scene.addItem(item)
|
||||
|
|
@ -148,13 +147,11 @@ class NormalizeItems(QtGui.QUndoCommand):
|
|||
self.old_scale_factors = []
|
||||
for item, factor in zip(self.items, self.scale_factors):
|
||||
self.old_scale_factors.append(item.scale())
|
||||
item.setScale(item.scale() * factor,
|
||||
QtCore.QPointF(item.width, item.height) / 2)
|
||||
item.setScale(item.scale() * factor, item.center)
|
||||
|
||||
def undo(self):
|
||||
for item, factor in zip(self.items, self.old_scale_factors):
|
||||
item.setScale(factor,
|
||||
QtCore.QPointF(item.width, item.height) / 2)
|
||||
item.setScale(factor, item.center)
|
||||
|
||||
|
||||
class FlipItems(QtGui.QUndoCommand):
|
||||
|
|
@ -226,6 +223,23 @@ class ResetFlip(QtGui.QUndoCommand):
|
|||
item.do_flip(anchor=item.center)
|
||||
|
||||
|
||||
class ResetCrop(QtGui.QUndoCommand):
|
||||
|
||||
def __init__(self, items):
|
||||
super().__init__('Reset Crop')
|
||||
self.items = [item for item in items if item.is_croppable]
|
||||
|
||||
def redo(self):
|
||||
self.old_crops = []
|
||||
for item in self.items:
|
||||
self.old_crops.append(item.crop)
|
||||
item.reset_crop()
|
||||
|
||||
def undo(self):
|
||||
for item, crop in zip(self.items, self.old_crops):
|
||||
item.crop = crop
|
||||
|
||||
|
||||
class ResetTransforms(QtGui.QUndoCommand):
|
||||
|
||||
def __init__(self, items):
|
||||
|
|
@ -235,11 +249,15 @@ class ResetTransforms(QtGui.QUndoCommand):
|
|||
def redo(self):
|
||||
self.old_values = []
|
||||
for item in self.items:
|
||||
self.old_values.append({
|
||||
values = {
|
||||
'scale': item.scale(),
|
||||
'rotation': item.rotation(),
|
||||
'flip': item.flip(),
|
||||
})
|
||||
}
|
||||
if item.is_croppable:
|
||||
values['crop'] = item.crop
|
||||
item.reset_crop()
|
||||
self.old_values.append(values)
|
||||
|
||||
item.setScale(1, anchor=item.center)
|
||||
item.setRotation(0, anchor=item.center)
|
||||
|
|
@ -252,6 +270,8 @@ class ResetTransforms(QtGui.QUndoCommand):
|
|||
item.setRotation(old['rotation'], anchor=item.center)
|
||||
if old['flip'] == -1:
|
||||
item.do_flip(anchor=item.center)
|
||||
if item.is_croppable:
|
||||
item.crop = old['crop']
|
||||
|
||||
|
||||
class ArrangeItems(QtGui.QUndoCommand):
|
||||
|
|
@ -266,7 +286,7 @@ class ArrangeItems(QtGui.QUndoCommand):
|
|||
self.old_positions = []
|
||||
for item, pos in zip(self.items, self.positions):
|
||||
self.old_positions.append(item.pos())
|
||||
orig_topleft = item.corners_scene_coords[0]
|
||||
orig_topleft = item.mapToScene(QtCore.QPointF(0, 0))
|
||||
rect_topleft = self.scene.itemsBoundingRect(
|
||||
items=[item]).topLeft()
|
||||
item.setPos(pos + orig_topleft - rect_topleft)
|
||||
|
|
@ -274,3 +294,17 @@ class ArrangeItems(QtGui.QUndoCommand):
|
|||
def undo(self):
|
||||
for item, pos in zip(self.items, self.old_positions):
|
||||
item.setPos(pos)
|
||||
|
||||
|
||||
class CropItem(QtGui.QUndoCommand):
|
||||
def __init__(self, item, crop):
|
||||
super().__init__('Crop item')
|
||||
self.item = item
|
||||
self.crop = crop
|
||||
|
||||
def redo(self):
|
||||
self.old_crop = self.item.crop
|
||||
self.item.crop = self.crop
|
||||
|
||||
def undo(self):
|
||||
self.item.crop = self.old_crop
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ class SQLiteIO:
|
|||
}
|
||||
|
||||
if data['type'] == 'pixmap':
|
||||
data['item'] = BeePixmapItem(QtGui.QImage(), **data['data'])
|
||||
data['item'] = BeePixmapItem(QtGui.QImage())
|
||||
data['item'].pixmap_from_bytes(row[9])
|
||||
|
||||
self.scene.add_item_later(data)
|
||||
|
|
|
|||
241
beeref/items.py
241
beeref/items.py
|
|
@ -22,6 +22,7 @@ import logging
|
|||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref import commands
|
||||
from beeref.constants import COLORS
|
||||
from beeref.selection import SelectableMixin
|
||||
|
||||
|
|
@ -79,12 +80,16 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
"""Class for images added by the user."""
|
||||
|
||||
TYPE = 'pixmap'
|
||||
CROP_HANDLE_SIZE = 15
|
||||
|
||||
def __init__(self, image, filename=None):
|
||||
super().__init__(QtGui.QPixmap.fromImage(image))
|
||||
self.save_id = None
|
||||
self.filename = filename
|
||||
self.reset_crop()
|
||||
logger.debug(f'Initialized {self}')
|
||||
self.is_croppable = True
|
||||
self.crop_mode = False
|
||||
self.init_selectable()
|
||||
|
||||
@classmethod
|
||||
|
|
@ -92,21 +97,37 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
item = kwargs.pop('item')
|
||||
data = kwargs.pop('data', {})
|
||||
item.filename = item.filename or data.get('filename')
|
||||
if 'crop' in data:
|
||||
item.crop = QtCore.QRectF(*data['crop'])
|
||||
return item
|
||||
|
||||
def __str__(self):
|
||||
return (f'Image "{self.filename}" {self.width} x {self.height}')
|
||||
size = self.pixmap().size()
|
||||
return (f'Image "{self.filename}" {size.width()} x {size.height()}')
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.pixmap().size().width()
|
||||
def crop(self):
|
||||
return self._crop
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.pixmap().size().height()
|
||||
@crop.setter
|
||||
def crop(self, value):
|
||||
logger.debug(f'Setting crop for {self} to {value}')
|
||||
self.prepareGeometryChange()
|
||||
self._crop = value
|
||||
self.update()
|
||||
|
||||
def bounding_rect_unselected(self):
|
||||
if self.crop_mode:
|
||||
return QtWidgets.QGraphicsPixmapItem.boundingRect(self)
|
||||
else:
|
||||
return self.crop
|
||||
|
||||
def get_extra_save_data(self):
|
||||
return {'filename': self.filename}
|
||||
return {'filename': self.filename,
|
||||
'crop': [self.crop.topLeft().x(),
|
||||
self.crop.topLeft().y(),
|
||||
self.crop.width(),
|
||||
self.crop.height()]}
|
||||
|
||||
def pixmap_to_bytes(self):
|
||||
"""Convert the pixmap data to PNG bytestring."""
|
||||
|
|
@ -117,16 +138,16 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
img.save(buffer, 'PNG')
|
||||
return barray.data()
|
||||
|
||||
def setPixmap(self, pixmap):
|
||||
super().setPixmap(pixmap)
|
||||
self.reset_crop()
|
||||
|
||||
def pixmap_from_bytes(self, data):
|
||||
"""Set image pimap from a bytestring."""
|
||||
pixmap = QtGui.QPixmap()
|
||||
pixmap.loadFromData(data)
|
||||
self.setPixmap(pixmap)
|
||||
|
||||
def paint(self, painter, option, widget):
|
||||
painter.drawPixmap(0, 0, self.pixmap())
|
||||
self.paint_selectable(painter, option, widget)
|
||||
|
||||
def create_copy(self):
|
||||
item = BeePixmapItem(QtGui.QImage(), self.filename)
|
||||
item.setPixmap(self.pixmap())
|
||||
|
|
@ -136,11 +157,196 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
item.setRotation(self.rotation())
|
||||
if self.flip() == -1:
|
||||
item.do_flip()
|
||||
item.crop = self.crop
|
||||
return item
|
||||
|
||||
def copy_to_clipboard(self, clipboard):
|
||||
clipboard.setPixmap(self.pixmap())
|
||||
|
||||
def reset_crop(self):
|
||||
self.crop = QtCore.QRectF(
|
||||
0, 0, self.pixmap().size().width(), self.pixmap().size().height())
|
||||
|
||||
@property
|
||||
def crop_handle_size(self):
|
||||
return self.fixed_length_for_viewport(self.CROP_HANDLE_SIZE)
|
||||
|
||||
def crop_handle_topleft(self):
|
||||
topleft = self.crop_temp.topLeft()
|
||||
return QtCore.QRectF(
|
||||
topleft.x(),
|
||||
topleft.y(),
|
||||
self.crop_handle_size,
|
||||
self.crop_handle_size)
|
||||
|
||||
def crop_handle_bottomleft(self):
|
||||
bottomleft = self.crop_temp.bottomLeft()
|
||||
return QtCore.QRectF(
|
||||
bottomleft.x(),
|
||||
bottomleft.y() - self.crop_handle_size,
|
||||
self.crop_handle_size,
|
||||
self.crop_handle_size)
|
||||
|
||||
def crop_handle_bottomright(self):
|
||||
bottomright = self.crop_temp.bottomRight()
|
||||
return QtCore.QRectF(
|
||||
bottomright.x() - self.crop_handle_size,
|
||||
bottomright.y() - self.crop_handle_size,
|
||||
self.crop_handle_size,
|
||||
self.crop_handle_size)
|
||||
|
||||
def crop_handle_topright(self):
|
||||
topright = self.crop_temp.topRight()
|
||||
return QtCore.QRectF(
|
||||
topright.x() - self.crop_handle_size,
|
||||
topright.y(),
|
||||
self.crop_handle_size,
|
||||
self.crop_handle_size)
|
||||
|
||||
def crop_handles(self):
|
||||
return (self.crop_handle_topleft,
|
||||
self.crop_handle_bottomleft,
|
||||
self.crop_handle_bottomright,
|
||||
self.crop_handle_topright)
|
||||
|
||||
def get_crop_handle_cursor(self, handle):
|
||||
"""Gets the crop cursor for the given handle."""
|
||||
|
||||
is_topleft_or_bottomright = handle in (
|
||||
self.crop_handle_topleft, self.crop_handle_bottomright)
|
||||
return self.get_diag_cursor(is_topleft_or_bottomright)
|
||||
|
||||
def draw_crop_rect(self, painter, rect):
|
||||
"""Paint a dotted rectangle for the cropping UI."""
|
||||
pen = QtGui.QPen(QtGui.QColor(255, 255, 255))
|
||||
pen.setWidth(2)
|
||||
pen.setCosmetic(True)
|
||||
painter.setPen(pen)
|
||||
painter.drawRect(rect)
|
||||
pen.setColor(QtGui.QColor(0, 0, 0))
|
||||
pen.setStyle(Qt.PenStyle.DotLine)
|
||||
painter.setPen(pen)
|
||||
painter.drawRect(rect)
|
||||
|
||||
def paint(self, painter, option, widget):
|
||||
if self.crop_mode:
|
||||
self.paint_debug(painter, option, widget)
|
||||
|
||||
# Darken image outside of cropped area
|
||||
painter.drawPixmap(0, 0, self.pixmap())
|
||||
path = QtWidgets.QGraphicsPixmapItem.shape(self)
|
||||
path.addRect(self.crop_temp)
|
||||
color = QtGui.QColor(0, 0, 0)
|
||||
color.setAlpha(100)
|
||||
painter.setBrush(QtGui.QBrush(color))
|
||||
painter.setPen(QtGui.QPen())
|
||||
painter.drawPath(path)
|
||||
painter.setBrush(QtGui.QBrush())
|
||||
|
||||
for handle in self.crop_handles():
|
||||
self.draw_crop_rect(painter, handle())
|
||||
self.draw_crop_rect(painter, self.crop_temp)
|
||||
else:
|
||||
painter.drawPixmap(self.crop, self.pixmap(), self.crop)
|
||||
self.paint_selectable(painter, option, widget)
|
||||
|
||||
def enter_crop_mode(self):
|
||||
logger.debug(f'Entering crop mode on {self}')
|
||||
self.prepareGeometryChange()
|
||||
self.crop_mode = True
|
||||
self.crop_temp = QtCore.QRectF(self.crop)
|
||||
self.crop_mode_move = None
|
||||
self.crop_mode_event_start = None
|
||||
self.grabKeyboard()
|
||||
self.update()
|
||||
self.scene().crop_item = self
|
||||
|
||||
def exit_crop_mode(self, confirm):
|
||||
logger.debug(f'Exiting crop mode with {confirm} on {self}')
|
||||
if confirm and self.crop != self.crop_temp:
|
||||
self.scene().undo_stack.push(
|
||||
commands.CropItem(self, self.crop_temp))
|
||||
self.prepareGeometryChange()
|
||||
self.crop_mode = False
|
||||
self.crop_temp = None
|
||||
self.crop_mode_move = None
|
||||
self.crop_mode_event_start = None
|
||||
self.ungrabKeyboard()
|
||||
self.update()
|
||||
self.scene().crop_item = None
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
||||
self.exit_crop_mode(confirm=True)
|
||||
elif event.key() == Qt.Key.Key_Escape:
|
||||
self.exit_crop_mode(confirm=False)
|
||||
else:
|
||||
super().keyPressEvent(event)
|
||||
|
||||
def hoverMoveEvent(self, event):
|
||||
if not self.crop_mode:
|
||||
return super().hoverMoveEvent(event)
|
||||
|
||||
for handle in self.crop_handles():
|
||||
if handle().contains(event.pos()):
|
||||
self.setCursor(self.get_crop_handle_cursor(handle))
|
||||
return
|
||||
self.setCursor(Qt.CursorShape.ArrowCursor)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if not self.crop_mode:
|
||||
return super().mousePressEvent(event)
|
||||
|
||||
event.accept()
|
||||
for handle in self.crop_handles():
|
||||
# Click into a handle?
|
||||
if handle().contains(event.pos()):
|
||||
self.crop_mode_event_start = event.pos()
|
||||
self.crop_mode_move = handle
|
||||
return
|
||||
# Click not in handle, end cropping mode:
|
||||
self.exit_crop_mode(
|
||||
confirm=self.crop_temp.contains(event.pos()))
|
||||
|
||||
def ensure_point_within_pixmap_bounds(self, point):
|
||||
"""Returns the point, or the nearest point within the pixmap."""
|
||||
point.setX(min(self.pixmap().size().width(), max(0, point.x())))
|
||||
point.setY(min(self.pixmap().size().height(), max(0, point.y())))
|
||||
return point
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self.crop_mode:
|
||||
diff = event.pos() - self.crop_mode_event_start
|
||||
if self.crop_mode_move == self.crop_handle_topleft:
|
||||
new = self.ensure_point_within_pixmap_bounds(
|
||||
self.crop_temp.topLeft() + diff)
|
||||
self.crop_temp.setTopLeft(new)
|
||||
if self.crop_mode_move == self.crop_handle_bottomleft:
|
||||
new = self.ensure_point_within_pixmap_bounds(
|
||||
self.crop_temp.bottomLeft() + diff)
|
||||
self.crop_temp.setBottomLeft(new)
|
||||
if self.crop_mode_move == self.crop_handle_bottomright:
|
||||
new = self.ensure_point_within_pixmap_bounds(
|
||||
self.crop_temp.bottomRight() + diff)
|
||||
self.crop_temp.setBottomRight(new)
|
||||
if self.crop_mode_move == self.crop_handle_topright:
|
||||
new = self.ensure_point_within_pixmap_bounds(
|
||||
self.crop_temp.topRight() + diff)
|
||||
self.crop_temp.setTopRight(new)
|
||||
self.update()
|
||||
self.crop_mode_event_start = event.pos()
|
||||
event.accept()
|
||||
else:
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
if self.crop_mode:
|
||||
self.crop_mode_move = None
|
||||
self.crop_mode_event_start = None
|
||||
event.accept()
|
||||
else:
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
|
||||
@register_item
|
||||
class BeeTextItem(BeeItemMixin, QtWidgets.QGraphicsTextItem):
|
||||
|
|
@ -152,6 +358,7 @@ class BeeTextItem(BeeItemMixin, QtWidgets.QGraphicsTextItem):
|
|||
super().__init__(text or "Text")
|
||||
self.save_id = None
|
||||
logger.debug(f'Initialized {self}')
|
||||
self.is_croppable = False
|
||||
self.init_selectable()
|
||||
self.is_editable = True
|
||||
self.edit_mode = False
|
||||
|
|
@ -167,14 +374,6 @@ class BeeTextItem(BeeItemMixin, QtWidgets.QGraphicsTextItem):
|
|||
txt = self.toPlainText()[:40]
|
||||
return (f'Text "{txt}"')
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return QtWidgets.QGraphicsTextItem.boundingRect(self).width()
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return QtWidgets.QGraphicsTextItem.boundingRect(self).height()
|
||||
|
||||
def get_extra_save_data(self):
|
||||
return {'text': self.toPlainText()}
|
||||
|
||||
|
|
@ -203,15 +402,19 @@ class BeeTextItem(BeeItemMixin, QtWidgets.QGraphicsTextItem):
|
|||
return item
|
||||
|
||||
def enter_edit_mode(self):
|
||||
logger.debug(f'Entering edit mode on {self}')
|
||||
self.edit_mode = True
|
||||
self.setTextInteractionFlags(
|
||||
Qt.TextInteractionFlag.TextEditorInteraction)
|
||||
self.scene().edit_item = self
|
||||
|
||||
def exit_edit_mode(self):
|
||||
logger.debug(f'Exiting edit mode on {self}')
|
||||
self.edit_mode = False
|
||||
# reset selection:
|
||||
self.setTextCursor(QtGui.QTextCursor(self.document()))
|
||||
self.setTextInteractionFlags(Qt.TextInteractionFlag.NoTextInteraction)
|
||||
self.scene().edit_item = None
|
||||
|
||||
def has_selection_handles(self):
|
||||
return super().has_selection_handles() and not self.edit_mode
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
self.items_to_add = Queue()
|
||||
self.internal_clipboard = []
|
||||
self.edit_item = None
|
||||
self.crop_item = None
|
||||
|
||||
def addItem(self, item):
|
||||
logger.debug(f'Adding item {item}')
|
||||
|
|
@ -56,6 +57,11 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
logger.debug(f'Removing item {item}')
|
||||
super().removeItem(item)
|
||||
|
||||
def cancel_crop_mode(self):
|
||||
"""Cancels an ongoing crop mode, if there is any."""
|
||||
if self.crop_item:
|
||||
self.crop_item.exit_crop_mode(confirm=False)
|
||||
|
||||
def copy_selection_to_internal_clipboard(self):
|
||||
self.internal_clipboard = []
|
||||
for item in self.selectedItems(user_only=True):
|
||||
|
|
@ -70,6 +76,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
self.undo_stack.push(commands.InsertItems(self, copies, position))
|
||||
|
||||
def raise_to_top(self):
|
||||
self.cancel_crop_mode()
|
||||
items = self.selectedItems(user_only=True)
|
||||
z_values = map(lambda i: i.zValue(), items)
|
||||
delta = self.max_z + self.Z_STEP - min(z_values)
|
||||
|
|
@ -78,6 +85,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
item.setZValue(item.zValue() + delta)
|
||||
|
||||
def lower_to_bottom(self):
|
||||
self.cancel_crop_mode()
|
||||
items = self.selectedItems(user_only=True)
|
||||
z_values = map(lambda i: i.zValue(), items)
|
||||
delta = self.min_z - self.Z_STEP - max(z_values)
|
||||
|
|
@ -93,6 +101,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
:param mode: "width" or "height".
|
||||
"""
|
||||
|
||||
self.cancel_crop_mode()
|
||||
values = []
|
||||
items = self.selectedItems(user_only=True)
|
||||
for item in items:
|
||||
|
|
@ -124,6 +133,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
Size meaning the area = widh * height.
|
||||
"""
|
||||
|
||||
self.cancel_crop_mode()
|
||||
sizes = []
|
||||
items = self.selectedItems(user_only=True)
|
||||
for item in items:
|
||||
|
|
@ -146,6 +156,8 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
def arrange(self, vertical=False):
|
||||
"""Arrange items in a line (horizontally or vertically)."""
|
||||
|
||||
self.cancel_crop_mode()
|
||||
|
||||
items = self.selectedItems(user_only=True)
|
||||
if len(items) < 2:
|
||||
return
|
||||
|
|
@ -184,6 +196,8 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
positions))
|
||||
|
||||
def arrange_optimal(self):
|
||||
self.cancel_crop_mode()
|
||||
|
||||
items = self.selectedItems(user_only=True)
|
||||
if len(items) < 2:
|
||||
return
|
||||
|
|
@ -218,13 +232,25 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
|
||||
def flip_items(self, vertical=False):
|
||||
"""Flip selected items."""
|
||||
self.cancel_crop_mode()
|
||||
self.undo_stack.push(
|
||||
commands.FlipItems(self.selectedItems(user_only=True),
|
||||
self.get_selection_center(),
|
||||
vertical=vertical))
|
||||
|
||||
def crop_items(self):
|
||||
"""Crop selected item."""
|
||||
|
||||
if self.crop_item:
|
||||
return
|
||||
if self.has_croppable_selection():
|
||||
item = self.selectedItems(user_only=True)[0]
|
||||
if item.is_croppable:
|
||||
item.enter_crop_mode()
|
||||
|
||||
def set_selected_all_items(self, value):
|
||||
"""Sets the selection mode of all items to ``value``."""
|
||||
self.cancel_crop_mode()
|
||||
for item in self.items():
|
||||
item.setSelected(value)
|
||||
|
||||
|
|
@ -243,6 +269,14 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
|
||||
return len(self.selectedItems(user_only=True)) > 1
|
||||
|
||||
def has_croppable_selection(self):
|
||||
"""Checks whether the current selection is croppable, i.e. a
|
||||
single selection whose item is croppable."""
|
||||
|
||||
if self.has_single_selection():
|
||||
return self.selectedItems(user_only=True)[0].is_croppable
|
||||
return False
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.MouseButton.RightButton:
|
||||
# Right-click invokes the context menu on the
|
||||
|
|
@ -257,7 +291,12 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
if self.edit_item:
|
||||
if item_at_pos != self.edit_item:
|
||||
self.edit_item.exit_edit_mode()
|
||||
self.edit_item = None
|
||||
else:
|
||||
super().mousePressEvent(event)
|
||||
return
|
||||
if self.crop_item:
|
||||
if item_at_pos != self.crop_item:
|
||||
self.cancel_crop_mode()
|
||||
else:
|
||||
super().mousePressEvent(event)
|
||||
return
|
||||
|
|
@ -275,7 +314,6 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
if not item.isSelected():
|
||||
item.setSelected(True)
|
||||
if item.is_editable:
|
||||
self.edit_item = item
|
||||
item.enter_edit_mode()
|
||||
self.mousePressEvent(event)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with BeeRef. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""Classes for items that draw and handle selection stuff."""
|
||||
"""Classes that draw and handle selection stuff for items."""
|
||||
|
||||
import logging
|
||||
import math
|
||||
|
|
@ -98,9 +98,20 @@ class BaseItemMixin:
|
|||
if vertical:
|
||||
self.setRotation(self.rotation() + 180)
|
||||
|
||||
def bounding_rect_unselected(self):
|
||||
return super().boundingRect()
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.bounding_rect_unselected().width()
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.bounding_rect_unselected().height()
|
||||
|
||||
@property
|
||||
def center(self):
|
||||
return QtCore.QPointF(self.width, self.height) / 2
|
||||
return self.bounding_rect_unselected().center()
|
||||
|
||||
@property
|
||||
def center_scene_coords(self):
|
||||
|
|
@ -166,7 +177,7 @@ class SelectableMixin(BaseItemMixin):
|
|||
else:
|
||||
painter.fillPath(shape, color)
|
||||
|
||||
def paint_selectable(self, painter, option, widget):
|
||||
def paint_debug(self, painter, option, widget):
|
||||
if commandline_args.debug_shapes:
|
||||
self.draw_debug_shape(painter, self.shape(), 255, 0, 0)
|
||||
if commandline_args.debug_boundingrects:
|
||||
|
|
@ -180,6 +191,9 @@ class SelectableMixin(BaseItemMixin):
|
|||
for edge in self.get_flip_bounds():
|
||||
self.draw_debug_shape(painter, edge['rect'], 255, 255, 0)
|
||||
|
||||
def paint_selectable(self, painter, option, widget):
|
||||
self.paint_debug(painter, option, widget)
|
||||
|
||||
if not self.has_selection_outline():
|
||||
return
|
||||
|
||||
|
|
@ -189,7 +203,7 @@ class SelectableMixin(BaseItemMixin):
|
|||
painter.setPen(pen)
|
||||
|
||||
# Draw the main selection rectangle
|
||||
painter.drawRect(0, 0, self.width, self.height)
|
||||
painter.drawRect(self.bounding_rect_unselected())
|
||||
|
||||
# If it's a single selection, draw the handles:
|
||||
if self.has_selection_handles():
|
||||
|
|
@ -202,10 +216,10 @@ class SelectableMixin(BaseItemMixin):
|
|||
@property
|
||||
def corners(self):
|
||||
"""The corners of the item. Used for scale and rotate handles."""
|
||||
return (QtCore.QPointF(0, 0),
|
||||
QtCore.QPointF(self.width, 0),
|
||||
QtCore.QPointF(self.width, self.height),
|
||||
QtCore.QPointF(0, self.height))
|
||||
return (self.bounding_rect_unselected().topLeft(),
|
||||
self.bounding_rect_unselected().topRight(),
|
||||
self.bounding_rect_unselected().bottomRight(),
|
||||
self.bounding_rect_unselected().bottomLeft())
|
||||
|
||||
@property
|
||||
def corners_scene_coords(self):
|
||||
|
|
@ -264,65 +278,66 @@ class SelectableMixin(BaseItemMixin):
|
|||
|
||||
outer_margin = self.select_resize_size / 2
|
||||
inner_margin = self.select_resize_size / 2
|
||||
origin = self.bounding_rect_unselected().topLeft()
|
||||
return [
|
||||
# top:
|
||||
{
|
||||
'rect': QtCore.QRectF(inner_margin,
|
||||
-outer_margin,
|
||||
self.width - 2 * inner_margin,
|
||||
outer_margin + inner_margin),
|
||||
'rect': QtCore.QRectF(
|
||||
origin.x() + inner_margin,
|
||||
origin.y() - outer_margin,
|
||||
self.width - 2 * inner_margin,
|
||||
outer_margin + inner_margin),
|
||||
'flip_v': True,
|
||||
},
|
||||
# bottom:
|
||||
{
|
||||
'rect': QtCore.QRectF(inner_margin,
|
||||
self.height - inner_margin,
|
||||
self.width - 2 * inner_margin,
|
||||
outer_margin + inner_margin),
|
||||
'rect': QtCore.QRectF(
|
||||
origin.x() + inner_margin,
|
||||
origin.y() + self.height - inner_margin,
|
||||
self.width - 2 * inner_margin,
|
||||
outer_margin + inner_margin),
|
||||
'flip_v': True,
|
||||
},
|
||||
# left:
|
||||
{
|
||||
'rect': QtCore.QRectF(-outer_margin,
|
||||
inner_margin,
|
||||
outer_margin + inner_margin,
|
||||
self.height - 2 * inner_margin),
|
||||
'rect': QtCore.QRectF(
|
||||
origin.x() - outer_margin,
|
||||
origin.y() + inner_margin,
|
||||
outer_margin + inner_margin,
|
||||
self.height - 2 * inner_margin),
|
||||
'flip_v': False,
|
||||
},
|
||||
# right:
|
||||
{
|
||||
'rect': QtCore.QRectF(self.width - inner_margin,
|
||||
inner_margin,
|
||||
outer_margin + inner_margin,
|
||||
self.height - 2 * inner_margin),
|
||||
'rect': QtCore.QRectF(
|
||||
origin.x() + self.width - inner_margin,
|
||||
origin.y() + inner_margin,
|
||||
outer_margin + inner_margin,
|
||||
self.height - 2 * inner_margin),
|
||||
'flip_v': False,
|
||||
}
|
||||
]
|
||||
|
||||
def boundingRect(self):
|
||||
if not self.has_selection_outline():
|
||||
return super().boundingRect()
|
||||
return self.bounding_rect_unselected()
|
||||
|
||||
# Add extra space for the interactive areas
|
||||
margin = self.select_resize_size / 2 + self.select_rotate_size
|
||||
return QtCore.QRectF(
|
||||
-margin, -margin,
|
||||
self.width + 2 * margin,
|
||||
self.height + 2 * margin)
|
||||
return self.bounding_rect_unselected().marginsAdded(
|
||||
QtCore.QMarginsF(margin, margin, margin, margin))
|
||||
|
||||
def shape(self):
|
||||
path = QtGui.QPainterPath()
|
||||
if self.has_selection_handles():
|
||||
margin = self.select_resize_size / 2
|
||||
rect = QtCore.QRectF(
|
||||
-margin, -margin,
|
||||
self.width + 2 * margin,
|
||||
self.height + 2 * margin)
|
||||
rect = self.bounding_rect_unselected().marginsAdded(
|
||||
QtCore.QMarginsF(margin, margin, margin, margin))
|
||||
path.addRect(rect)
|
||||
for corner in self.corners:
|
||||
path.addPath(self.get_rotate_bounds(corner))
|
||||
else:
|
||||
rect = super().boundingRect()
|
||||
rect = self.bounding_rect_unselected()
|
||||
path.addRect(rect)
|
||||
return path
|
||||
|
||||
|
|
@ -408,14 +423,15 @@ class SelectableMixin(BaseItemMixin):
|
|||
|
||||
def get_scale_anchor(self, corner):
|
||||
"""Get the anchor around which the scale for this corner operates."""
|
||||
return QtCore.QPointF(self.width - corner.x(),
|
||||
self.height - corner.y())
|
||||
origin = self.bounding_rect_unselected().topLeft()
|
||||
return QtCore.QPointF(self.width - corner.x() + 2*origin.x(),
|
||||
self.height - corner.y() + 2*origin.y())
|
||||
|
||||
def get_corner_direction(self, corner):
|
||||
"""Get the direction facing away from the center, e.g. the direction
|
||||
in which the scale for this corner increases."""
|
||||
return QtCore.QPointF(1 if corner.x() > 0 else -1,
|
||||
1 if corner.y() > 0 else -1)
|
||||
return QtCore.QPointF(1 if corner.x() > self.center.x() else -1,
|
||||
1 if corner.y() > self.center.y() else -1)
|
||||
|
||||
def get_direction_from_center(self, pos):
|
||||
"""The direction of a point in relation to the item's center."""
|
||||
|
|
@ -444,11 +460,16 @@ class SelectableMixin(BaseItemMixin):
|
|||
def get_corner_scale_cursor(self, corner):
|
||||
"""Gets the scale cursor for the given corner."""
|
||||
|
||||
is_topleft_or_bottomright = corner in (
|
||||
self.bounding_rect_unselected().topLeft(),
|
||||
self.bounding_rect_unselected().bottomRight())
|
||||
return self.get_diag_cursor(is_topleft_or_bottomright)
|
||||
|
||||
def get_diag_cursor(self, is_topleft_or_bottomright):
|
||||
rotation = self.rotation() % 180
|
||||
flipped = self.flip() == -1
|
||||
|
||||
if corner in (QtCore.QPointF(0, 0),
|
||||
QtCore.QPointF(self.width, self.height)):
|
||||
if is_topleft_or_bottomright:
|
||||
if 22.5 < rotation < 67.5:
|
||||
return Qt.CursorShape.SizeVerCursor
|
||||
elif 67.5 < rotation < 112.5:
|
||||
|
|
@ -571,14 +592,6 @@ class MultiSelectItem(SelectableMixin,
|
|||
def __str__(self):
|
||||
return (f'MultiSelectItem {self.width} x {self.height}')
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.rect().width()
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.rect().height()
|
||||
|
||||
def paint(self, painter, option, widget):
|
||||
self.paint_selectable(painter, option, widget)
|
||||
|
||||
|
|
@ -641,14 +654,6 @@ class RubberbandItem(BaseItemMixin, QtWidgets.QGraphicsRectItem):
|
|||
def __str__(self):
|
||||
return (f'RubberbandItem {self.width} x {self.height}')
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.rect().width()
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.rect().height()
|
||||
|
||||
def fit(self, point1, point2):
|
||||
"""Updates itself to fit the two given points."""
|
||||
|
||||
|
|
|
|||
|
|
@ -215,10 +215,12 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
|
||||
def on_action_undo(self):
|
||||
logger.debug('Undo: %s' % self.undo_stack.undoText())
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.undo()
|
||||
|
||||
def on_action_redo(self):
|
||||
logger.debug('Redo: %s' % self.undo_stack.redoText())
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.redo()
|
||||
|
||||
def on_action_select_all(self):
|
||||
|
|
@ -229,6 +231,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
|
||||
def on_action_delete_items(self):
|
||||
logger.debug('Deleting items...')
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.push(
|
||||
commands.DeleteItems(
|
||||
self.scene, self.scene.selectedItems(user_only=True)))
|
||||
|
|
@ -264,6 +267,9 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
def on_action_arrange_optimal(self):
|
||||
self.scene.arrange_optimal()
|
||||
|
||||
def on_action_crop(self):
|
||||
self.scene.crop_items()
|
||||
|
||||
def on_action_flip_horizontally(self):
|
||||
self.scene.flip_items(vertical=False)
|
||||
|
||||
|
|
@ -271,18 +277,27 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.scene.flip_items(vertical=True)
|
||||
|
||||
def on_action_reset_scale(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.push(commands.ResetScale(
|
||||
self.scene.selectedItems(user_only=True)))
|
||||
|
||||
def on_action_reset_rotation(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.push(commands.ResetRotation(
|
||||
self.scene.selectedItems(user_only=True)))
|
||||
|
||||
def on_action_reset_flip(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.push(commands.ResetFlip(
|
||||
self.scene.selectedItems(user_only=True)))
|
||||
|
||||
def on_action_reset_crop(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.push(commands.ResetCrop(
|
||||
self.scene.selectedItems(user_only=True)))
|
||||
|
||||
def on_action_reset_transforms(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
self.undo_stack.push(commands.ResetTransforms(
|
||||
self.scene.selectedItems(user_only=True)))
|
||||
|
||||
|
|
@ -316,6 +331,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.worker.start()
|
||||
|
||||
def on_action_open(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
filename, f = QtWidgets.QFileDialog.getOpenFileName(
|
||||
parent=self,
|
||||
caption='Open file',
|
||||
|
|
@ -349,6 +365,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.worker.start()
|
||||
|
||||
def on_action_save_as(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
filename, f = QtWidgets.QFileDialog.getSaveFileName(
|
||||
parent=self,
|
||||
caption='Save file',
|
||||
|
|
@ -357,6 +374,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.do_save(filename, create_new=True)
|
||||
|
||||
def on_action_save(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
if not self.filename:
|
||||
self.on_action_save_as()
|
||||
else:
|
||||
|
|
@ -429,6 +447,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.worker.start()
|
||||
|
||||
def on_action_insert_images(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
formats = self.get_supported_image_formats(QtGui.QImageReader)
|
||||
logger.debug(f'Supported image types for reading: {formats}')
|
||||
filenames, f = QtWidgets.QFileDialog.getOpenFileNames(
|
||||
|
|
@ -438,6 +457,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.do_insert_images(filenames)
|
||||
|
||||
def on_action_insert_text(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
item = BeeTextItem()
|
||||
pos = self.mapToScene(self.mapFromGlobal(self.cursor().pos()))
|
||||
item.setScale(1 / self.get_scale())
|
||||
|
|
@ -445,6 +465,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
|
||||
def on_action_copy(self):
|
||||
logger.debug('Copying to clipboard...')
|
||||
self.scene.cancel_crop_mode()
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
items = self.scene.selectedItems(user_only=True)
|
||||
|
||||
|
|
@ -462,6 +483,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
'beeref/items', QtCore.QByteArray.number(len(items)))
|
||||
|
||||
def on_action_paste(self):
|
||||
self.scene.cancel_crop_mode()
|
||||
logger.debug('Pasting from clipboard...')
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
pos = self.mapToScene(self.mapFromGlobal(self.cursor().pos()))
|
||||
|
|
@ -499,6 +521,8 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
len(self.scene.selectedItems(user_only=True)))
|
||||
self.actiongroup_set_enabled('active_when_selection',
|
||||
self.scene.has_selection())
|
||||
self.actiongroup_set_enabled('active_when_croppable',
|
||||
self.scene.has_croppable_selection())
|
||||
self.viewport().repaint()
|
||||
|
||||
def recalc_scene_rect(self):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import os.path
|
|||
import stat
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt6 import QtGui
|
||||
from PyQt6 import QtCore, QtGui
|
||||
import pytest
|
||||
|
||||
from beeref.fileio import schema, is_bee_file
|
||||
|
|
@ -233,6 +233,7 @@ def test_sqliteio_write_inserts_new_pixmap_item(tmpfile, view):
|
|||
item.setZValue(0.22)
|
||||
item.setRotation(33)
|
||||
item.do_flip()
|
||||
item.crop = QtCore.QRectF(5, 5, 100, 80)
|
||||
item.pixmap_to_bytes = MagicMock(return_value=b'abc')
|
||||
io = SQLiteIO(tmpfile, view.scene, create_new=True)
|
||||
io.write()
|
||||
|
|
@ -249,7 +250,10 @@ def test_sqliteio_write_inserts_new_pixmap_item(tmpfile, view):
|
|||
assert result[3] == 1.3
|
||||
assert result[4] == 33
|
||||
assert result[5] == -1
|
||||
assert json.loads(result[6]) == {'filename': 'bee.jpg'}
|
||||
assert json.loads(result[6]) == {
|
||||
'filename': 'bee.jpg',
|
||||
'crop': [5, 5, 100, 80],
|
||||
}
|
||||
assert result[7] == 'pixmap'
|
||||
assert result[8] == b'abc'
|
||||
assert result[9] == '0001-bee.png'
|
||||
|
|
@ -265,7 +269,7 @@ def test_sqliteio_write_inserts_new_pixmap_item_without_filename(
|
|||
result = io.fetchone(
|
||||
'SELECT items.data, sqlar.name FROM items '
|
||||
'INNER JOIN sqlar on sqlar.item_id = items.id')
|
||||
assert json.loads(result[0]) == {'filename': None}
|
||||
assert json.loads(result[0])['filename'] is None
|
||||
assert result[1] == '0001.png'
|
||||
|
||||
|
||||
|
|
@ -311,6 +315,7 @@ def test_sqliteio_write_updates_existing_pixmap_item(tmpfile, view):
|
|||
item.setZValue(0.22)
|
||||
item.setRotation(33)
|
||||
item.save_id = 1
|
||||
item.crop = QtCore.QRectF(5, 5, 80, 100)
|
||||
item.pixmap_to_bytes = MagicMock(return_value=b'abc')
|
||||
io = SQLiteIO(tmpfile, view.scene, create_new=True)
|
||||
io.write()
|
||||
|
|
@ -319,6 +324,7 @@ def test_sqliteio_write_updates_existing_pixmap_item(tmpfile, view):
|
|||
item.setZValue(0.33)
|
||||
item.setRotation(100)
|
||||
item.do_flip()
|
||||
item.crop = QtCore.QRectF(1, 2, 30, 40)
|
||||
item.filename = 'new.png'
|
||||
item.pixmap_to_bytes.return_value = b'updated'
|
||||
io.create_new = False
|
||||
|
|
@ -335,7 +341,10 @@ def test_sqliteio_write_updates_existing_pixmap_item(tmpfile, view):
|
|||
assert result[3] == 0.7
|
||||
assert result[4] == 100
|
||||
assert result[5] == -1
|
||||
assert json.loads(result[6]) == {'filename': 'new.png'}
|
||||
assert json.loads(result[6]) == {
|
||||
'filename': 'new.png',
|
||||
'crop': [1, 2, 30, 40],
|
||||
}
|
||||
assert result[7] == b'abc'
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from unittest.mock import patch, MagicMock, PropertyMock
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref.items import BeePixmapItem, item_registry
|
||||
|
||||
|
|
@ -17,44 +19,66 @@ def test_init(selectable_mock, qapp, imgfilename3x3):
|
|||
assert item.height == 3
|
||||
assert item.scale() == 1
|
||||
assert item.filename == imgfilename3x3
|
||||
assert item.crop == QtCore.QRectF(0, 0, 3, 3)
|
||||
assert item.is_croppable is True
|
||||
assert item.crop_mode is False
|
||||
selectable_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_set_pos_center(qapp, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -100
|
||||
assert item.pos().y() == -50
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -100
|
||||
assert item.pos().y() == -50
|
||||
|
||||
|
||||
def test_set_pos_center_when_scaled(qapp, item):
|
||||
item.setScale(2)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -200
|
||||
assert item.pos().y() == -100
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -200
|
||||
assert item.pos().y() == -100
|
||||
|
||||
|
||||
def test_set_pos_center_when_rotated(qapp, item):
|
||||
item.setRotation(90)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == 50
|
||||
assert item.pos().y() == -100
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == 50
|
||||
assert item.pos().y() == -100
|
||||
|
||||
|
||||
def test_set_crop(qapp, item):
|
||||
item.update = MagicMock()
|
||||
item.prepareGeometryChange = MagicMock()
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.update.assert_called_once_with()
|
||||
item.prepareGeometryChange.assert_called_once_with()
|
||||
|
||||
|
||||
def test_bounding_rect_unselected(qapp, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
item.crop = QtCore.QRectF(1, 1, 2, 2)
|
||||
assert item.bounding_rect_unselected() == QtCore.QRectF(1, 1, 2, 2)
|
||||
|
||||
|
||||
def test_bounding_rect_unselected_in_crop_mode(qapp, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
item.crop = QtCore.QRectF(1, 1, 2, 2)
|
||||
item.crop_mode = True
|
||||
assert item.bounding_rect_unselected() == QtCore.QRectF(-0.5, -0.5, 4, 4)
|
||||
|
||||
|
||||
def test_get_extra_save_data(item):
|
||||
item.filename = 'foobar.png'
|
||||
assert item.get_extra_save_data() == {'filename': 'foobar.png'}
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
assert item.get_extra_save_data() == {
|
||||
'filename': 'foobar.png',
|
||||
'crop': [10, 20, 30, 40],
|
||||
}
|
||||
|
||||
|
||||
def test_pixmap_to_bytes(qapp, imgfilename3x3):
|
||||
|
|
@ -68,15 +92,7 @@ def test_pixmap_from_bytes(qapp, item, imgfilename3x3):
|
|||
item.pixmap_from_bytes(imgdata)
|
||||
assert item.width == 3
|
||||
assert item.height == 3
|
||||
|
||||
|
||||
def test_paint(qapp, item):
|
||||
item.pixmap = MagicMock(return_value='bee')
|
||||
item.paint_selectable = MagicMock()
|
||||
painter = MagicMock()
|
||||
item.paint(painter, None, None)
|
||||
item.paint_selectable.assert_called_once()
|
||||
painter.drawPixmap.assert_called_with(0, 0, 'bee')
|
||||
assert item.crop == QtCore.QRectF(0, 0, 3, 3)
|
||||
|
||||
|
||||
def test_has_selection_outline_when_not_selected(view, item):
|
||||
|
|
@ -159,6 +175,14 @@ def test_create_from_data(item):
|
|||
assert item.filename == 'foobar.png'
|
||||
|
||||
|
||||
def test_create_from_data_with_crop(item):
|
||||
new_item = BeePixmapItem.create_from_data(
|
||||
item=item, data={'filename': 'foobar.png', 'crop': [10, 20, 30, 40]})
|
||||
assert new_item is item
|
||||
assert item.filename == 'foobar.png'
|
||||
assert item.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
|
||||
|
||||
def test_create_copy(qapp, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3), 'foo.png')
|
||||
item.setPos(20, 30)
|
||||
|
|
@ -166,19 +190,401 @@ def test_create_copy(qapp, imgfilename3x3):
|
|||
item.do_flip()
|
||||
item.setZValue(0.5)
|
||||
item.setScale(2.2)
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
|
||||
copy = item.create_copy()
|
||||
assert copy.pixmap_to_bytes() == item.pixmap_to_bytes()
|
||||
assert copy.filename == 'foo.png'
|
||||
assert copy.pos() == QtCore.QPointF(20, 30)
|
||||
assert copy.rotation() == 33
|
||||
assert item.flip() == -1
|
||||
assert item.zValue() == 0.5
|
||||
assert item.scale() == 2.2
|
||||
assert copy.flip() == -1
|
||||
assert copy.zValue() == 0.5
|
||||
assert copy.scale() == 2.2
|
||||
assert copy.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
|
||||
|
||||
def test_item_to_clipboard(qapp, imgfilename3x3):
|
||||
def test_copy_to_clipboard(qapp, imgfilename3x3):
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3), 'foo.png')
|
||||
item.copy_to_clipboard(clipboard)
|
||||
assert clipboard.pixmap().size() == item.pixmap().size()
|
||||
|
||||
|
||||
def test_reset_crop(qapp, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.reset_crop()
|
||||
assert item.crop == QtCore.QRectF(0, 0, 3, 3)
|
||||
|
||||
|
||||
def test_crop_handle_topleft(qapp, item):
|
||||
item.crop_temp = QtCore.QRectF(100, 200, 300, 400)
|
||||
assert item.crop_handle_topleft() == QtCore.QRectF(100, 200, 15, 15)
|
||||
|
||||
|
||||
def test_crop_handle_bottomleft(qapp, item):
|
||||
item.crop_temp = QtCore.QRectF(100, 200, 300, 400)
|
||||
assert item.crop_handle_bottomleft() == QtCore.QRectF(100, 585, 15, 15)
|
||||
|
||||
|
||||
def test_crop_handle_bottomright(qapp, item):
|
||||
item.crop_temp = QtCore.QRectF(100, 200, 300, 400)
|
||||
assert item.crop_handle_bottomright() == QtCore.QRectF(385, 585, 15, 15)
|
||||
|
||||
|
||||
def test_crop_handle_topright(qapp, item):
|
||||
item.crop_temp = QtCore.QRectF(100, 200, 300, 400)
|
||||
assert item.crop_handle_topright() == QtCore.QRectF(385, 200, 15, 15)
|
||||
|
||||
|
||||
def test_paint(qapp, item):
|
||||
item.pixmap = MagicMock()
|
||||
item.paint_selectable = MagicMock()
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
painter = MagicMock()
|
||||
item.paint(painter, None, None)
|
||||
item.paint_selectable.assert_called_once()
|
||||
painter.drawPixmap.assert_called_with(
|
||||
QtCore.QRectF(10, 20, 30, 40),
|
||||
item.pixmap(),
|
||||
QtCore.QRectF(10, 20, 30, 40))
|
||||
|
||||
|
||||
def test_paint_when_crop_mode(qapp, item):
|
||||
item.pixmap = MagicMock()
|
||||
item.paint_selectable = MagicMock()
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode = True
|
||||
item.crop_temp = QtCore.QRectF(11, 22, 29, 39)
|
||||
painter = MagicMock()
|
||||
item.paint(painter, None, None)
|
||||
item.paint_selectable.assert_not_called()
|
||||
painter.drawPixmap.assert_called_with(0, 0, item.pixmap())
|
||||
|
||||
|
||||
def test_enter_crop_mode(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.update = MagicMock()
|
||||
item.prepareGeometryChange = MagicMock()
|
||||
item.grabKeyboard = MagicMock()
|
||||
|
||||
item.enter_crop_mode()
|
||||
assert item.crop_mode is True
|
||||
assert item.crop_temp == QtCore.QRectF(10, 20, 30, 40)
|
||||
assert item.crop_mode_move is None
|
||||
assert item.crop_mode_event_start is None
|
||||
item.update.assert_called_once_with()
|
||||
item.prepareGeometryChange.assert_called_once_with()
|
||||
item.grabKeyboard.assert_called_once_with()
|
||||
assert view.scene.crop_item == item
|
||||
|
||||
|
||||
def test_exit_crop_mode_confirmed(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.update = MagicMock()
|
||||
item.prepareGeometryChange = MagicMock()
|
||||
item.ungrabKeyboard = MagicMock()
|
||||
item.crop = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode = True
|
||||
item.crop_mode_move = 'topleft'
|
||||
item.crop_mode_event_start = QtCore.QRectF(1, 1, 1, 1)
|
||||
|
||||
item.exit_crop_mode(confirm=True)
|
||||
item.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
assert item.crop_mode is False
|
||||
assert item.crop_temp is None
|
||||
assert item.crop_mode_move is None
|
||||
assert item.crop_mode_event_start is None
|
||||
item.update.assert_called()
|
||||
item.prepareGeometryChange.assert_called()
|
||||
item.ungrabKeyboard.assert_called_once_with()
|
||||
assert view.scene.crop_item is None
|
||||
view.scene.undo_stack.canUndo() is True
|
||||
|
||||
|
||||
def test_exit_crop_mode_confirmed_no_change(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.crop = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_temp = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode = True
|
||||
|
||||
item.exit_crop_mode(confirm=True)
|
||||
assert item.crop == QtCore.QRectF(0, 0, 100, 80)
|
||||
view.scene.undo_stack.canUndo() is False
|
||||
|
||||
|
||||
def test_exit_crop_mode_not_confirmed(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.update = MagicMock()
|
||||
item.prepareGeometryChange = MagicMock()
|
||||
item.ungrabKeyboard = MagicMock()
|
||||
item.crop = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode = True
|
||||
item.crop_mode_move = 'topleft'
|
||||
item.crop_mode_event_start = QtCore.QRectF(1, 1, 1, 1)
|
||||
|
||||
item.exit_crop_mode(confirm=False)
|
||||
item.crop == QtCore.QRectF(0, 0, 100, 80)
|
||||
assert item.crop_mode is False
|
||||
assert item.crop_temp is None
|
||||
assert item.crop_mode_move is None
|
||||
assert item.crop_mode_event_start is None
|
||||
item.update.assert_called()
|
||||
item.prepareGeometryChange.assert_called()
|
||||
item.ungrabKeyboard.assert_called_once_with()
|
||||
assert view.scene.crop_item is None
|
||||
view.scene.undo_stack.canUndo() is False
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsPixmapItem.keyPressEvent')
|
||||
def test_key_press_event_return(key_mock, qapp, item):
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
event.key.return_value = Qt.Key.Key_Return
|
||||
item.keyPressEvent(event)
|
||||
item.exit_crop_mode.assert_called_once_with(confirm=True)
|
||||
key_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsPixmapItem.keyPressEvent')
|
||||
def test_key_press_event_escape(key_mock, qapp, item):
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
event.key.return_value = Qt.Key.Key_Escape
|
||||
item.keyPressEvent(event)
|
||||
item.exit_crop_mode.assert_called_once_with(confirm=False)
|
||||
key_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsPixmapItem.keyPressEvent')
|
||||
def test_key_press_event_other(key_mock, qapp, item):
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
event.key.return_value = Qt.Key.Key_Space
|
||||
item.keyPressEvent(event)
|
||||
item.exit_crop_mode.assert_not_called()
|
||||
key_mock.assert_called_once_with(event)
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.hoverMoveEvent')
|
||||
def test_hover_move_event_when_not_crop_mode(hover_mock, qapp, item):
|
||||
item.crop_mode = False
|
||||
event = MagicMock()
|
||||
|
||||
item.hoverMoveEvent(event)
|
||||
hover_mock.assert_called_once_with(event)
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.hoverMoveEvent')
|
||||
def test_hover_move_event_crop_mode_inside_handle(hover_mock, qapp, item):
|
||||
item.crop_mode = True
|
||||
item.crop_temp = QtCore.QRectF(0, 0, 100, 80)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(5, 5)
|
||||
|
||||
item.hoverMoveEvent(event)
|
||||
item.cursor() == Qt.CursorShape.SizeFDiagCursor
|
||||
hover_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.hoverMoveEvent')
|
||||
def test_hover_move_event_crop_mode_outside_handle(hover_mock, qapp, item):
|
||||
item.crop_mode = True
|
||||
item.crop_temp = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.setCursor(Qt.CursorShape.SizeFDiagCursor)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(50, 50)
|
||||
|
||||
item.hoverMoveEvent(event)
|
||||
item.cursor() == Qt.CursorShape.ArrowCursor
|
||||
hover_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mousePressEvent')
|
||||
def test_mouse_press_event_when_not_crop_mode(mouse_mock, qapp, item):
|
||||
item.crop_mode = False
|
||||
item.crop_mode_move = None
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
|
||||
item.mousePressEvent(event)
|
||||
assert item.crop_mode_move is None
|
||||
item.exit_crop_mode.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
event.accept.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mousePressEvent')
|
||||
def test_mouse_press_event_crop_mode_inside_handle(mouse_mock, qapp, item):
|
||||
item.crop_mode = True
|
||||
item.crop_temp = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode_move = None
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(5, 5)
|
||||
|
||||
item.mousePressEvent(event)
|
||||
assert item.crop_mode_move == item.crop_handle_topleft
|
||||
assert item.crop_mode_event_start == QtCore.QPointF(5, 5)
|
||||
item.exit_crop_mode.assert_not_called()
|
||||
mouse_mock.assert_not_called()
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mousePressEvent')
|
||||
def test_mouse_press_event_crop_mode_outside_handle_inside_crop(
|
||||
mouse_mock, qapp, item):
|
||||
item.crop_mode = True
|
||||
item.crop_temp = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode_move = None
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(50, 50)
|
||||
|
||||
item.mousePressEvent(event)
|
||||
assert item.crop_mode_move is None
|
||||
item.exit_crop_mode.assert_called_once_with(confirm=True)
|
||||
mouse_mock.assert_not_called()
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mousePressEvent')
|
||||
def test_mouse_press_event_crop_mode_outside_handle_outside_crop(
|
||||
mouse_mock, qapp, item):
|
||||
item.crop_mode = True
|
||||
item.crop_temp = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode_move = None
|
||||
item.exit_crop_mode = MagicMock()
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(150, 150)
|
||||
|
||||
item.mousePressEvent(event)
|
||||
assert item.crop_mode_move is None
|
||||
item.exit_crop_mode.assert_called_once_with(confirm=False)
|
||||
mouse_mock.assert_not_called()
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
@pytest.mark.parametrize('point,expected',
|
||||
[((45, 56), (45, 56)),
|
||||
((0, 0), (0, 0)),
|
||||
((-5, -5), (0, 0)),
|
||||
((100, 80), (100, 80)),
|
||||
((105, 85), (100, 80))])
|
||||
def test_ensure_point_within_pixmap_bounds_inside(point, expected, qapp, item):
|
||||
pixmap = MagicMock()
|
||||
pixmap.size.return_value = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.pixmap = MagicMock(return_value=pixmap)
|
||||
result = item.ensure_point_within_pixmap_bounds(QtCore.QPointF(*point))
|
||||
assert result == QtCore.QPointF(*expected)
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseMoveEvent')
|
||||
def test_mouse_move_when_crop_mode_bottomleft(mouse_mock, qapp, item):
|
||||
pixmap = MagicMock()
|
||||
pixmap.size.return_value = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode = True
|
||||
item.pixmap = MagicMock(return_value=pixmap)
|
||||
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode_event_start = QtCore.QPointF(15, 75)
|
||||
item.crop_mode_move = item.crop_handle_bottomleft
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(10, 70)
|
||||
|
||||
item.mouseMoveEvent(event)
|
||||
assert item.crop_temp == QtCore.QRectF(5, 20, 35, 35)
|
||||
event.accept.assert_called_once()
|
||||
mouse_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseMoveEvent')
|
||||
def test_mouse_move_when_crop_mode_bottomright(mouse_mock, qapp, item):
|
||||
pixmap = MagicMock()
|
||||
pixmap.size.return_value = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode = True
|
||||
item.pixmap = MagicMock(return_value=pixmap)
|
||||
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode_event_start = QtCore.QPointF(95, 75)
|
||||
item.crop_mode_move = item.crop_handle_bottomright
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(90, 70)
|
||||
|
||||
item.mouseMoveEvent(event)
|
||||
assert item.crop_temp == QtCore.QRectF(10, 20, 25, 35)
|
||||
event.accept.assert_called_once()
|
||||
mouse_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseMoveEvent')
|
||||
def test_mouse_move_when_crop_mode_topleft(mouse_mock, qapp, item):
|
||||
pixmap = MagicMock()
|
||||
pixmap.size.return_value = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode = True
|
||||
item.pixmap = MagicMock(return_value=pixmap)
|
||||
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode_event_start = QtCore.QPointF(15, 25)
|
||||
item.crop_mode_move = item.crop_handle_topleft
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(10, 20)
|
||||
|
||||
item.mouseMoveEvent(event)
|
||||
assert item.crop_temp == QtCore.QRectF(5, 15, 35, 45)
|
||||
event.accept.assert_called_once()
|
||||
mouse_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseMoveEvent')
|
||||
def test_mouse_move_when_crop_mode_topright(mouse_mock, qapp, item):
|
||||
pixmap = MagicMock()
|
||||
pixmap.size.return_value = QtCore.QRectF(0, 0, 100, 80)
|
||||
item.crop_mode = True
|
||||
item.pixmap = MagicMock(return_value=pixmap)
|
||||
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.crop_mode_event_start = QtCore.QPointF(35, 55)
|
||||
item.crop_mode_move = item.crop_handle_topright
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(30, 50)
|
||||
|
||||
item.mouseMoveEvent(event)
|
||||
assert item.crop_temp == QtCore.QRectF(10, 15, 25, 45)
|
||||
event.accept.assert_called_once()
|
||||
mouse_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseMoveEvent')
|
||||
def test_mouse_move_when_not_crop_mode(mouse_mock, qapp, item):
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(30, 50)
|
||||
|
||||
item.mouseMoveEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseReleaseEvent')
|
||||
def test_mouse_release_event_when_crop_mode(mouse_mock, qapp, item):
|
||||
event = MagicMock()
|
||||
item.crop_mode = True
|
||||
item.crop_mode_move = item.crop_handle_topright
|
||||
item.crop_mode_event_start = QtCore.QPointF(44, 55)
|
||||
|
||||
item.mouseReleaseEvent(event)
|
||||
assert item.crop_mode is True
|
||||
assert item.crop_mode_move is None
|
||||
assert item.crop_mode_event_start is None
|
||||
event.accept.assert_called_once()
|
||||
mouse_mock.assert_not_called()
|
||||
|
||||
|
||||
@patch('beeref.selection.SelectableMixin.mouseReleaseEvent')
|
||||
def test_mouse_release_event_when_not_crop_mode(mouse_mock, qapp, item):
|
||||
event = MagicMock()
|
||||
item.crop_mode = False
|
||||
|
||||
item.mouseReleaseEvent(event)
|
||||
assert item.crop_mode is False
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from unittest.mock import patch, MagicMock, PropertyMock
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
|
@ -25,37 +25,31 @@ def test_init(selectable_mock, qapp):
|
|||
|
||||
def test_set_pos_center(qapp):
|
||||
item = BeeTextItem('foo bar')
|
||||
with patch('beeref.items.BeeTextItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeeTextItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -100
|
||||
assert item.pos().y() == -50
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -100
|
||||
assert item.pos().y() == -50
|
||||
|
||||
|
||||
def test_set_pos_center_when_scaled(qapp):
|
||||
item = BeeTextItem('foo bar')
|
||||
item.setScale(2)
|
||||
with patch('beeref.items.BeeTextItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeeTextItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -200
|
||||
assert item.pos().y() == -100
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == -200
|
||||
assert item.pos().y() == -100
|
||||
|
||||
|
||||
def test_set_pos_center_when_rotated(qapp):
|
||||
item = BeeTextItem('foo bar')
|
||||
item.setRotation(90)
|
||||
with patch('beeref.items.BeeTextItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeeTextItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == 50
|
||||
assert item.pos().y() == -100
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
item.set_pos_center(QtCore.QPointF(0, 0))
|
||||
assert item.pos().x() == 50
|
||||
assert item.pos().y() == -100
|
||||
|
||||
|
||||
def test_get_extra_save_data(qapp):
|
||||
|
|
@ -206,21 +200,26 @@ def test_create_copy(qapp):
|
|||
assert item.scale() == 2.2
|
||||
|
||||
|
||||
def test_enter_edit_mode(qapp):
|
||||
def test_enter_edit_mode(view):
|
||||
item = BeeTextItem('foo bar')
|
||||
view.scene.addItem(item)
|
||||
item.enter_edit_mode()
|
||||
assert item.edit_mode is True
|
||||
assert view.scene.edit_item == item
|
||||
flags = item.textInteractionFlags()
|
||||
assert flags == Qt.TextInteractionFlag.TextEditorInteraction
|
||||
|
||||
|
||||
@patch('PyQt6.QtGui.QTextCursor')
|
||||
@patch('beeref.items.BeeTextItem.setTextCursor')
|
||||
def test_exit_edit_mode(setcursor_mock, cursor_mock, qapp):
|
||||
def test_exit_edit_mode(setcursor_mock, cursor_mock, view):
|
||||
item = BeeTextItem('foo bar')
|
||||
item.edit_mode = True
|
||||
view.scene.addItem(item)
|
||||
view.scene.edit_item = item
|
||||
item.exit_edit_mode()
|
||||
assert item.edit_mode is False
|
||||
assert view.scene.edit_item is None
|
||||
flags = item.textInteractionFlags()
|
||||
assert flags == Qt.TextInteractionFlag.NoTextInteraction
|
||||
cursor_mock.assert_called_once_with(item.document())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from unittest.mock import patch, MagicMock, PropertyMock
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from PyQt6 import QtCore, QtGui
|
||||
|
||||
|
|
@ -118,12 +118,73 @@ def test_do_flip_vertical_anchor(qapp, item):
|
|||
assert item.pos() == QtCore.QPointF(0, 200)
|
||||
|
||||
|
||||
def test_base_item_mixin_center_scene_coords(view, item):
|
||||
def test_width(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.center_scene_coords == QtCore.QPointF(105, 85)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.width == 100
|
||||
|
||||
|
||||
def test_width_cropped_item(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.width == 100
|
||||
|
||||
|
||||
def test_height(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.height == 80
|
||||
|
||||
|
||||
def test_height_cropped_item(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.height == 80
|
||||
|
||||
|
||||
def test_center(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.center == QtCore.QPointF(50, 40)
|
||||
|
||||
|
||||
def test_center_cropped_item(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(10, 10, 40, 30)):
|
||||
assert item.center == QtCore.QPointF(30, 25)
|
||||
|
||||
|
||||
def test_center_scene_coords(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.center_scene_coords == QtCore.QPointF(105, 85)
|
||||
|
||||
|
||||
def test_center_scene_coords_cropped_item(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setPos(5, 5)
|
||||
item.setScale(2)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(10, 10, 40, 30)):
|
||||
assert item.center_scene_coords == QtCore.QPointF(65, 55)
|
||||
|
|
|
|||
|
|
@ -14,18 +14,6 @@ def test_init(selectable_mock):
|
|||
selectable_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_width():
|
||||
item = MultiSelectItem()
|
||||
item.setRect(0, 0, 50, 100)
|
||||
assert item.width == 50
|
||||
|
||||
|
||||
def test_height():
|
||||
item = MultiSelectItem()
|
||||
item.setRect(0, 0, 50, 100)
|
||||
assert item.height == 100
|
||||
|
||||
|
||||
def test_paint():
|
||||
item = MultiSelectItem()
|
||||
item.paint_selectable = MagicMock()
|
||||
|
|
@ -67,8 +55,8 @@ def test_fit_selection_area():
|
|||
item.fit_selection_area(QtCore.QRectF(-10, -20, 100, 80))
|
||||
assert item.pos().x() == -10
|
||||
assert item.pos().y() == -20
|
||||
assert item.width == 100
|
||||
assert item.height == 80
|
||||
assert item.width == 101
|
||||
assert item.height == 81
|
||||
assert item.scale() == 1
|
||||
assert item.rotation() == 0
|
||||
assert item.flip() == 1
|
||||
|
|
|
|||
|
|
@ -3,18 +3,6 @@ from PyQt6 import QtCore
|
|||
from beeref.selection import RubberbandItem
|
||||
|
||||
|
||||
def test_width():
|
||||
item = RubberbandItem()
|
||||
item.setRect(5, 5, 100, 80)
|
||||
assert item.width == 100
|
||||
|
||||
|
||||
def test_height():
|
||||
item = RubberbandItem()
|
||||
item.setRect(5, 5, 100, 80)
|
||||
assert item.height == 80
|
||||
|
||||
|
||||
def test_fit_topleft_to_bottomright():
|
||||
item = RubberbandItem()
|
||||
item.fit(QtCore.QPointF(-10, -20), QtCore.QPointF(30, 40))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import math
|
||||
from pytest import approx, mark
|
||||
from unittest.mock import patch, MagicMock, PropertyMock
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from PyQt6 import QtCore, QtGui
|
||||
from PyQt6.QtCore import Qt
|
||||
|
|
@ -8,31 +8,6 @@ from PyQt6.QtCore import Qt
|
|||
from beeref.assets import BeeAssets
|
||||
from beeref import commands
|
||||
from beeref.items import BeePixmapItem
|
||||
from beeref.scene import BeeGraphicsScene
|
||||
|
||||
|
||||
@mark.skip
|
||||
class SelectableMixinBaseTestCase():
|
||||
|
||||
def setUp(self):
|
||||
self.scene = BeeGraphicsScene(None)
|
||||
self.item = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(self.item)
|
||||
self.view = MagicMock(get_scale=MagicMock(return_value=1))
|
||||
views_patcher = patch('beeref.scene.BeeGraphicsScene.views',
|
||||
return_value=[self.view])
|
||||
views_patcher.start()
|
||||
self.addCleanup(views_patcher.stop)
|
||||
width_patcher = patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock,
|
||||
return_value=100)
|
||||
width_patcher.start()
|
||||
self.addCleanup(width_patcher.stop)
|
||||
height_patcher = patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock,
|
||||
return_value=80)
|
||||
height_patcher.start()
|
||||
self.addCleanup(height_patcher.stop)
|
||||
|
||||
|
||||
def test_init_selectable(view):
|
||||
|
|
@ -195,43 +170,37 @@ def test_paint_when_debug_handles(view):
|
|||
|
||||
|
||||
def test_corners(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert len(item.corners) == 4
|
||||
assert QtCore.QPointF(0, 0) in item.corners
|
||||
assert QtCore.QPointF(100, 0) in item.corners
|
||||
assert QtCore.QPointF(0, 80) in item.corners
|
||||
assert QtCore.QPointF(100, 80) in item.corners
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert len(item.corners) == 4
|
||||
assert QtCore.QPointF(0, 0) in item.corners
|
||||
assert QtCore.QPointF(100, 0) in item.corners
|
||||
assert QtCore.QPointF(0, 80) in item.corners
|
||||
assert QtCore.QPointF(100, 80) in item.corners
|
||||
|
||||
|
||||
def test_corners_scene_coords_translated(view, item):
|
||||
item.setPos(5, 5)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
corners = item.corners_scene_coords
|
||||
assert len(item.corners) == 4
|
||||
assert QtCore.QPointF(5, 5) in corners
|
||||
assert QtCore.QPointF(105, 5) in corners
|
||||
assert QtCore.QPointF(5, 85) in corners
|
||||
assert QtCore.QPointF(105, 85) in corners
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
corners = item.corners_scene_coords
|
||||
assert len(corners) == 4
|
||||
assert QtCore.QPointF(5, 5) in corners
|
||||
assert QtCore.QPointF(105, 5) in corners
|
||||
assert QtCore.QPointF(5, 85) in corners
|
||||
assert QtCore.QPointF(105, 85) in corners
|
||||
|
||||
|
||||
def test_corners_scene_coords_scaled(view, item):
|
||||
item.setScale(2)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
corners = item.corners_scene_coords
|
||||
assert len(item.corners) == 4
|
||||
assert QtCore.QPointF(0, 0) in corners
|
||||
assert QtCore.QPointF(200, 0) in corners
|
||||
assert QtCore.QPointF(0, 160) in corners
|
||||
assert QtCore.QPointF(200, 160) in corners
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
corners = item.corners_scene_coords
|
||||
assert len(corners) == 4
|
||||
assert QtCore.QPointF(0, 0) in corners
|
||||
assert QtCore.QPointF(200, 0) in corners
|
||||
assert QtCore.QPointF(0, 160) in corners
|
||||
assert QtCore.QPointF(200, 160) in corners
|
||||
|
||||
|
||||
def test_get_scale_bounds(view, item):
|
||||
|
|
@ -279,29 +248,47 @@ def test_rotate_bounds_topleft(view, item):
|
|||
def test_get_flip_bounds(view, item):
|
||||
item.SELECT_RESIZE_SIZE = 10
|
||||
item.SELECT_ROTATE_SIZE = 10
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
edges = item.get_flip_bounds()
|
||||
assert edges[0]['rect'].topLeft() == QtCore.QPointF(5, -5)
|
||||
assert edges[0]['rect'].bottomRight() == QtCore.QPointF(95, 5)
|
||||
assert edges[0]['flip_v'] is True
|
||||
assert edges[1]['rect'].topLeft() == QtCore.QPointF(5, 75)
|
||||
assert edges[1]['rect'].bottomRight() == QtCore.QPointF(95, 85)
|
||||
assert edges[1]['flip_v'] is True
|
||||
assert edges[2]['rect'].topLeft() == QtCore.QPointF(-5, 5)
|
||||
assert edges[2]['rect'].bottomRight() == QtCore.QPointF(5, 75)
|
||||
assert edges[2]['flip_v'] is False
|
||||
assert edges[3]['rect'].topLeft() == QtCore.QPointF(95, 5)
|
||||
assert edges[3]['rect'].bottomRight() == QtCore.QPointF(105, 75)
|
||||
assert edges[3]['flip_v'] is False
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
edges = item.get_flip_bounds()
|
||||
assert edges[0]['rect'].topLeft() == QtCore.QPointF(5, -5)
|
||||
assert edges[0]['rect'].bottomRight() == QtCore.QPointF(95, 5)
|
||||
assert edges[0]['flip_v'] is True
|
||||
assert edges[1]['rect'].topLeft() == QtCore.QPointF(5, 75)
|
||||
assert edges[1]['rect'].bottomRight() == QtCore.QPointF(95, 85)
|
||||
assert edges[1]['flip_v'] is True
|
||||
assert edges[2]['rect'].topLeft() == QtCore.QPointF(-5, 5)
|
||||
assert edges[2]['rect'].bottomRight() == QtCore.QPointF(5, 75)
|
||||
assert edges[2]['flip_v'] is False
|
||||
assert edges[3]['rect'].topLeft() == QtCore.QPointF(95, 5)
|
||||
assert edges[3]['rect'].bottomRight() == QtCore.QPointF(105, 75)
|
||||
assert edges[3]['flip_v'] is False
|
||||
|
||||
|
||||
def test_get_flip_bounds_cropped_item(view, item):
|
||||
item.SELECT_RESIZE_SIZE = 10
|
||||
item.SELECT_ROTATE_SIZE = 10
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
edges = item.get_flip_bounds()
|
||||
assert edges[0]['rect'].topLeft() == QtCore.QPointF(10, 0)
|
||||
assert edges[0]['rect'].bottomRight() == QtCore.QPointF(100, 10)
|
||||
assert edges[0]['flip_v'] is True
|
||||
assert edges[1]['rect'].topLeft() == QtCore.QPointF(10, 80)
|
||||
assert edges[1]['rect'].bottomRight() == QtCore.QPointF(100, 90)
|
||||
assert edges[1]['flip_v'] is True
|
||||
assert edges[2]['rect'].topLeft() == QtCore.QPointF(0, 10)
|
||||
assert edges[2]['rect'].bottomRight() == QtCore.QPointF(10, 80)
|
||||
assert edges[2]['flip_v'] is False
|
||||
assert edges[3]['rect'].topLeft() == QtCore.QPointF(100, 10)
|
||||
assert edges[3]['rect'].bottomRight() == QtCore.QPointF(110, 80)
|
||||
assert edges[3]['flip_v'] is False
|
||||
|
||||
|
||||
def test_bounding_rect_when_not_selected(view, item):
|
||||
item.setSelected(False)
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.boundingRect',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
rect = item.boundingRect()
|
||||
assert rect.topLeft().x() == 0
|
||||
assert rect.topLeft().y() == 0
|
||||
|
|
@ -313,22 +300,20 @@ def test_bounding_rect_when_selected(view, item):
|
|||
item.SELECT_RESIZE_SIZE = 10
|
||||
item.SELECT_ROTATE_SIZE = 10
|
||||
item.setSelected(True)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
rect = item.boundingRect()
|
||||
assert rect.topLeft().x() == -15
|
||||
assert rect.topLeft().y() == -15
|
||||
assert rect.bottomRight().x() == 115
|
||||
assert rect.bottomRight().y() == 95
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
rect = item.boundingRect()
|
||||
assert rect.topLeft().x() == -15
|
||||
assert rect.topLeft().y() == -15
|
||||
assert rect.bottomRight().x() == 115
|
||||
assert rect.bottomRight().y() == 95
|
||||
|
||||
|
||||
def test_shape_when_not_selected(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(False)
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.boundingRect',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
shape = item.shape().boundingRect()
|
||||
assert shape.topLeft().x() == 0
|
||||
assert shape.topLeft().y() == 0
|
||||
|
|
@ -344,17 +329,13 @@ def test_shape_when_selected_single(view, item):
|
|||
path = QtGui.QPainterPath()
|
||||
path.addRect(QtCore.QRectF(0, 0, 100, 80))
|
||||
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.shape',
|
||||
return_value=path):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
shape = item.shape().boundingRect()
|
||||
assert shape.topLeft().x() == -15
|
||||
assert shape.topLeft().y() == -15
|
||||
assert shape.bottomRight().x() == 115
|
||||
assert shape.bottomRight().y() == 95
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
shape = item.shape().boundingRect()
|
||||
assert shape.topLeft().x() == -15
|
||||
assert shape.topLeft().y() == -15
|
||||
assert shape.bottomRight().x() == 115
|
||||
assert shape.bottomRight().y() == 95
|
||||
|
||||
|
||||
def test_shape_when_selected_multi(view, item):
|
||||
|
|
@ -366,8 +347,8 @@ def test_shape_when_selected_multi(view, item):
|
|||
item.SELECT_ROTATE_SIZE = 10
|
||||
item.setSelected(True)
|
||||
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.boundingRect',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
shape = item.shape().boundingRect()
|
||||
assert shape.topLeft().x() == 0
|
||||
assert shape.topLeft().y() == 0
|
||||
|
|
@ -381,11 +362,20 @@ def test_get_scale_factor_bottomright(view, item):
|
|||
item.scale_orig_factor = 1
|
||||
event = MagicMock()
|
||||
event.scenePos.return_value = QtCore.QPointF(20, 90)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.get_scale_factor(event) == approx(1.5, 0.01)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.get_scale_factor(event) == approx(1.5, 0.01)
|
||||
|
||||
|
||||
def test_get_scale_factor_bottomright_cropped_item(view, item):
|
||||
item.event_start = QtCore.QPointF(15, 15)
|
||||
item.event_direction = QtCore.QPointF(1, 1) / math.sqrt(2)
|
||||
item.scale_orig_factor = 1
|
||||
event = MagicMock()
|
||||
event.scenePos.return_value = QtCore.QPointF(25, 95)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.get_scale_factor(event) == approx(1.5, 0.01)
|
||||
|
||||
|
||||
def test_get_scale_factor_topleft(view, item):
|
||||
|
|
@ -394,115 +384,176 @@ def test_get_scale_factor_topleft(view, item):
|
|||
item.scale_orig_factor = 0.5
|
||||
event = MagicMock()
|
||||
event.scenePos.return_value = QtCore.QPointF(-10, -60)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.get_scale_factor(event) == approx(2, 0.01)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.get_scale_factor(event) == approx(2, 0.01)
|
||||
|
||||
|
||||
def test_get_scale_factor_topleft_cropped_item(view, item):
|
||||
item.event_start = QtCore.QPointF(15, 15)
|
||||
item.event_direction = QtCore.QPointF(-1, -1) / math.sqrt(2)
|
||||
item.scale_orig_factor = 0.5
|
||||
event = MagicMock()
|
||||
event.scenePos.return_value = QtCore.QPointF(-5, -55)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.get_scale_factor(event) == approx(2, 0.01)
|
||||
|
||||
|
||||
def test_get_scale_anchor_topleft(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(0, 0))
|
||||
assert anchor.x() == 100
|
||||
assert anchor.y() == 80
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(0, 0))
|
||||
assert anchor.x() == 100
|
||||
assert anchor.y() == 80
|
||||
|
||||
|
||||
def test_get_scale_anchor_topleft_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(5, 5))
|
||||
assert anchor.x() == 105
|
||||
assert anchor.y() == 85
|
||||
|
||||
|
||||
def test_get_scale_anchor_bottomright(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(100, 80))
|
||||
assert anchor.x() == 0
|
||||
assert anchor.y() == 0
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(100, 80))
|
||||
assert anchor.x() == 0
|
||||
assert anchor.y() == 0
|
||||
|
||||
|
||||
def test_get_scale_anchor_bottomright_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(105, 85))
|
||||
assert anchor.x() == 5
|
||||
assert anchor.y() == 5
|
||||
|
||||
|
||||
def test_get_scale_anchor_topright(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(100, 0))
|
||||
assert anchor.x() == 0
|
||||
assert anchor.y() == 80
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(100, 0))
|
||||
assert anchor.x() == 0
|
||||
assert anchor.y() == 80
|
||||
|
||||
|
||||
def test_get_scale_anchor_topright_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(105, 5))
|
||||
assert anchor.x() == 5
|
||||
assert anchor.y() == 85
|
||||
|
||||
|
||||
def test_get_scale_anchor_bottomleft(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(0, 80))
|
||||
assert anchor.x() == 100
|
||||
assert anchor.y() == 0
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(0, 80))
|
||||
assert anchor.x() == 100
|
||||
assert anchor.y() == 0
|
||||
|
||||
|
||||
def test_get_scale_anchor_bottomleft_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
anchor = item.get_scale_anchor(QtCore.QPointF(5, 85))
|
||||
assert anchor.x() == 105
|
||||
assert anchor.y() == 5
|
||||
|
||||
|
||||
def test_get_corner_direction_topleft(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(0, 0)) == QtCore.QPointF(-1, -1)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(0, 0)) == QtCore.QPointF(-1, -1)
|
||||
|
||||
|
||||
def test_get_corner_direction_topleft_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(5, 5)) == QtCore.QPointF(-1, -1)
|
||||
|
||||
|
||||
def test_get_corner_direction_bottomright(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(100, 80)) == QtCore.QPointF(1, 1)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(100, 80)) == QtCore.QPointF(1, 1)
|
||||
|
||||
|
||||
def test_get_corner_direction_bottomright_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(105, 85)) == QtCore.QPointF(1, 1)
|
||||
|
||||
|
||||
def test_get_corner_direction_topright(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(100, 0)) == QtCore.QPointF(1, -1)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(100, 0)) == QtCore.QPointF(1, -1)
|
||||
|
||||
|
||||
def test_get_corner_direction_topright_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(105, 5)) == QtCore.QPointF(1, -1)
|
||||
|
||||
|
||||
def test_get_corner_direction_bottomleft(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(0, 80)) == QtCore.QPointF(-1, 1)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(0, 80)) == QtCore.QPointF(-1, 1)
|
||||
|
||||
|
||||
def test_get_direction_from_center_bottomright(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(100, 90))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
def test_get_corner_direction_bottomleft_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
assert item.get_corner_direction(
|
||||
QtCore.QPointF(5, 85)) == QtCore.QPointF(-1, 1)
|
||||
|
||||
|
||||
def test_get_direction_from_center_topleft(view, item):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(0, -10))
|
||||
assert direction == approx(QtCore.QPointF(-1, -1) / math.sqrt(2))
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(0, -10))
|
||||
assert direction == approx(QtCore.QPointF(-1, -1) / math.sqrt(2))
|
||||
|
||||
|
||||
def test_get_direction_from_center_topleft_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(5, -5))
|
||||
assert direction == approx(QtCore.QPointF(-1, -1) / math.sqrt(2))
|
||||
|
||||
|
||||
def test_get_direction_from_center_bottomright(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(100, 90))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
|
||||
|
||||
def test_get_direction_from_center_bottomright_cropped_item(view, item):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 100, 80)):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(105, 95))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
|
||||
|
||||
def test_get_direction_from_center_bottomright_when_rotated_180(view, item):
|
||||
item.setRotation(180, QtCore.QPointF(50, 40))
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(100, 90))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
direction = item.get_direction_from_center(QtCore.QPointF(100, 90))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
|
||||
|
||||
def test_get_rotate_angle(view, item):
|
||||
|
|
@ -548,12 +599,10 @@ def test_hover_move_event_no_selection(view, item):
|
|||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(0, 0)
|
||||
item.setCursor = MagicMock()
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
item.setCursor.assert_not_called()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
item.setCursor.assert_not_called()
|
||||
|
||||
|
||||
@mark.parametrize('pos,flipped,rotation, expected',
|
||||
|
|
@ -575,7 +624,7 @@ def test_hover_move_event_no_selection(view, item):
|
|||
((0, 0), True, 45, 'SizeVerCursor'),
|
||||
((0, 0), True, 90, 'SizeFDiagCursor'),
|
||||
((0, 0), True, 135, 'SizeHorCursor')])
|
||||
def test_hover_move_event_topleft_scale(
|
||||
def test_hover_move_event_scale(
|
||||
pos, flipped, rotation, expected, view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
|
|
@ -584,25 +633,21 @@ def test_hover_move_event_topleft_scale(
|
|||
item.setRotation(rotation)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(*pos)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == getattr(Qt.CursorShape, expected)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == getattr(Qt.CursorShape, expected)
|
||||
|
||||
|
||||
def test_hover_move_event_bottomright_scale_very_wide_item(view, item):
|
||||
def test_hover_move_event_scale_bottomright_very_wide_item(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(1000, 100)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=1000):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == Qt.CursorShape.SizeFDiagCursor
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 1000, 100)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == Qt.CursorShape.SizeFDiagCursor
|
||||
|
||||
|
||||
def test_hover_move_event_rotate(view, item):
|
||||
|
|
@ -610,12 +655,10 @@ def test_hover_move_event_rotate(view, item):
|
|||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(115, 95)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_rotate
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_rotate
|
||||
|
||||
|
||||
def test_hover_flip_event_top_edge(view, item):
|
||||
|
|
@ -623,12 +666,10 @@ def test_hover_flip_event_top_edge(view, item):
|
|||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(50, 0)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_v
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_v
|
||||
|
||||
|
||||
def test_hover_flip_event_bottom_edge(view, item):
|
||||
|
|
@ -636,12 +677,10 @@ def test_hover_flip_event_bottom_edge(view, item):
|
|||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(50, 80)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_v
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_v
|
||||
|
||||
|
||||
def test_hover_flip_event_left_edge(view, item):
|
||||
|
|
@ -649,12 +688,10 @@ def test_hover_flip_event_left_edge(view, item):
|
|||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(0, 50)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_h
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_h
|
||||
|
||||
|
||||
def test_hover_flip_event_right_edge(view, item):
|
||||
|
|
@ -662,12 +699,10 @@ def test_hover_flip_event_right_edge(view, item):
|
|||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(100, 50)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_h
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_h
|
||||
|
||||
|
||||
def test_hover_flip_event_top_edge_rotated_90(view, item):
|
||||
|
|
@ -676,12 +711,10 @@ def test_hover_flip_event_top_edge_rotated_90(view, item):
|
|||
item.setRotation(90)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(50, 0)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_h
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_h
|
||||
|
||||
|
||||
def test_hover_flip_event_left_edge_when_rotated_90(view, item):
|
||||
|
|
@ -690,12 +723,10 @@ def test_hover_flip_event_left_edge_when_rotated_90(view, item):
|
|||
item.setSelected(True)
|
||||
item.setRotation(90)
|
||||
event.pos.return_value = QtCore.QPointF(0, 50)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_v
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == BeeAssets().cursor_flip_v
|
||||
|
||||
|
||||
def test_hover_move_event_not_in_handles(view, item):
|
||||
|
|
@ -703,12 +734,10 @@ def test_hover_move_event_not_in_handles(view, item):
|
|||
item.setSelected(True)
|
||||
event = MagicMock()
|
||||
event.pos.return_value = QtCore.QPointF(50, 50)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == Qt.CursorShape.ArrowCursor
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.hoverMoveEvent(event)
|
||||
assert item.cursor() == Qt.CursorShape.ArrowCursor
|
||||
|
||||
|
||||
def test_hover_enter_event_when_selected(view, item):
|
||||
|
|
@ -772,17 +801,15 @@ def test_mouse_press_event_bottomright_scale(view, item):
|
|||
event.pos.return_value = QtCore.QPointF(99, 79)
|
||||
event.scenePos.return_value = QtCore.QPointF(101, 81)
|
||||
event.button.return_value = Qt.MouseButton.LeftButton
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.mousePressEvent(event)
|
||||
assert item.scale_active is True
|
||||
assert item.event_start == QtCore.QPointF(101, 81)
|
||||
assert item.event_direction.x() > 0
|
||||
assert item.event_direction.y() > 0
|
||||
assert item.scale_orig_factor == 1
|
||||
event.accept.assert_called_once_with()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.mousePressEvent(event)
|
||||
assert item.scale_active is True
|
||||
assert item.event_start == QtCore.QPointF(101, 81)
|
||||
assert item.event_direction.x() > 0
|
||||
assert item.event_direction.y() > 0
|
||||
assert item.scale_orig_factor == 1
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
def test_mouse_press_event_rotate(view, item):
|
||||
|
|
@ -792,10 +819,9 @@ def test_mouse_press_event_rotate(view, item):
|
|||
event.pos.return_value = QtCore.QPointF(111, 91)
|
||||
event.scenePos.return_value = QtCore.QPointF(66, 99)
|
||||
event.button.return_value = Qt.MouseButton.LeftButton
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.mousePressEvent'):
|
||||
item.mousePressEvent(event)
|
||||
assert item.rotate_active is True
|
||||
assert item.event_anchor == QtCore.QPointF(50, 40)
|
||||
|
|
@ -810,12 +836,10 @@ def test_mouse_press_event_flip(view, item):
|
|||
event.pos.return_value = QtCore.QPointF(0, 40)
|
||||
event.button.return_value = Qt.MouseButton.LeftButton
|
||||
view.scene.undo_stack = MagicMock(push=MagicMock())
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.mousePressEvent'):
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.mousePressEvent(event)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.mousePressEvent'):
|
||||
item.mousePressEvent(event)
|
||||
args = view.scene.undo_stack.push.call_args_list[0][0]
|
||||
cmd = args[0]
|
||||
isinstance(cmd, commands.FlipItems)
|
||||
|
|
@ -893,14 +917,12 @@ def test_mouse_move_event_when_scale_action(view, item):
|
|||
item.scale_orig_factor = 1
|
||||
|
||||
with patch('PyQt6.QtWidgets.QGraphicsPixmapItem.mouseMoveEvent') as m:
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.mouseMoveEvent(event)
|
||||
m.assert_not_called()
|
||||
assert item.scale() == approx(1.5, 0.01)
|
||||
event.accept.assert_called_once_with()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.mouseMoveEvent(event)
|
||||
m.assert_not_called()
|
||||
assert item.scale() == approx(1.5, 0.01)
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
def test_mouse_move_event_when_rotate_action(view, item):
|
||||
|
|
@ -955,21 +977,19 @@ def test_mouse_release_event_when_scale_action(view, item):
|
|||
item.scale_orig_factor = 1
|
||||
view.scene.undo_stack = MagicMock(push=MagicMock())
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.mouseReleaseEvent(event)
|
||||
view.scene.undo_stack.push.assert_called_once()
|
||||
args = view.scene.undo_stack.push.call_args_list[0][0]
|
||||
cmd = args[0]
|
||||
isinstance(cmd, commands.ScaleItemsBy)
|
||||
assert cmd.items == [item]
|
||||
assert cmd.factor == approx(1.5, 0.01)
|
||||
assert cmd.anchor == QtCore.QPointF(100, 80)
|
||||
assert cmd.ignore_first_redo is True
|
||||
assert item.scale_active is False
|
||||
event.accept.assert_called_once_with()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.mouseReleaseEvent(event)
|
||||
view.scene.undo_stack.push.assert_called_once()
|
||||
args = view.scene.undo_stack.push.call_args_list[0][0]
|
||||
cmd = args[0]
|
||||
isinstance(cmd, commands.ScaleItemsBy)
|
||||
assert cmd.items == [item]
|
||||
assert cmd.factor == approx(1.5, 0.01)
|
||||
assert cmd.anchor == QtCore.QPointF(100, 80)
|
||||
assert cmd.ignore_first_redo is True
|
||||
assert item.scale_active is False
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
def test_mouse_release_event_when_scale_action_zero(view, item):
|
||||
|
|
@ -983,14 +1003,12 @@ def test_mouse_release_event_when_scale_action_zero(view, item):
|
|||
item.scale_orig_factor = 1
|
||||
view.scene.undo_stack = MagicMock(push=MagicMock())
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.mouseReleaseEvent(event)
|
||||
view.scene.undo_stack.push.assert_not_called()
|
||||
assert item.scale_active is False
|
||||
event.accept.assert_called_once_with()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.mouseReleaseEvent(event)
|
||||
view.scene.undo_stack.push.assert_not_called()
|
||||
assert item.scale_active is False
|
||||
event.accept.assert_called_once_with()
|
||||
|
||||
|
||||
def test_mouse_release_event_when_rotate_action(view, item):
|
||||
|
|
@ -1039,11 +1057,9 @@ def test_mouse_release_event_when_flip_action(view, item):
|
|||
item.flip_active = True
|
||||
view.scene.undo_stack = MagicMock(push=MagicMock())
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
item.mouseReleaseEvent(event)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
item.mouseReleaseEvent(event)
|
||||
view.scene.undo_stack.push.assert_not_called()
|
||||
assert item.flip_active is False
|
||||
event.accept.assert_called_once_with()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from unittest.mock import MagicMock, patch, PropertyMock
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from PyQt6 import QtCore, QtGui
|
||||
|
||||
from beeref import commands
|
||||
from beeref.items import BeePixmapItem
|
||||
from beeref.items import BeePixmapItem, BeeTextItem
|
||||
|
||||
|
||||
def test_insert_items(view):
|
||||
|
|
@ -36,10 +36,10 @@ def test_insert_items_with_position(view):
|
|||
item2.setPos(50, 40)
|
||||
view.scene.addItem(item2)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
command = commands.InsertItems(
|
||||
view.scene, [item1, item2], QtCore.QPointF(100, 200))
|
||||
command.redo()
|
||||
|
|
@ -231,10 +231,10 @@ def test_normalize_items(qapp):
|
|||
item1.setScale(1)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
item2.setScale(3)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
command = commands.NormalizeItems([item1, item2], [2, 0.5])
|
||||
command.redo()
|
||||
assert item1.scale() == 2
|
||||
|
|
@ -304,46 +304,42 @@ def test_flip_items_vertical(qapp):
|
|||
|
||||
def test_reset_scale(view, item):
|
||||
item.setScale(2)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
command = commands.ResetScale([item])
|
||||
command.redo()
|
||||
assert item.scale() == 1
|
||||
assert item.pos().x() == 50
|
||||
assert item.pos().y() == 40
|
||||
command.undo()
|
||||
assert item.scale() == 2
|
||||
assert item.pos().x() == 0
|
||||
assert item.pos().y() == 0
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
command = commands.ResetScale([item])
|
||||
command.redo()
|
||||
assert item.scale() == 1
|
||||
assert item.pos().x() == 50
|
||||
assert item.pos().y() == 40
|
||||
command.undo()
|
||||
assert item.scale() == 2
|
||||
assert item.pos().x() == 0
|
||||
assert item.pos().y() == 0
|
||||
|
||||
|
||||
def test_reset_rotate(view, item):
|
||||
item.setRotation(180)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
command = commands.ResetRotation([item])
|
||||
command.redo()
|
||||
assert item.rotation() == 0
|
||||
assert item.pos().x() == -100
|
||||
assert item.pos().y() == -80
|
||||
command.undo()
|
||||
assert item.rotation() == 180
|
||||
assert item.pos().x() == 0
|
||||
assert item.pos().y() == 0
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
command = commands.ResetRotation([item])
|
||||
command.redo()
|
||||
assert item.rotation() == 0
|
||||
assert item.pos().x() == -100
|
||||
assert item.pos().y() == -80
|
||||
command.undo()
|
||||
assert item.rotation() == 180
|
||||
assert item.pos().x() == 0
|
||||
assert item.pos().y() == 0
|
||||
|
||||
|
||||
def test_reset_flip(qapp):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
item1.do_flip()
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
command = commands.ResetFlip([item1, item2])
|
||||
command.redo()
|
||||
assert item1.flip() == 1
|
||||
|
|
@ -361,17 +357,53 @@ def test_reset_flip(qapp):
|
|||
assert item2.pos().y() == 0
|
||||
|
||||
|
||||
def test_reset_crop(qapp):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
item1.crop = QtCore.QRectF(10, 20, 30, 50)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
item2.crop = QtCore.QRectF(5, 6, 55, 66)
|
||||
with patch.object(BeePixmapItem, 'reset_crop'):
|
||||
command = commands.ResetCrop([item1, item2])
|
||||
command.redo()
|
||||
assert BeePixmapItem.reset_crop.call_count == 2
|
||||
assert item1.pos() == QtCore.QPointF(0, 0)
|
||||
assert item2.pos() == QtCore.QPointF(0, 0)
|
||||
|
||||
item1.crop = QtCore.QRectF(0, 0, 0, 0)
|
||||
item2.crop = QtCore.QRectF(0, 0, 0, 0)
|
||||
command.undo()
|
||||
assert item1.crop == QtCore.QRectF(10, 20, 30, 50)
|
||||
assert item1.pos() == QtCore.QPointF(0, 0)
|
||||
assert item2.crop == QtCore.QRectF(5, 6, 55, 66)
|
||||
assert item2.pos() == QtCore.QPointF(0, 0)
|
||||
|
||||
|
||||
def test_reset_crop_ignores_uncroppable(qapp):
|
||||
item = BeeTextItem('foo')
|
||||
brect = item.boundingRect()
|
||||
command = commands.ResetCrop([item])
|
||||
command.redo()
|
||||
assert item.pos() == QtCore.QPointF(0, 0)
|
||||
assert item.boundingRect() == brect
|
||||
command.undo()
|
||||
assert item.pos() == QtCore.QPointF(0, 0)
|
||||
assert item.boundingRect() == brect
|
||||
|
||||
|
||||
def test_reset_transforms(qapp):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
item1.setScale(2)
|
||||
item1.do_flip()
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
item2 = BeeTextItem('foo')
|
||||
item2.setRotation(180)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
command = commands.ResetTransforms([item1, item2])
|
||||
item3 = BeePixmapItem(QtGui.QImage())
|
||||
item3.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item3.reset_crop = MagicMock()
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
command = commands.ResetTransforms([item1, item2, item3])
|
||||
command.redo()
|
||||
assert item1.scale() == 1
|
||||
assert item1.rotation() == 0
|
||||
|
|
@ -383,6 +415,9 @@ def test_reset_transforms(qapp):
|
|||
assert item2.flip() == 1
|
||||
assert item2.pos().x() == -100
|
||||
assert item2.pos().y() == -80
|
||||
item3.reset_crop.assert_called_once_with()
|
||||
|
||||
item3.crop = QtCore.QRectF(0, 0, 0, 0)
|
||||
command.undo()
|
||||
assert item1.scale() == 2
|
||||
assert item1.rotation() == 0
|
||||
|
|
@ -394,6 +429,7 @@ def test_reset_transforms(qapp):
|
|||
assert item2.flip() == 1
|
||||
assert item2.pos().x() == 0
|
||||
assert item2.pos().y() == 0
|
||||
assert item3.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
|
||||
|
||||
def test_arrange_items(view):
|
||||
|
|
@ -403,18 +439,38 @@ def test_arrange_items(view):
|
|||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
item2.setRotation(90)
|
||||
view.scene.addItem(item2)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
command = commands.ArrangeItems(
|
||||
view.scene,
|
||||
[item1, item2],
|
||||
[QtCore.QPointF(1, 2), QtCore.QPointF(203, 204)])
|
||||
item3 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item3)
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item3, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(5, 5, 20, 30)):
|
||||
|
||||
command.redo()
|
||||
assert item1.pos() == QtCore.QPointF(101, 2)
|
||||
assert item2.pos() == QtCore.QPointF(283, 204)
|
||||
command.undo()
|
||||
assert item1.pos() == QtCore.QPointF(0, 0)
|
||||
assert item2.pos() == QtCore.QPointF(0, 0)
|
||||
command = commands.ArrangeItems(
|
||||
view.scene,
|
||||
[item1, item2, item3],
|
||||
[QtCore.QPointF(1, 2),
|
||||
QtCore.QPointF(203, 204),
|
||||
QtCore.QPointF(307, 308)])
|
||||
|
||||
command.redo()
|
||||
assert item1.pos() == QtCore.QPointF(101, 2)
|
||||
assert item2.pos() == QtCore.QPointF(283, 204)
|
||||
assert item3.pos() == QtCore.QPointF(302, 303)
|
||||
command.undo()
|
||||
assert item1.pos() == QtCore.QPointF(0, 0)
|
||||
assert item2.pos() == QtCore.QPointF(0, 0)
|
||||
assert item3.pos() == QtCore.QPointF(0, 0)
|
||||
|
||||
|
||||
def test_crop_item(item):
|
||||
item.crop = QtCore.QRectF(0, 0, 100, 80)
|
||||
command = commands.CropItem(item, QtCore.QRectF(10, 20, 30, 40))
|
||||
command.redo()
|
||||
assert item.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
assert item.pos() == QtCore.QPointF(0, 0)
|
||||
command.undo()
|
||||
assert item.crop == QtCore.QRectF(0, 0, 100, 80)
|
||||
assert item.pos() == QtCore.QPointF(0, 0)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import math
|
||||
from unittest.mock import patch, MagicMock, PropertyMock
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from pytest import approx
|
||||
|
||||
|
|
@ -17,6 +17,17 @@ def test_add_remove_item(view, item):
|
|||
assert view.scene.items() == []
|
||||
|
||||
|
||||
def test_cancel_crop_mode_when_crop(view, item):
|
||||
view.scene.crop_item = item
|
||||
item.exit_crop_mode = MagicMock()
|
||||
view.scene.cancel_crop_mode()
|
||||
item.exit_crop_mode.assert_called_once_with(confirm=False)
|
||||
|
||||
|
||||
def test_cancel_crop_mode_when_no_crop(view, item):
|
||||
view.scene.cancel_crop_mode()
|
||||
|
||||
|
||||
def test_copy_selection_to_internal_clipboard(view):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item1)
|
||||
|
|
@ -60,11 +71,13 @@ def test_raise_to_top(view):
|
|||
item3 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item3)
|
||||
item3.setZValue(0.07)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
view.scene.raise_to_top()
|
||||
assert item1.zValue() == 0.11 + view.scene.Z_STEP
|
||||
assert item2.zValue() == 0.07 + view.scene.Z_STEP
|
||||
assert item3.zValue() == 0.07
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_lower_to_bottom(view):
|
||||
|
|
@ -79,11 +92,13 @@ def test_lower_to_bottom(view):
|
|||
item3 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item3)
|
||||
item3.setZValue(-0.07)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
view.scene.lower_to_bottom()
|
||||
assert item1.zValue() == -0.11 - view.scene.Z_STEP
|
||||
assert item2.zValue() == -0.07 - view.scene.Z_STEP
|
||||
assert item3.zValue() == -0.07
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_height(view):
|
||||
|
|
@ -94,17 +109,19 @@ def test_normalize_height(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setScale(3)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
view.scene.normalize_height()
|
||||
|
||||
assert item1.scale() == 2
|
||||
assert item1.pos() == QtCore.QPointF(-50, -40)
|
||||
assert item2.scale() == 2
|
||||
assert item2.pos() == QtCore.QPointF(50, 40)
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_height_with_rotation(view):
|
||||
|
|
@ -115,19 +132,23 @@ def test_normalize_height_with_rotation(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setRotation(90)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 200)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 200)):
|
||||
view.scene.normalize_height()
|
||||
|
||||
assert item1.scale() == 0.75
|
||||
assert item2.scale() == 1.5
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_height_when_no_items(view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.normalize_height()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_width(view):
|
||||
|
|
@ -138,17 +159,19 @@ def test_normalize_width(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setScale(3)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 80, 100)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 80, 100)):
|
||||
view.scene.normalize_width()
|
||||
|
||||
assert item1.scale() == 2
|
||||
assert item1.pos() == QtCore.QPointF(-40, -50)
|
||||
assert item2.scale() == 2
|
||||
assert item2.pos() == QtCore.QPointF(40, 50)
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_width_with_rotation(view):
|
||||
|
|
@ -159,19 +182,23 @@ def test_normalize_width_with_rotation(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setRotation(90)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 200, 100)):
|
||||
view.scene.normalize_height()
|
||||
|
||||
assert item1.scale() == 1.5
|
||||
assert item2.scale() == 0.75
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_width_when_no_items(view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.normalize_width()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_size(view):
|
||||
|
|
@ -182,15 +209,17 @@ def test_normalize_size(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setScale(2)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
view.scene.normalize_size()
|
||||
|
||||
assert item1.scale() == approx(math.sqrt(2.5))
|
||||
assert item2.scale() == approx(math.sqrt(2.5))
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_size_with_rotation(view):
|
||||
|
|
@ -201,19 +230,23 @@ def test_normalize_size_with_rotation(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setRotation(90)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 200)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 200)):
|
||||
view.scene.normalize_size()
|
||||
|
||||
assert item1.scale() == 1
|
||||
assert item2.scale() == 1
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_normalize_size_when_no_items(view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.normalize_size()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_arrange_horizontal(view):
|
||||
|
|
@ -225,15 +258,17 @@ def test_arrange_horizontal(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setPos(-10, 40)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
view.scene.arrange()
|
||||
|
||||
assert item2.pos() == QtCore.QPointF(-50, -30)
|
||||
assert item1.pos() == QtCore.QPointF(50, -30)
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_arrange_vertical(view):
|
||||
|
|
@ -245,15 +280,17 @@ def test_arrange_vertical(view):
|
|||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setPos(-10, 40)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
view.scene.arrange(vertical=True)
|
||||
|
||||
assert item1.pos() == QtCore.QPointF(0, -70)
|
||||
assert item2.pos() == QtCore.QPointF(0, 10)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
|
||||
def test_arrange_when_rotated(view):
|
||||
|
|
@ -267,19 +304,23 @@ def test_arrange_when_rotated(view):
|
|||
item2.setSelected(True)
|
||||
item2.setPos(-10, 40)
|
||||
item2.setRotation(90)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 80)):
|
||||
view.scene.arrange()
|
||||
|
||||
assert item2.pos() == QtCore.QPointF(-40, -30)
|
||||
assert item1.pos() == QtCore.QPointF(40, -30)
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_arrange_when_no_items(view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.arrange()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_arrange_optimal(view):
|
||||
|
|
@ -287,17 +328,16 @@ def test_arrange_optimal(view):
|
|||
item = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
view.scene.arrange_optimal()
|
||||
item.crop = QtCore.QRectF(0, 0, 100, 80)
|
||||
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.arrange_optimal()
|
||||
expected_positions = {(-50, -40), (50, -40), (-50, 40), (50, 40)}
|
||||
actual_positions = {
|
||||
(i.pos().x(), i.pos().y())
|
||||
for i in view.scene.selectedItems(user_only=True)}
|
||||
assert expected_positions == actual_positions
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_arrange_optimal_when_rotated(view):
|
||||
|
|
@ -306,27 +346,30 @@ def test_arrange_optimal_when_rotated(view):
|
|||
view.scene.addItem(item)
|
||||
item.setRotation(90)
|
||||
item.setSelected(True)
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
view.scene.arrange_optimal()
|
||||
item.crop = QtCore.QRectF(0, 0, 100, 80)
|
||||
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.arrange_optimal()
|
||||
|
||||
expected_positions = {(-40, -50), (40, -50), (-40, 50), (40, 50)}
|
||||
actual_positions = {
|
||||
(i.pos().x(), i.pos().y())
|
||||
for i in view.scene.selectedItems(user_only=True)}
|
||||
assert expected_positions == actual_positions
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_arrange_optimal_when_no_items(view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.arrange_optimal()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_flip_items(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
view.scene.undo_stack = MagicMock(push=MagicMock())
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
with patch('beeref.scene.BeeGraphicsScene.itemsBoundingRect',
|
||||
return_value=QtCore.QRectF(10, 20, 100, 60)):
|
||||
view.scene.flip_items(vertical=True)
|
||||
|
|
@ -336,32 +379,86 @@ def test_flip_items(view, item):
|
|||
assert cmd.items == [item]
|
||||
assert cmd.anchor == QtCore.QPointF(60, 50)
|
||||
assert cmd.vertical is True
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_set_selection_all_items_when_true(view):
|
||||
def test_crop_items(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
item.enter_crop_mode = MagicMock()
|
||||
|
||||
view.scene.crop_items()
|
||||
item.enter_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_crop_items_when_in_crop_mode(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
item.enter_crop_mode = MagicMock()
|
||||
view.scene.crop_item = item
|
||||
|
||||
view.scene.crop_items()
|
||||
item.enter_crop_mode.assert_not_called()
|
||||
|
||||
|
||||
def test_crop_item_multi_select(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
item.enter_crop_mode = MagicMock()
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
|
||||
view.scene.crop_items()
|
||||
item.enter_crop_mode.assert_not_called()
|
||||
|
||||
|
||||
def test_crop_item_no_selection(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(False)
|
||||
item.enter_crop_mode = MagicMock()
|
||||
|
||||
view.scene.crop_items()
|
||||
item.enter_crop_mode.assert_not_called()
|
||||
|
||||
|
||||
def test_crop_item_when_not_croppable(view):
|
||||
item = BeeTextItem('foo')
|
||||
item.setSelected(True)
|
||||
item.enter_crop_mode = MagicMock()
|
||||
|
||||
view.scene.crop_items()
|
||||
item.enter_crop_mode.assert_not_called()
|
||||
|
||||
|
||||
def test_set_selected_all_items_when_true(view):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
view.scene.set_selected_all_items(True)
|
||||
assert item1.isSelected() is True
|
||||
assert item2.isSelected() is True
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_set_selection_all_items_when_false(view):
|
||||
def test_set_selected_all_items_when_false(view):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
view.scene.set_selected_all_items(False)
|
||||
assert item1.isSelected() is False
|
||||
assert item2.isSelected() is False
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_has_selection_when_no_selection(view, item):
|
||||
|
|
@ -423,6 +520,34 @@ def test_has_multi_selection_when_multi_selection(view):
|
|||
assert view.scene.has_multi_selection() is True
|
||||
|
||||
|
||||
def test_has_croppable_selection(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
assert view.scene.has_croppable_selection() is True
|
||||
|
||||
|
||||
def test_has_croppable_selection_when_item_not_croppable(view):
|
||||
item = BeeTextItem('foo')
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
assert view.scene.has_croppable_selection() is False
|
||||
|
||||
|
||||
def test_has_croppable_selection_when_no_selection(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(False)
|
||||
assert view.scene.has_croppable_selection() is False
|
||||
|
||||
|
||||
def test_has_croppable_selection_when_multi_selection(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
assert view.scene.has_croppable_selection() is False
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsScene.mousePressEvent')
|
||||
def test_mouse_press_event_when_right_click(mouse_mock, view):
|
||||
event = MagicMock(
|
||||
|
|
@ -461,7 +586,6 @@ def test_mouse_press_event_when_left_click_over_item_in_edit_mode(
|
|||
view.scene.mousePressEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
assert view.scene.edit_item == item
|
||||
item.exit_edit_mode.assert_not_called()
|
||||
assert view.scene.move_active is False
|
||||
assert view.scene.rubberband_active is False
|
||||
|
|
@ -481,7 +605,6 @@ def test_mouse_press_event_when_left_click_over_diff_item_in_edit_mode(
|
|||
view.scene.mousePressEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
assert view.scene.edit_item is None
|
||||
txtitem.exit_edit_mode.assert_called_once_with()
|
||||
assert view.scene.move_active is True
|
||||
assert view.scene.rubberband_active is False
|
||||
|
|
@ -501,12 +624,66 @@ def test_mouse_press_event_when_left_click_over_no_item_in_edit_mode(
|
|||
view.scene.mousePressEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
assert view.scene.edit_item is None
|
||||
item.exit_edit_mode.assert_called_once_with()
|
||||
assert view.scene.move_active is False
|
||||
assert view.scene.rubberband_active is True
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsScene.mousePressEvent')
|
||||
def test_mouse_press_event_when_left_click_over_item_in_crop_mode(
|
||||
mouse_mock, view, item):
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.crop_item = item
|
||||
view.scene.itemAt = MagicMock(return_value=item)
|
||||
event = MagicMock(
|
||||
button=MagicMock(return_value=Qt.MouseButton.LeftButton),
|
||||
)
|
||||
view.scene.mousePressEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
view.scene.cancel_crop_mode.assert_not_called()
|
||||
assert view.scene.move_active is False
|
||||
assert view.scene.rubberband_active is False
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsScene.mousePressEvent')
|
||||
def test_mouse_press_event_when_left_click_over_diff_item_in_crop_mode(
|
||||
mouse_mock, view, item):
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.crop_item = item
|
||||
other_item = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.itemAt = MagicMock(return_value=other_item)
|
||||
event = MagicMock(
|
||||
button=MagicMock(return_value=Qt.MouseButton.LeftButton),
|
||||
)
|
||||
view.scene.mousePressEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
assert view.scene.move_active is True
|
||||
assert view.scene.rubberband_active is False
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsScene.mousePressEvent')
|
||||
def test_mouse_press_event_when_left_click_over_no_item_in_crop_mode(
|
||||
mouse_mock, view, item):
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.crop_item = item
|
||||
view.scene.itemAt = MagicMock(return_value=None)
|
||||
event = MagicMock(
|
||||
button=MagicMock(return_value=Qt.MouseButton.LeftButton),
|
||||
)
|
||||
view.scene.mousePressEvent(event)
|
||||
event.accept.assert_not_called()
|
||||
mouse_mock.assert_called_once_with(event)
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
assert view.scene.move_active is False
|
||||
assert view.scene.rubberband_active is True
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsScene.mousePressEvent')
|
||||
def test_mouse_press_event_when_left_click_not_over_item(
|
||||
mouse_mock, view, item):
|
||||
|
|
@ -549,11 +726,9 @@ def test_mouse_doubleclick_event_when_over_item(mouse_mock, view, item):
|
|||
view.scene.itemAt = MagicMock(return_value=item)
|
||||
view.fit_rect = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
view.scene.mouseDoubleClickEvent(event)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
view.scene.mouseDoubleClickEvent(event)
|
||||
|
||||
assert view.scene.move_active is False
|
||||
view.fit_rect.assert_called_once_with(
|
||||
|
|
@ -575,15 +750,12 @@ def test_mouse_doubleclick_event_when_over_editable_item(
|
|||
view.scene.itemAt = MagicMock(return_value=item)
|
||||
view.fit_rect = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
view.scene.mouseDoubleClickEvent(event)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
view.scene.mouseDoubleClickEvent(event)
|
||||
|
||||
assert view.scene.move_active is False
|
||||
item.enter_edit_mode.assert_called_once_with()
|
||||
view.scene.edit_item == item
|
||||
double_mock.assert_not_called()
|
||||
press_mock.assert_called_once_with(event)
|
||||
|
||||
|
|
@ -599,11 +771,9 @@ def test_mouse_doubleclick_event_when_item_not_selected(
|
|||
view.scene.itemAt = MagicMock(return_value=item)
|
||||
view.fit_rect = MagicMock()
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
view.scene.mouseDoubleClickEvent(event)
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
view.scene.mouseDoubleClickEvent(event)
|
||||
|
||||
assert view.scene.move_active is False
|
||||
view.fit_rect.assert_called_once_with(
|
||||
|
|
@ -863,10 +1033,10 @@ def test_items_bounding_rect_given_items(view):
|
|||
item3.setSelected(True)
|
||||
item3.setPos(1000, 1000)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
rect = view.scene.itemsBoundingRect(items=[item1, item2])
|
||||
|
||||
assert rect.topLeft().x() == -33
|
||||
|
|
@ -889,10 +1059,10 @@ def test_items_bounding_rect_two_items_selection_only(view):
|
|||
item3.setSelected(False)
|
||||
item3.setPos(1000, 1000)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch.object(item1, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
with patch.object(item2, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
rect = view.scene.itemsBoundingRect(selection_only=True)
|
||||
|
||||
assert rect.topLeft().x() == -33
|
||||
|
|
@ -905,11 +1075,9 @@ def test_items_bounding_rect_rotated_item(view, item):
|
|||
view.scene.addItem(item)
|
||||
item.setRotation(-45)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
rect = view.scene.itemsBoundingRect()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 100, 100)):
|
||||
rect = view.scene.itemsBoundingRect()
|
||||
|
||||
assert rect.topLeft().x() == 0
|
||||
assert rect.topLeft().y() == approx(-math.sqrt(2) * 50)
|
||||
|
|
@ -921,11 +1089,9 @@ def test_items_bounding_rect_flipped_item(view):
|
|||
item = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item)
|
||||
item.do_flip()
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=50):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
rect = view.scene.itemsBoundingRect()
|
||||
with patch.object(item, 'bounding_rect_unselected',
|
||||
return_value=QtCore.QRectF(0, 0, 50, 100)):
|
||||
rect = view.scene.itemsBoundingRect()
|
||||
|
||||
assert rect.topLeft().x() == -50
|
||||
assert rect.topLeft().y() == 0
|
||||
|
|
|
|||
|
|
@ -182,6 +182,8 @@ def test_on_action_open(dialog_mock, view, qtbot):
|
|||
filename = os.path.join(root, 'assets', 'test1item.bee')
|
||||
dialog_mock.return_value = (filename, None)
|
||||
view.on_loading_finished = MagicMock()
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
|
||||
view.on_action_open()
|
||||
qtbot.waitUntil(lambda: view.on_loading_finished.called is True)
|
||||
assert len(view.scene.items()) == 1
|
||||
|
|
@ -189,26 +191,31 @@ def test_on_action_open(dialog_mock, view, qtbot):
|
|||
assert item.isSelected() is False
|
||||
assert item.pixmap()
|
||||
view.on_loading_finished.assert_called_once_with(filename, [])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QFileDialog.getOpenFileName')
|
||||
@patch('beeref.view.BeeGraphicsView.on_action_open')
|
||||
def test_on_action_open_when_no_filename(dialog_mock, open_mock, view):
|
||||
@patch('beeref.view.BeeGraphicsView.open_from_file')
|
||||
def test_on_action_open_when_no_filename(open_mock, dialog_mock, view):
|
||||
dialog_mock.return_value = (None, None)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_open()
|
||||
open_mock.assert_not_called()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
||||
def test_on_action_save_as(dialog_mock, view, imgfilename3x3, tmpdir):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
filename = os.path.join(tmpdir, 'test.bee')
|
||||
assert os.path.exists(filename) is False
|
||||
dialog_mock.return_value = (filename, None)
|
||||
view.on_action_save_as()
|
||||
view.worker.wait()
|
||||
assert os.path.exists(filename) is True
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
||||
|
|
@ -217,9 +224,11 @@ def test_on_action_save_as_when_no_filename(
|
|||
save_mock, dialog_mock, view, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
dialog_mock.return_value = (None, None)
|
||||
view.on_action_save_as()
|
||||
save_mock.assert_not_called()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
||||
|
|
@ -227,6 +236,7 @@ def test_on_action_save_as_filename_doesnt_end_with_bee(
|
|||
dialog_mock, view, qtbot, imgfilename3x3, tmpdir):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_saving_finished = MagicMock()
|
||||
filename = os.path.join(tmpdir, 'test')
|
||||
assert os.path.exists(filename) is False
|
||||
|
|
@ -235,6 +245,7 @@ def test_on_action_save_as_filename_doesnt_end_with_bee(
|
|||
qtbot.waitUntil(lambda: view.on_saving_finished.called is True)
|
||||
assert os.path.exists(f'{filename}.bee') is True
|
||||
view.on_saving_finished.assert_called_once_with(f'{filename}.bee', [])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
||||
|
|
@ -244,17 +255,20 @@ def test_on_action_save_as_when_error(
|
|||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.on_saving_finished = MagicMock()
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
filename = os.path.join(tmpdir, 'test.bee')
|
||||
dialog_mock.return_value = (filename, None)
|
||||
save_mock.side_effect = sqlite3.Error('foo')
|
||||
view.on_action_save_as()
|
||||
qtbot.waitUntil(lambda: view.on_saving_finished.called is True)
|
||||
view.on_saving_finished.assert_called_once_with(filename, ['foo'])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
def test_on_action_save(view, qtbot, imgfilename3x3, tmpdir):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.filename = os.path.join(tmpdir, 'test.bee')
|
||||
root = os.path.dirname(__file__)
|
||||
shutil.copyfile(os.path.join(root, 'assets', 'test1item.bee'),
|
||||
|
|
@ -264,15 +278,18 @@ def test_on_action_save(view, qtbot, imgfilename3x3, tmpdir):
|
|||
qtbot.waitUntil(lambda: view.on_saving_finished.called is True)
|
||||
assert os.path.exists(view.filename) is True
|
||||
view.on_saving_finished.assert_called_once_with(view.filename, [])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.view.BeeGraphicsView.on_action_save_as')
|
||||
def test_on_action_save_when_no_filename(save_as_mock, view, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.filename = None
|
||||
view.on_action_save()
|
||||
save_as_mock.assert_called_once_with()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.widgets.HelpDialog.show')
|
||||
|
|
@ -295,6 +312,7 @@ def test_on_action_insert_images_new_scene(
|
|||
dialog_mock, clear_mock, view, imgfilename3x3, qtbot):
|
||||
dialog_mock.return_value = ([imgfilename3x3], None)
|
||||
view.on_insert_images_finished = MagicMock()
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_insert_images()
|
||||
qtbot.waitUntil(lambda: view.on_insert_images_finished.called is True)
|
||||
assert len(view.scene.items()) == 1
|
||||
|
|
@ -303,6 +321,7 @@ def test_on_action_insert_images_new_scene(
|
|||
assert item.pixmap()
|
||||
clear_mock.assert_called_once_with()
|
||||
view.on_insert_images_finished.assert_called_once_with(True, '', [])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.scene.BeeGraphicsScene.clearSelection')
|
||||
|
|
@ -312,6 +331,7 @@ def test_on_action_insert_images_existing_scene(
|
|||
view.scene.addItem(item)
|
||||
dialog_mock.return_value = ([imgfilename3x3], None)
|
||||
view.on_insert_images_finished = MagicMock()
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_insert_images()
|
||||
qtbot.waitUntil(lambda: view.on_insert_images_finished.called is True)
|
||||
assert len(view.scene.items()) == 2
|
||||
|
|
@ -320,6 +340,7 @@ def test_on_action_insert_images_existing_scene(
|
|||
assert item.pixmap()
|
||||
clear_mock.assert_called_once_with()
|
||||
view.on_insert_images_finished.assert_called_once_with(False, '', [])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.scene.BeeGraphicsScene.clearSelection')
|
||||
|
|
@ -328,6 +349,7 @@ def test_on_action_insert_images_when_error(
|
|||
dialog_mock, clear_mock, view, imgfilename3x3, qtbot):
|
||||
dialog_mock.return_value = ([imgfilename3x3, 'iaeiae', 'trntrn'], None)
|
||||
view.on_insert_images_finished = MagicMock()
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_insert_images()
|
||||
qtbot.waitUntil(lambda: view.on_insert_images_finished.called is True)
|
||||
assert len(view.scene.items()) == 1
|
||||
|
|
@ -337,22 +359,26 @@ def test_on_action_insert_images_when_error(
|
|||
clear_mock.assert_called_once_with()
|
||||
view.on_insert_images_finished.assert_called_once_with(
|
||||
True, '', ['iaeiae', 'trntrn'])
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.scene.BeeGraphicsScene.clearSelection')
|
||||
def test_on_action_insert_text(clear_mock, view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_insert_text()
|
||||
clear_mock.assert_called_once_with()
|
||||
assert len(view.scene.items()) == 1
|
||||
item = view.scene.items()[0]
|
||||
assert item.toPlainText() == 'Text'
|
||||
assert item.isSelected() is True
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QApplication.clipboard')
|
||||
def test_on_action_copy_image(clipboard_mock, view, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
item.setSelected(True)
|
||||
mimedata = QtCore.QMimeData()
|
||||
clipboard_mock.return_value.mimeData.return_value = mimedata
|
||||
|
|
@ -361,12 +387,14 @@ def test_on_action_copy_image(clipboard_mock, view, imgfilename3x3):
|
|||
clipboard_mock.return_value.setPixmap.assert_called_once()
|
||||
view.scene.internal_clipboard == [item]
|
||||
assert mimedata.data('beeref/items') == b'1'
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QApplication.clipboard')
|
||||
def test_on_action_copy_text(clipboard_mock, view, imgfilename3x3):
|
||||
item = BeeTextItem('foo bar')
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
item.setSelected(True)
|
||||
mimedata = QtCore.QMimeData()
|
||||
clipboard_mock.return_value.mimeData.return_value = mimedata
|
||||
|
|
@ -375,6 +403,7 @@ def test_on_action_copy_text(clipboard_mock, view, imgfilename3x3):
|
|||
clipboard_mock.return_value.setText.assert_called_once_with('foo bar')
|
||||
view.scene.internal_clipboard == [item]
|
||||
assert mimedata.data('beeref/items') == b'1'
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.view.BeeGraphicsView.on_action_fit_scene')
|
||||
|
|
@ -383,10 +412,12 @@ def test_on_action_copy_text(clipboard_mock, view, imgfilename3x3):
|
|||
def test_on_action_paste_external_new_scene(
|
||||
clipboard_mock, clear_mock, fit_mock, view, imgfilename3x3):
|
||||
clipboard_mock.return_value = QtGui.QImage(imgfilename3x3)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_paste()
|
||||
assert len(view.scene.items()) == 1
|
||||
assert view.scene.items()[0].isSelected() is True
|
||||
fit_mock.assert_called_once_with()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.view.BeeGraphicsView.on_action_fit_scene')
|
||||
|
|
@ -395,12 +426,14 @@ def test_on_action_paste_external_new_scene(
|
|||
def test_on_action_paste_external_existing_scene(
|
||||
clipboard_mock, clear_mock, fit_mock, view, item, imgfilename3x3):
|
||||
view.scene.addItem(item)
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
clipboard_mock.return_value = QtGui.QImage(imgfilename3x3)
|
||||
view.on_action_paste()
|
||||
assert len(view.scene.items()) == 2
|
||||
assert view.scene.items()[0].isSelected() is True
|
||||
assert view.scene.items()[1].isSelected() is False
|
||||
fit_mock.assert_not_called()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.scene.BeeGraphicsScene.clearSelection')
|
||||
|
|
@ -411,10 +444,12 @@ def test_on_action_paste_internal(mimedata_mock, clear_mock, view):
|
|||
mimedata_mock.return_value = mimedata
|
||||
item = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.internal_clipboard = [item]
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_paste()
|
||||
assert len(view.scene.items()) == 1
|
||||
assert view.scene.items()[0].isSelected() is True
|
||||
clear_mock.assert_called_once_with()
|
||||
view.scene.cancel_crop_mode.assert_called()
|
||||
|
||||
|
||||
@patch('beeref.scene.BeeGraphicsScene.clearSelection')
|
||||
|
|
@ -423,22 +458,26 @@ def test_on_action_paste_internal(mimedata_mock, clear_mock, view):
|
|||
def test_on_action_paste_when_text(img_mock, text_mock, clear_mock, view):
|
||||
img_mock.return_value = QtGui.QImage()
|
||||
text_mock.return_value = 'foo bar'
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.on_action_paste()
|
||||
assert len(view.scene.items()) == 1
|
||||
assert view.scene.items()[0].isSelected() is True
|
||||
assert view.scene.items()[0].toPlainText() == 'foo bar'
|
||||
clear_mock.assert_called_once_with()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.scene.BeeGraphicsScene.clearSelection')
|
||||
@patch('PyQt6.QtGui.QClipboard.text')
|
||||
@patch('PyQt6.QtGui.QClipboard.image')
|
||||
def test_on_action_paste_when_empty(img_mock, text_mock, clear_mock, view):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
img_mock.return_value = QtGui.QImage()
|
||||
text_mock.return_value = ''
|
||||
view.on_action_paste()
|
||||
assert len(view.scene.items()) == 0
|
||||
clear_mock.assert_not_called()
|
||||
view.scene.cancel_crop_mode.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('beeref.view.BeeGraphicsView.on_action_copy')
|
||||
|
|
@ -508,11 +547,13 @@ def test_on_action_show_titlebar_unchecked(
|
|||
|
||||
|
||||
def test_on_action_delete_items(view, item):
|
||||
view.scene.cancel_crop_mode = MagicMock()
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
view.on_action_delete_items()
|
||||
assert view.scene.items() == []
|
||||
assert view.undo_stack.isClean() is False
|
||||
view.scene.cancel_crop_mode.assert_called_once()
|
||||
|
||||
|
||||
@patch('PyQt6.QtGui.QUndoStack.isClean', return_value=True)
|
||||
|
|
|
|||
Loading…
Reference in a new issue