diff --git a/beeref/__main__.py b/beeref/__main__.py
index ad1d328..dfb6a29 100755
--- a/beeref/__main__.py
+++ b/beeref/__main__.py
@@ -22,6 +22,7 @@ import sys
from PyQt6 import QtCore, QtGui, QtWidgets
+from beeref.assets import BeeAssets
from beeref.config import CommandlineArgs
from beeref.view import BeeGraphicsView
@@ -33,10 +34,7 @@ class BeeRefMainWindow(QtWidgets.QWidget):
def __init__(self, app, filename=None):
super().__init__()
self.setWindowTitle('BeeRef')
- root = os.path.dirname(__file__)
- logo = os.path.join(root, 'assets', 'logo.png')
- logger.debug(f'Loading icon {logo}')
- self.setWindowIcon(QtGui.QIcon(logo))
+ self.setWindowIcon(BeeAssets().logo)
layout = QtWidgets.QVBoxLayout()
layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
self.setLayout(layout)
diff --git a/beeref/assets.py b/beeref/assets.py
new file mode 100644
index 0000000..745f3ee
--- /dev/null
+++ b/beeref/assets.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+
+# This file is part of BeeRef.
+#
+# BeeRef is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# BeeRef is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with BeeRef. If not, see .
+
+import logging
+import os.path
+
+from PyQt6 import QtCore, QtGui, QtWidgets
+from PyQt6.QtCore import Qt
+
+
+logger = logging.getLogger('BeeRef')
+
+
+class BeeAssets:
+ _instance = None
+ PATH = os.path.join( os.path.dirname(__file__), 'assets')
+
+ def __new__(cls, *args, **kwargs):
+ if not cls._instance:
+ cls._instance = super().__new__(cls, *args, **kwargs)
+ cls._instance.on_new()
+ return cls._instance
+
+ def on_new(self):
+ PATH = os.path.join(os.path.dirname(__file__), 'assets')
+ logger.debug(f'Assets path: {self.PATH}')
+
+ self.logo = QtGui.QIcon(os.path.join(self.PATH, 'logo.png'))
+ self.cursor_rotate = self.cursor_from_image('cursor_rotate', (6, 10))
+
+ def cursor_from_image(self, filename, hotspot):
+ img = QtGui.QImage(os.path.join(self.PATH, filename))
+ return QtGui.QCursor(
+ QtGui.QPixmap.fromImage(img), hotspot[0], hotspot[1])
diff --git a/beeref/assets/cursor_rotate.png b/beeref/assets/cursor_rotate.png
new file mode 100644
index 0000000..b2d4e7e
Binary files /dev/null and b/beeref/assets/cursor_rotate.png differ
diff --git a/beeref/assets/cursor_rotate.svg b/beeref/assets/cursor_rotate.svg
new file mode 100644
index 0000000..06fc6d3
--- /dev/null
+++ b/beeref/assets/cursor_rotate.svg
@@ -0,0 +1,111 @@
+
+
+
+
diff --git a/beeref/config.py b/beeref/config.py
index 5cb6a11..11cd717 100644
--- a/beeref/config.py
+++ b/beeref/config.py
@@ -35,7 +35,7 @@ parser.add_argument(
help='draw debug shapes for bounding rects and interactable areas')
-class CommandlineArgs():
+class CommandlineArgs:
"""Wrapper around argument parsing.
Checking for unknown arugments is configurable so that it can be
@@ -52,10 +52,11 @@ class CommandlineArgs():
return cls._instance
def __init__(self, with_check=False):
- if with_check:
- self._args = parser.parse_args()
- else:
- self._args = parser.parse_known_args()[0]
+ if not hasattr(self, '_args'):
+ if with_check:
+ self._args = parser.parse_args()
+ else:
+ self._args = parser.parse_known_args()[0]
def __getattribute__(self, name):
if name == '_args':
diff --git a/beeref/selection.py b/beeref/selection.py
index 2bf2ef2..ea49190 100644
--- a/beeref/selection.py
+++ b/beeref/selection.py
@@ -21,6 +21,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QGraphicsItem
+from beeref.assets import BeeAssets
from beeref import commands
from beeref.config import CommandlineArgs
from beeref import utils
@@ -204,7 +205,7 @@ class SelectableMixin(BaseItemMixin):
self.setCursor(Qt.CursorShape.SizeBDiagCursor)
return
if self.get_rotate_bounds(corner).contains(event.pos()):
- self.setCursor(Qt.CursorShape.ForbiddenCursor)
+ self.setCursor(BeeAssets().cursor_rotate)
return
self.setCursor(Qt.CursorShape.ArrowCursor)
diff --git a/tests/test_assets.py b/tests/test_assets.py
new file mode 100644
index 0000000..98b21f6
--- /dev/null
+++ b/tests/test_assets.py
@@ -0,0 +1,14 @@
+from PyQt6 import QtGui
+
+from beeref.assets import BeeAssets
+from .base import BeeTestCase
+
+
+class GetRectFromPointsTestCase(BeeTestCase):
+
+ def test_singleton(self):
+ assert BeeAssets() is BeeAssets()
+ assert BeeAssets().logo is BeeAssets().logo
+
+ def test_has_logo(self):
+ assert isinstance(BeeAssets().logo, QtGui.QIcon)
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644
index 0000000..56cb80a
--- /dev/null
+++ b/tests/test_config.py
@@ -0,0 +1,8 @@
+from unittest.mock import patch
+
+from beeref.config import CommandlineArgs
+
+
+def test_singleton():
+ assert CommandlineArgs() is CommandlineArgs()
+ assert CommandlineArgs()._args is CommandlineArgs()._args
diff --git a/tests/test_selection.py b/tests/test_selection.py
index f36e3e7..72aa3f9 100644
--- a/tests/test_selection.py
+++ b/tests/test_selection.py
@@ -3,6 +3,7 @@ from unittest.mock import patch, MagicMock, PropertyMock
from PyQt6 import QtCore, QtGui
from PyQt6.QtCore import Qt
+from beeref.assets import BeeAssets
from beeref.items import BeePixmapItem
from beeref.scene import BeeGraphicsScene
from beeref.selection import MultiSelectItem, RubberbandItem
@@ -406,6 +407,14 @@ class SelectableMixinMouseEventsTestCase(SelectableMixinBaseTestCase):
self.item.setCursor.assert_called_once_with(
Qt.CursorShape.SizeBDiagCursor)
+ def test_hover_move_event_rotate(self):
+ self.item.setSelected(True)
+ self.item.SELECT_RESIZE_SIZE = 10
+ self.item.SELECT_ROTATE_SIZE = 10
+ self.event.pos = MagicMock(return_value=QtCore.QPointF(110, 90))
+ self.item.hoverMoveEvent(self.event)
+ self.item.setCursor.assert_called_once_with(BeeAssets().cursor_rotate)
+
def test_hover_move_event_not_in_handles(self):
self.item.setSelected(True)
self.event.pos = MagicMock(return_value=QtCore.QPointF(50, 50))