135 lines
5.0 KiB
Python
135 lines
5.0 KiB
Python
"""
|
|
Asset drop mixin for GLWidget - handles drag-and-drop file operations
|
|
"""
|
|
|
|
from pyPhotoAlbum.models import ImageData, PlaceholderData
|
|
from pyPhotoAlbum.commands import AddElementCommand
|
|
|
|
|
|
class AssetDropMixin:
|
|
"""
|
|
Mixin providing drag-and-drop asset functionality.
|
|
|
|
This mixin handles dragging image files into the widget and creating
|
|
or updating ImageData elements.
|
|
"""
|
|
|
|
IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp']
|
|
|
|
def dragEnterEvent(self, event):
|
|
"""Handle drag enter events"""
|
|
if event.mimeData().hasUrls():
|
|
urls = event.mimeData().urls()
|
|
for url in urls:
|
|
file_path = url.toLocalFile()
|
|
if any(file_path.lower().endswith(ext) for ext in self.IMAGE_EXTENSIONS):
|
|
event.acceptProposedAction()
|
|
return
|
|
event.ignore()
|
|
|
|
def dragMoveEvent(self, event):
|
|
"""Handle drag move events"""
|
|
if event.mimeData().hasUrls():
|
|
event.acceptProposedAction()
|
|
else:
|
|
event.ignore()
|
|
|
|
def dropEvent(self, event):
|
|
"""Handle drop events"""
|
|
if not event.mimeData().hasUrls():
|
|
event.ignore()
|
|
return
|
|
|
|
image_path = None
|
|
|
|
for url in event.mimeData().urls():
|
|
file_path = url.toLocalFile()
|
|
if any(file_path.lower().endswith(ext) for ext in self.IMAGE_EXTENSIONS):
|
|
image_path = file_path
|
|
break
|
|
|
|
if not image_path:
|
|
event.ignore()
|
|
return
|
|
|
|
x, y = event.position().x(), event.position().y()
|
|
|
|
target_element = self._get_element_at(x, y)
|
|
|
|
if target_element and isinstance(target_element, (ImageData, PlaceholderData)):
|
|
if isinstance(target_element, PlaceholderData):
|
|
new_image = ImageData(
|
|
image_path=image_path,
|
|
x=target_element.position[0],
|
|
y=target_element.position[1],
|
|
width=target_element.size[0],
|
|
height=target_element.size[1],
|
|
z_index=target_element.z_index
|
|
)
|
|
main_window = self.window()
|
|
if hasattr(main_window, 'project') and main_window.project and main_window.project.pages:
|
|
for page in main_window.project.pages:
|
|
if target_element in page.layout.elements:
|
|
page.layout.elements.remove(target_element)
|
|
page.layout.add_element(new_image)
|
|
break
|
|
else:
|
|
target_element.image_path = image_path
|
|
|
|
print(f"Updated element with image: {image_path}")
|
|
else:
|
|
try:
|
|
from PIL import Image
|
|
img = Image.open(image_path)
|
|
img_width, img_height = img.size
|
|
|
|
max_size = 300
|
|
if img_width > max_size or img_height > max_size:
|
|
scale = min(max_size / img_width, max_size / img_height)
|
|
img_width = int(img_width * scale)
|
|
img_height = int(img_height * scale)
|
|
|
|
except Exception as e:
|
|
print(f"Error loading image dimensions: {e}")
|
|
img_width, img_height = 200, 150
|
|
|
|
main_window = self.window()
|
|
if hasattr(main_window, 'project') and main_window.project and main_window.project.pages:
|
|
# Detect which page the drop occurred on
|
|
target_page, page_index, page_renderer = self._get_page_at(x, y)
|
|
|
|
if target_page and page_renderer:
|
|
# Update current_page_index
|
|
if page_index >= 0:
|
|
self.current_page_index = page_index
|
|
|
|
# Convert screen coordinates to page-local coordinates
|
|
page_local_x, page_local_y = page_renderer.screen_to_page(x, y)
|
|
|
|
try:
|
|
asset_path = main_window.project.asset_manager.import_asset(image_path)
|
|
|
|
new_image = ImageData(
|
|
image_path=asset_path,
|
|
x=page_local_x,
|
|
y=page_local_y,
|
|
width=img_width,
|
|
height=img_height
|
|
)
|
|
|
|
cmd = AddElementCommand(
|
|
target_page.layout,
|
|
new_image,
|
|
asset_manager=main_window.project.asset_manager
|
|
)
|
|
main_window.project.history.execute(cmd)
|
|
|
|
print(f"Added new image to page {page_index + 1} at ({page_local_x:.1f}, {page_local_y:.1f}): {asset_path}")
|
|
except Exception as e:
|
|
print(f"Error adding dropped image: {e}")
|
|
else:
|
|
print("Drop location not on any page")
|
|
|
|
event.acceptProposedAction()
|
|
self.update()
|