mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Add ability to change opacity
This commit is contained in:
parent
9c506aadaa
commit
3769531493
15 changed files with 254 additions and 32 deletions
|
|
@ -6,12 +6,14 @@ Added
|
|||
|
||||
* For arranging, a gap between images can now be configured in the
|
||||
settings.
|
||||
* The opacity of images can now be changed (Images -> Change Opacity).
|
||||
|
||||
|
||||
Fixed:
|
||||
------
|
||||
|
||||
* Scene Export: Fix output image size and margins when scene had been
|
||||
scaled or moved
|
||||
scaled or moved.
|
||||
* Scene Export: Selecting filename without file extension now
|
||||
automatically appends the extension from the selected filter istead
|
||||
of resulting in a confusing error message.
|
||||
|
|
|
|||
|
|
@ -154,12 +154,18 @@ actions = [
|
|||
'callback': 'on_action_arrange_vertical',
|
||||
'group': 'active_when_selection',
|
||||
},
|
||||
{
|
||||
'id': 'change_opacity',
|
||||
'text': 'Change &Opacity...',
|
||||
'callback': 'on_action_change_opacity',
|
||||
'group': 'active_when_selection',
|
||||
},
|
||||
{
|
||||
'id': 'crop',
|
||||
'text': '&Crop',
|
||||
'shortcuts': ['Shift+C'],
|
||||
'callback': 'on_action_crop',
|
||||
'group': 'active_when_croppable',
|
||||
'group': 'active_when_single_image',
|
||||
},
|
||||
{
|
||||
'id': 'flip_horizontally',
|
||||
|
|
|
|||
|
|
@ -103,6 +103,12 @@ menu_structure = [
|
|||
'arrange_vertical',
|
||||
],
|
||||
},
|
||||
{
|
||||
'menu': '&Images',
|
||||
'items': [
|
||||
'change_opacity',
|
||||
],
|
||||
},
|
||||
{
|
||||
'menu': '&Settings',
|
||||
'items': [
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ class InsertItems(QtGui.QUndoCommand):
|
|||
self.scene = scene
|
||||
self.items = items
|
||||
self.position = position
|
||||
self.old_positions = []
|
||||
self.ignore_first_redo = ignore_first_redo
|
||||
|
||||
def redo(self):
|
||||
|
|
@ -31,6 +30,7 @@ class InsertItems(QtGui.QUndoCommand):
|
|||
self.ignore_first_redo = False
|
||||
return
|
||||
if self.position:
|
||||
self.old_positions = []
|
||||
rect = self.scene.itemsBoundingRect(items=self.items)
|
||||
for item in self.items:
|
||||
self.old_positions.append(item.pos())
|
||||
|
|
@ -226,7 +226,7 @@ class ResetCrop(QtGui.QUndoCommand):
|
|||
|
||||
def __init__(self, items):
|
||||
super().__init__('Reset Crop')
|
||||
self.items = [item for item in items if item.is_croppable]
|
||||
self.items = [item for item in items if item.is_image]
|
||||
|
||||
def redo(self):
|
||||
self.old_crops = []
|
||||
|
|
@ -253,7 +253,7 @@ class ResetTransforms(QtGui.QUndoCommand):
|
|||
'rotation': item.rotation(),
|
||||
'flip': item.flip(),
|
||||
}
|
||||
if item.is_croppable:
|
||||
if item.is_image:
|
||||
values['crop'] = item.crop
|
||||
item.reset_crop()
|
||||
self.old_values.append(values)
|
||||
|
|
@ -269,7 +269,7 @@ 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:
|
||||
if item.is_image:
|
||||
item.crop = old['crop']
|
||||
|
||||
|
||||
|
|
@ -322,3 +322,26 @@ class ChangeText(QtGui.QUndoCommand):
|
|||
|
||||
def undo(self):
|
||||
self.item.setPlainText(self.old_text)
|
||||
|
||||
|
||||
class ChangeOpacity(QtGui.QUndoCommand):
|
||||
"""Change Opacity."""
|
||||
|
||||
def __init__(self, items, opacity, ignore_first_redo=False):
|
||||
super().__init__('Change Opacity')
|
||||
self.ignore_first_redo = ignore_first_redo
|
||||
self.items = list(filter(lambda item: item.is_image, items))
|
||||
self.opacity = opacity
|
||||
self.old_opacities = [item.opacity() for item in items]
|
||||
|
||||
def redo(self):
|
||||
if self.ignore_first_redo:
|
||||
self.ignore_first_redo = False
|
||||
return
|
||||
|
||||
for item in self.items:
|
||||
item.setOpacity(self.opacity)
|
||||
|
||||
def undo(self):
|
||||
for item, opacity in zip(self.items, self.old_opacities):
|
||||
item.setOpacity(opacity)
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
self.filename = filename
|
||||
self.reset_crop()
|
||||
logger.debug(f'Initialized {self}')
|
||||
self.is_croppable = True
|
||||
self.is_image = True
|
||||
self.crop_mode = False
|
||||
self.init_selectable()
|
||||
self.settings = BeeSettings()
|
||||
|
|
@ -101,6 +101,7 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
item.filename = item.filename or data.get('filename')
|
||||
if 'crop' in data:
|
||||
item.crop = QtCore.QRectF(*data['crop'])
|
||||
item.setOpacity(data.get('opacity', 1))
|
||||
return item
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -126,6 +127,7 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
|
||||
def get_extra_save_data(self):
|
||||
return {'filename': self.filename,
|
||||
'opacity': self.opacity(),
|
||||
'crop': [self.crop.topLeft().x(),
|
||||
self.crop.topLeft().y(),
|
||||
self.crop.width(),
|
||||
|
|
@ -174,6 +176,7 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
|||
item.setZValue(self.zValue())
|
||||
item.setScale(self.scale())
|
||||
item.setRotation(self.rotation())
|
||||
item.setOpacity(self.opacity())
|
||||
if self.flip() == -1:
|
||||
item.do_flip()
|
||||
item.crop = self.crop
|
||||
|
|
@ -494,7 +497,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.is_image = False
|
||||
self.init_selectable()
|
||||
self.is_editable = True
|
||||
self.edit_mode = False
|
||||
|
|
|
|||
|
|
@ -252,9 +252,9 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
|
||||
if self.crop_item:
|
||||
return
|
||||
if self.has_croppable_selection():
|
||||
if self.has_single_image_selection():
|
||||
item = self.selectedItems(user_only=True)[0]
|
||||
if item.is_croppable:
|
||||
if item.is_image:
|
||||
item.enter_crop_mode()
|
||||
|
||||
def set_selected_all_items(self, value):
|
||||
|
|
@ -278,12 +278,11 @@ 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."""
|
||||
def has_single_image_selection(self):
|
||||
"""Checks whether the current selection is a single image."""
|
||||
|
||||
if self.has_single_selection():
|
||||
return self.selectedItems(user_only=True)[0].is_croppable
|
||||
return self.selectedItems(user_only=True)[0].is_image
|
||||
return False
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
|
|
@ -455,7 +454,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
self.items_to_add.put((itemdata, selected))
|
||||
|
||||
def add_queued_items(self):
|
||||
"""Adds items added via ``add_items_later``"""
|
||||
"""Adds items added via ``add_item_later``"""
|
||||
|
||||
while not self.items_to_add.empty():
|
||||
data, selected = self.items_to_add.get()
|
||||
|
|
@ -467,6 +466,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
cls = item_registry.get('text')
|
||||
data['data'] = {'text': f'Item of unknown type: {typ}'}
|
||||
item = cls.create_from_data(**data)
|
||||
# Set the values common to all item types:
|
||||
item.update_from_data(**data)
|
||||
self.addItem(item)
|
||||
# Force recalculation of min/max z values:
|
||||
|
|
|
|||
|
|
@ -281,6 +281,12 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
def on_action_arrange_optimal(self):
|
||||
self.scene.arrange_optimal()
|
||||
|
||||
def on_action_change_opacity(self):
|
||||
images = list(filter(
|
||||
lambda item: item.is_image,
|
||||
self.scene.selectedItems(user_only=True)))
|
||||
widgets.ChangeOpacityDialog(self, images, self.undo_stack)
|
||||
|
||||
def on_action_crop(self):
|
||||
self.scene.crop_items()
|
||||
|
||||
|
|
@ -575,8 +581,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.actiongroup_set_enabled('active_when_single_image',
|
||||
self.scene.has_single_image_selection())
|
||||
self.viewport().repaint()
|
||||
|
||||
def recalc_scene_rect(self):
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import os.path
|
|||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref import constants
|
||||
from beeref import constants, commands
|
||||
from beeref.config import logfile_name
|
||||
from beeref.widgets import settings, welcome_overlay # noqa: F401
|
||||
|
||||
|
|
@ -187,3 +187,55 @@ class SceneToPixmapExporterDialog(QtWidgets.QDialog):
|
|||
def value(self):
|
||||
return QtCore.QSize(self.width_input.value(),
|
||||
self.height_input.value())
|
||||
|
||||
|
||||
class ChangeOpacityDialog(QtWidgets.QDialog):
|
||||
|
||||
def __init__(self, parent, images, undo_stack):
|
||||
super().__init__(parent)
|
||||
self.undo_stack = undo_stack
|
||||
self.images = images
|
||||
self.command = commands.ChangeOpacity(images, opacity=1)
|
||||
|
||||
value = int(images[0].opacity() * 100) if images else 100
|
||||
|
||||
self.setWindowTitle('Change Opacity:')
|
||||
self.setWindowModality(Qt.WindowModality.WindowModal)
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
self.label = QtWidgets.QLabel('Opacity:')
|
||||
layout.addWidget(self.label)
|
||||
|
||||
self.input = QtWidgets.QSlider(Qt.Orientation.Horizontal)
|
||||
self.input.valueChanged.connect(self.on_value_changed)
|
||||
self.input.setRange(0, 100)
|
||||
self.input.setValue(value)
|
||||
layout.addWidget(self.input)
|
||||
|
||||
# Bottom row of buttons
|
||||
buttons = QtWidgets.QDialogButtonBox(
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Ok |
|
||||
QtWidgets.QDialogButtonBox.StandardButton.Cancel)
|
||||
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
self.show()
|
||||
|
||||
def on_value_changed(self, value):
|
||||
self.label.setText(f'Opacity: {value}%')
|
||||
self.command.opacity = value / 100
|
||||
self.command.redo()
|
||||
|
||||
def accept(self):
|
||||
if self.images:
|
||||
logger.debug(f'Setting opacity to {self.command.opacity}')
|
||||
self.command.ignore_first_redo = True
|
||||
self.undo_stack.push(self.command)
|
||||
return super().accept()
|
||||
|
||||
def reject(self):
|
||||
self.command.undo()
|
||||
return super().reject()
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ def test_sqliteio_write_inserts_new_text_item(tmpfile, view):
|
|||
def test_sqliteio_write_inserts_new_pixmap_item_png(tmpfile, view):
|
||||
item = BeePixmapItem(QtGui.QImage(), filename='bee.jpg')
|
||||
view.scene.addItem(item)
|
||||
item.setOpacity(0.66)
|
||||
item.setScale(1.3)
|
||||
item.setPos(44, 55)
|
||||
item.setZValue(0.22)
|
||||
|
|
@ -253,6 +254,7 @@ def test_sqliteio_write_inserts_new_pixmap_item_png(tmpfile, view):
|
|||
assert json.loads(result[6]) == {
|
||||
'filename': 'bee.jpg',
|
||||
'crop': [5, 5, 100, 80],
|
||||
'opacity': 0.66,
|
||||
}
|
||||
assert result[7] == 'pixmap'
|
||||
assert result[8] == b'abc'
|
||||
|
|
@ -331,6 +333,7 @@ def test_sqliteio_write_updates_existing_pixmap_item(tmpfile, view):
|
|||
item.setPos(44, 55)
|
||||
item.setZValue(0.22)
|
||||
item.setRotation(33)
|
||||
item.setOpacity(0.2)
|
||||
item.save_id = 1
|
||||
item.crop = QtCore.QRectF(5, 5, 80, 100)
|
||||
item.pixmap_to_bytes = MagicMock(return_value=(b'abc', 'png'))
|
||||
|
|
@ -340,6 +343,7 @@ def test_sqliteio_write_updates_existing_pixmap_item(tmpfile, view):
|
|||
item.setPos(20, 30)
|
||||
item.setZValue(0.33)
|
||||
item.setRotation(100)
|
||||
item.setOpacity(0.75)
|
||||
item.do_flip()
|
||||
item.crop = QtCore.QRectF(1, 2, 30, 40)
|
||||
item.filename = 'new.png'
|
||||
|
|
@ -361,6 +365,7 @@ def test_sqliteio_write_updates_existing_pixmap_item(tmpfile, view):
|
|||
assert json.loads(result[6]) == {
|
||||
'filename': 'new.png',
|
||||
'crop': [1, 2, 30, 40],
|
||||
'opacity': 0.75,
|
||||
}
|
||||
assert result[7] == b'abc'
|
||||
|
||||
|
|
@ -495,6 +500,8 @@ def test_sqliteio_read_reads_readonly_pixmap_item(tmpfile, view, imgdata3x3):
|
|||
assert item.filename == 'bee.png'
|
||||
assert item.width == 3
|
||||
assert item.height == 3
|
||||
assert item.crop == QtCore.QRectF(0, 0, 3, 3)
|
||||
assert item.opacity() == 1
|
||||
assert view.scene.items_to_add.empty() is True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ def test_init(selectable_mock, qapp, imgfilename3x3):
|
|||
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.is_image is True
|
||||
assert item.crop_mode is False
|
||||
selectable_mock.assert_called_once()
|
||||
|
||||
|
|
@ -75,9 +75,11 @@ def test_bounding_rect_unselected_in_crop_mode(qapp, imgfilename3x3):
|
|||
def test_get_extra_save_data(item):
|
||||
item.filename = 'foobar.png'
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.setOpacity(0.75)
|
||||
assert item.get_extra_save_data() == {
|
||||
'filename': 'foobar.png',
|
||||
'crop': [10, 20, 30, 40],
|
||||
'opacity': 0.75,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -242,11 +244,17 @@ def test_update_from_data_keeps_unset_values(item):
|
|||
assert item.flip() == 1
|
||||
|
||||
|
||||
def test_create_from_data(item):
|
||||
def test_create_from_minimal_data(qapp, item, imgfilename3x3):
|
||||
with open(imgfilename3x3, 'rb') as f:
|
||||
imgdata = f.read()
|
||||
item.pixmap_from_bytes(imgdata)
|
||||
|
||||
new_item = BeePixmapItem.create_from_data(
|
||||
item=item, data={'filename': 'foobar.png'})
|
||||
assert new_item is item
|
||||
assert item.filename == 'foobar.png'
|
||||
assert item.crop == QtCore.QRectF(0, 0, 3, 3)
|
||||
assert item.opacity() == 1
|
||||
|
||||
|
||||
def test_create_from_data_with_crop(item):
|
||||
|
|
@ -257,6 +265,14 @@ def test_create_from_data_with_crop(item):
|
|||
assert item.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
|
||||
|
||||
def test_create_from_data_with_opacity(item):
|
||||
new_item = BeePixmapItem.create_from_data(
|
||||
item=item, data={'filename': 'foobar.png', 'opacity': 0.7})
|
||||
assert new_item is item
|
||||
assert item.filename == 'foobar.png'
|
||||
assert item.opacity() == 0.7
|
||||
|
||||
|
||||
def test_create_copy(qapp, imgfilename3x3):
|
||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3), 'foo.png')
|
||||
item.setPos(20, 30)
|
||||
|
|
@ -265,6 +281,7 @@ def test_create_copy(qapp, imgfilename3x3):
|
|||
item.setZValue(0.5)
|
||||
item.setScale(2.2)
|
||||
item.crop = QtCore.QRectF(10, 20, 30, 40)
|
||||
item.setOpacity(0.7)
|
||||
|
||||
copy = item.create_copy()
|
||||
assert copy.pixmap_to_bytes() == item.pixmap_to_bytes()
|
||||
|
|
@ -275,6 +292,7 @@ def test_create_copy(qapp, imgfilename3x3):
|
|||
assert copy.zValue() == 0.5
|
||||
assert copy.scale() == 2.2
|
||||
assert copy.crop == QtCore.QRectF(10, 20, 30, 40)
|
||||
assert copy.opacity() == 0.7
|
||||
|
||||
|
||||
def test_copy_to_clipboard(qapp, imgfilename3x3):
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ def test_init(selectable_mock, qapp):
|
|||
assert item.toPlainText() == 'foo bar'
|
||||
assert item.is_editable is True
|
||||
assert item.edit_mode is False
|
||||
assert item.is_image is False
|
||||
selectable_mock.assert_called_once()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ def test_reset_crop(qapp):
|
|||
assert item2.pos() == QtCore.QPointF(0, 0)
|
||||
|
||||
|
||||
def test_reset_crop_ignores_uncroppable(qapp):
|
||||
def test_reset_crop_ignores_non_images(qapp):
|
||||
item = BeeTextItem('foo')
|
||||
brect = item.boundingRect()
|
||||
command = commands.ResetCrop([item])
|
||||
|
|
@ -483,3 +483,34 @@ def test_change_text():
|
|||
assert item.toPlainText() == 'bar'
|
||||
command.undo()
|
||||
assert item.toPlainText() == 'foo'
|
||||
|
||||
|
||||
def test_change_opacity(view):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
item1.setOpacity(0.5)
|
||||
view.scene.addItem(item1)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
item2.setOpacity(1)
|
||||
command = commands.ChangeOpacity([item1, item2], 0.7)
|
||||
command.redo()
|
||||
assert item1.opacity() == 0.7
|
||||
assert item2.opacity() == 0.7
|
||||
command.undo()
|
||||
assert item1.opacity() == 0.5
|
||||
assert item2.opacity() == 1
|
||||
|
||||
|
||||
def test_change_opacity_ignore_first_redo(view):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
item1.setOpacity(0.5)
|
||||
view.scene.addItem(item1)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
item2.setOpacity(1)
|
||||
command = commands.ChangeOpacity(
|
||||
[item1, item2], 0.7, ignore_first_redo=True)
|
||||
command.redo()
|
||||
assert item1.opacity() == 0.5
|
||||
assert item2.opacity() == 1
|
||||
command.redo()
|
||||
assert item1.opacity() == 0.7
|
||||
assert item2.opacity() == 0.7
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ def test_crop_item_no_selection(view, item):
|
|||
item.enter_crop_mode.assert_not_called()
|
||||
|
||||
|
||||
def test_crop_item_when_not_croppable(view):
|
||||
def test_crop_item_when_not_image(view):
|
||||
item = BeeTextItem('foo')
|
||||
item.setSelected(True)
|
||||
item.enter_crop_mode = MagicMock()
|
||||
|
|
@ -584,32 +584,32 @@ def test_has_multi_selection_when_multi_selection(view):
|
|||
assert view.scene.has_multi_selection() is True
|
||||
|
||||
|
||||
def test_has_croppable_selection(view, item):
|
||||
def test_has_single_image_selection(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
assert view.scene.has_croppable_selection() is True
|
||||
assert view.scene.has_single_image_selection() is True
|
||||
|
||||
|
||||
def test_has_croppable_selection_when_item_not_croppable(view):
|
||||
def test_has_single_image_selection_when_item_not_image(view):
|
||||
item = BeeTextItem('foo')
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(True)
|
||||
assert view.scene.has_croppable_selection() is False
|
||||
assert view.scene.has_single_image_selection() is False
|
||||
|
||||
|
||||
def test_has_croppable_selection_when_no_selection(view, item):
|
||||
def test_has_single_image_selection_when_no_selection(view, item):
|
||||
view.scene.addItem(item)
|
||||
item.setSelected(False)
|
||||
assert view.scene.has_croppable_selection() is False
|
||||
assert view.scene.has_single_image_selection() is False
|
||||
|
||||
|
||||
def test_has_croppable_selection_when_multi_selection(view, item):
|
||||
def test_has_single_image_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
|
||||
assert view.scene.has_single_image_selection() is False
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsScene.mousePressEvent')
|
||||
|
|
|
|||
|
|
@ -716,6 +716,25 @@ def test_on_action_delete_items(view, item):
|
|||
view.scene.cancel_crop_mode.assert_called_once()
|
||||
|
||||
|
||||
@patch('beeref.widgets.ChangeOpacityDialog.__init__',
|
||||
return_value=None)
|
||||
def test_on_action_change_opacity(dialog_mock, view):
|
||||
pixmapitem1 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(pixmapitem1)
|
||||
pixmapitem1.setSelected(True)
|
||||
|
||||
pixmapitem2 = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(pixmapitem2)
|
||||
pixmapitem2.setSelected(False)
|
||||
|
||||
textitem = BeeTextItem('foo')
|
||||
view.scene.addItem(textitem)
|
||||
textitem.setSelected(True)
|
||||
|
||||
view.on_action_change_opacity()
|
||||
dialog_mock.assert_called_once_with(view, [pixmapitem1], view.undo_stack)
|
||||
|
||||
|
||||
@patch('PyQt6.QtGui.QUndoStack.isClean', return_value=True)
|
||||
def test_update_window_title_no_changes_no_filename(clear_mock, view):
|
||||
view.filename = None
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6 import QtCore, QtWidgets, QtGui
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref.config import logfile_name
|
||||
from beeref.widgets import (
|
||||
ChangeOpacityDialog,
|
||||
DebugLogDialog,
|
||||
SceneToPixmapExporterDialog)
|
||||
SceneToPixmapExporterDialog,
|
||||
)
|
||||
|
||||
|
||||
def test_debug_log_dialog(qtbot, settings, view):
|
||||
|
|
@ -46,3 +48,49 @@ def test_scene_to_pixmap_exporter_dialog_updates_width(view):
|
|||
dlg.height_input.setValue(160)
|
||||
assert dlg.width_input.value() == 120
|
||||
assert dlg.value() == QtCore.QSize(120, 160)
|
||||
|
||||
|
||||
def test_change_opacity_dialog_init(view, item):
|
||||
item.setOpacity(0.6)
|
||||
stack = QtGui.QUndoStack()
|
||||
dlg = ChangeOpacityDialog(view, [item], stack)
|
||||
assert dlg.input.value() == 60
|
||||
assert dlg.label.text() == 'Opacity: 60%'
|
||||
|
||||
|
||||
def test_change_opacity_dialog_live_update(view, item):
|
||||
item.setOpacity(0.6)
|
||||
stack = QtGui.QUndoStack()
|
||||
dlg = ChangeOpacityDialog(view, [item], stack)
|
||||
dlg.input.setValue(30)
|
||||
assert dlg.label.text() == 'Opacity: 30%'
|
||||
assert item.opacity() == 0.3
|
||||
|
||||
|
||||
def test_change_opacity_dialog_accept(view, item):
|
||||
item.setOpacity(0.6)
|
||||
stack = QtGui.QUndoStack()
|
||||
dlg = ChangeOpacityDialog(view, [item], stack)
|
||||
dlg.input.setValue(30)
|
||||
dlg.accept()
|
||||
assert item.opacity() == 0.3
|
||||
assert len(stack) == 1
|
||||
|
||||
|
||||
def test_change_opacity_dialog_accept_when_no_items(view):
|
||||
stack = QtGui.QUndoStack()
|
||||
dlg = ChangeOpacityDialog(view, [], stack)
|
||||
assert dlg.input.value() == 100
|
||||
dlg.input.setValue(30)
|
||||
dlg.accept()
|
||||
assert len(stack) == 0
|
||||
|
||||
|
||||
def test_change_opacity_dialog_reject(view, item):
|
||||
item.setOpacity(0.6)
|
||||
stack = QtGui.QUndoStack()
|
||||
dlg = ChangeOpacityDialog(view, [item], stack)
|
||||
dlg.input.setValue(30)
|
||||
dlg.reject()
|
||||
assert item.opacity() == 0.6
|
||||
assert len(stack) == 0
|
||||
|
|
|
|||
Loading…
Reference in a new issue