Fixes mirrored slice exports by making orientation explicit: - PhotoSlice.swapped flag persists a user left/right swap - swap_left_right() mirrors [TL,TR,BR,BL] -> [TR,TL,BL,BR] - normalize_top_left() honors the flag so squarize/reset_rotation no longer overwrite manual orientation - Swap L/R toolbar button wired through canvas state + controller - Color-code left (orange) vs right (cyan) corners and edges
126 lines
5.4 KiB
Python
126 lines
5.4 KiB
Python
from .slices import PhotoSlice
|
|
|
|
|
|
# ScanSlicerCanvasActionsMixin: class definition for ScanSlicer behavior.
|
|
class ScanSlicerCanvasActionsMixin:
|
|
# on_active_slice_changed: function definition for ScanSlicer behavior.
|
|
def on_active_slice_changed(self, index):
|
|
self.refresh_active_box_toolbar(index)
|
|
|
|
# refresh_active_box_toolbar: function definition for ScanSlicer behavior.
|
|
def refresh_active_box_toolbar(self, index=None):
|
|
if index == -1:
|
|
index = None
|
|
if index is None:
|
|
index = self.slicing_canvas.active_slice_index
|
|
|
|
has_slices = len(self.slicing_canvas.slices) > 0
|
|
self.all_boxes_lock_button.setEnabled(has_slices)
|
|
self.all_boxes_lock_button.blockSignals(True)
|
|
self.all_boxes_lock_button.setChecked(self.slicing_canvas.are_all_slices_locked())
|
|
self.all_boxes_lock_button.blockSignals(False)
|
|
|
|
active_slice = self.slicing_canvas.get_active_slice()
|
|
if active_slice is None:
|
|
self.active_box_label.setText("Active Box: none")
|
|
self.active_box_lock_button.setEnabled(False)
|
|
self.active_box_squarize_button.setEnabled(False)
|
|
self.active_box_reset_rotation_button.setEnabled(False)
|
|
self.active_box_swap_button.setEnabled(False)
|
|
self.active_box_remove_button.setEnabled(False)
|
|
self.active_box_lock_button.blockSignals(True)
|
|
self.active_box_lock_button.setChecked(False)
|
|
self.active_box_lock_button.blockSignals(False)
|
|
return
|
|
|
|
if index is None:
|
|
index = self.slicing_canvas.active_slice_index
|
|
self.active_box_label.setText(f"Active Box: {index}")
|
|
self.active_box_lock_button.setEnabled(True)
|
|
self.active_box_squarize_button.setEnabled(True)
|
|
self.active_box_reset_rotation_button.setEnabled(True)
|
|
self.active_box_swap_button.setEnabled(True)
|
|
self.active_box_remove_button.setEnabled(True)
|
|
self.active_box_lock_button.blockSignals(True)
|
|
self.active_box_lock_button.setChecked(active_slice.locked)
|
|
self.active_box_lock_button.blockSignals(False)
|
|
|
|
# toggle_active_box_lock: function definition for ScanSlicer behavior.
|
|
def toggle_active_box_lock(self, checked):
|
|
if not self.slicing_canvas.set_active_slice_locked(checked):
|
|
self.refresh_active_box_toolbar()
|
|
return
|
|
self.refresh_active_box_toolbar()
|
|
|
|
# toggle_all_boxes_lock: function definition for ScanSlicer behavior.
|
|
def toggle_all_boxes_lock(self, checked):
|
|
count = self.slicing_canvas.set_all_slices_locked(checked)
|
|
self.refresh_active_box_toolbar()
|
|
if count == 0:
|
|
self.update_statusbar("No boxes available.")
|
|
return
|
|
if checked:
|
|
self.update_statusbar(f"Locked {count} box(es).")
|
|
else:
|
|
self.update_statusbar(f"Unlocked {count} box(es).")
|
|
|
|
# squarize_active_box: function definition for ScanSlicer behavior.
|
|
def squarize_active_box(self):
|
|
if not self.slicing_canvas.squarize_active_slice():
|
|
self.update_statusbar("No active box selected.")
|
|
return
|
|
self.update_statusbar("Active box squarized.")
|
|
|
|
# swap_active_box_left_right: function definition for ScanSlicer behavior.
|
|
def swap_active_box_left_right(self):
|
|
if not self.slicing_canvas.swap_active_slice_left_right():
|
|
self.update_statusbar("No active box selected.")
|
|
return
|
|
self.update_statusbar("Active box left/right swapped.")
|
|
|
|
# reset_active_box_rotation: function definition for ScanSlicer behavior.
|
|
def reset_active_box_rotation(self):
|
|
if not self.slicing_canvas.reset_active_slice_rotation():
|
|
self.update_statusbar("No active box selected.")
|
|
return
|
|
self.update_statusbar("Active box rotation reset.")
|
|
|
|
# remove_active_box: function definition for ScanSlicer behavior.
|
|
def remove_active_box(self):
|
|
if not self.slicing_canvas.remove_active_slice():
|
|
self.update_statusbar("No active box selected.")
|
|
return
|
|
self.refresh_active_box_toolbar()
|
|
self.update_statusbar("Active box removed.")
|
|
|
|
# set_preview_filter_enabled: function definition for ScanSlicer behavior.
|
|
def set_preview_filter_enabled(self, checked):
|
|
self.preview_filter_enabled = bool(checked)
|
|
if self.preview_filter_enabled:
|
|
self.update_statusbar("Filter preview enabled.")
|
|
else:
|
|
self.update_statusbar("Filter preview disabled.")
|
|
|
|
if self.autoslicer.image_loaded():
|
|
self.update_preview(new_image=False, run_detection=False)
|
|
|
|
# set_rotate_handles_mode: function definition for ScanSlicer behavior.
|
|
def set_rotate_handles_mode(self, checked):
|
|
self.slicing_canvas.set_rotate_handles_mode(checked)
|
|
if checked:
|
|
self.update_statusbar("Rotate mode enabled.")
|
|
else:
|
|
self.update_statusbar("Rotate mode disabled.")
|
|
|
|
# reset_canvas_view: function definition for ScanSlicer behavior.
|
|
def reset_canvas_view(self):
|
|
if not self.slicing_canvas.reset_view():
|
|
self.update_statusbar("No image loaded.")
|
|
return
|
|
self.update_statusbar("View reset.")
|
|
|
|
# add_box: function definition for ScanSlicer behavior.
|
|
def add_box(self):
|
|
new_slice = PhotoSlice(None)
|
|
new_slice.toggle_locked()
|
|
self.slicing_canvas.add_bbox(new_slice)
|