waaa
This commit is contained in:
@@ -49,7 +49,7 @@ class AreaSelectionHandler:
|
||||
|
||||
# Selection state
|
||||
self._selectionMode = False
|
||||
self._selectionType = "rectangle" # "rectangle", "circle", or "lasso"
|
||||
self._selectionType = "rectangle" # "rectangle", "circle", "lasso", or "polygon"
|
||||
self._selectionStartX = None
|
||||
self._selectionStartY = None
|
||||
self._selectionEndX = None
|
||||
@@ -57,6 +57,9 @@ class AreaSelectionHandler:
|
||||
self._selectionRectangle = None
|
||||
self._lassoPath = [] # List of canvas coordinates for lasso drawing
|
||||
self._lassoLine = None # Canvas line item for lasso path
|
||||
self._polygonPath = [] # List of canvas coordinates for polygon points
|
||||
self._polygonLines = [] # List of canvas line items for polygon drawing
|
||||
self._polygonPoints = [] # List of canvas point markers for polygon vertices
|
||||
|
||||
# Pending operation callback (called when selection is completed)
|
||||
self._pendingOperationCallback = None
|
||||
@@ -120,6 +123,72 @@ class AreaSelectionHandler:
|
||||
"""Set selection to lasso (free-form) mode and enable selection."""
|
||||
self.set_selection_shape("lasso")
|
||||
|
||||
def set_polygon_selection(self) -> None:
|
||||
"""Set selection to polygon mode and enable selection."""
|
||||
self.set_selection_shape("polygon")
|
||||
|
||||
def _complete_polygon_selection(self) -> None:
|
||||
"""Complete the polygon selection by converting canvas coordinates to image coordinates."""
|
||||
if not self._polygonPath or len(self._polygonPath) < 3:
|
||||
return
|
||||
|
||||
current_image = self._get_current_image()
|
||||
if current_image is None:
|
||||
return
|
||||
|
||||
pil_image = current_image.getImage()
|
||||
if pil_image is None:
|
||||
return
|
||||
|
||||
img_width, img_height = pil_image.size
|
||||
|
||||
# Get canvas dimensions for scaling
|
||||
canvas_width, canvas_height = self._get_canvas_dimensions()
|
||||
if canvas_width <= 0 or canvas_height <= 0:
|
||||
return
|
||||
|
||||
# Calculate scaling factors
|
||||
scale_x = img_width / canvas_width
|
||||
scale_y = img_height / canvas_height
|
||||
|
||||
# Convert canvas coordinates to image coordinates
|
||||
image_path = [(int(x * scale_x), int(y * scale_y)) for x, y in self._polygonPath]
|
||||
|
||||
# Set the polygon path in selection area
|
||||
self._selectionArea.set_polygon_path(image_path)
|
||||
|
||||
# Clear polygon drawing elements
|
||||
for line in self._polygonLines:
|
||||
self._canvas.delete(line)
|
||||
for point in self._polygonPoints:
|
||||
self._canvas.delete(point)
|
||||
self._polygonLines = []
|
||||
self._polygonPoints = []
|
||||
|
||||
# Redraw the selection highlight to ensure it's visible
|
||||
self._render_image()
|
||||
|
||||
# Check if there's a pending operation callback and execute it
|
||||
if self._pendingOperationCallback and self._selectionArea.is_valid():
|
||||
callback = self._pendingOperationCallback
|
||||
self._pendingOperationCallback = None # Clear callback to prevent multiple calls
|
||||
callback()
|
||||
|
||||
def on_double_click(self, event) -> bool:
|
||||
"""Handle double-click to complete polygon selection.
|
||||
|
||||
Returns:
|
||||
True if the double-click was handled, False otherwise
|
||||
"""
|
||||
if not self._selectionMode or self._selectionType != "polygon":
|
||||
return False
|
||||
|
||||
if len(self._polygonPath) >= 3:
|
||||
self._complete_polygon_selection()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def set_pending_operation_callback(self, callback: Optional[Callable]) -> None:
|
||||
"""Set a callback to be executed when a selection is completed.
|
||||
|
||||
@@ -153,6 +222,45 @@ class AreaSelectionHandler:
|
||||
self._lassoPath.append((canvas_x, canvas_y))
|
||||
return True
|
||||
|
||||
# Handle polygon mode
|
||||
if self._selectionType == "polygon":
|
||||
# If this is the first point, clear any existing polygon
|
||||
if not self._polygonPath:
|
||||
# Clear any existing selection
|
||||
if self._selectionArea.is_active:
|
||||
self._selectionArea.clear()
|
||||
# Clear any existing polygon drawing elements
|
||||
for line in self._polygonLines:
|
||||
self._canvas.delete(line)
|
||||
for point in self._polygonPoints:
|
||||
self._canvas.delete(point)
|
||||
self._polygonLines = []
|
||||
self._polygonPoints = []
|
||||
|
||||
canvas_x = self._canvas.canvasx(event.x)
|
||||
canvas_y = self._canvas.canvasy(event.y)
|
||||
|
||||
# Add point to polygon
|
||||
self._polygonPath.append((canvas_x, canvas_y))
|
||||
|
||||
# Draw point marker
|
||||
point_marker = self._canvas.create_oval(
|
||||
canvas_x - 3, canvas_y - 3, canvas_x + 3, canvas_y + 3,
|
||||
fill="red", outline="red", width=2
|
||||
)
|
||||
self._polygonPoints.append(point_marker)
|
||||
|
||||
# Draw lines connecting points
|
||||
if len(self._polygonPath) > 1:
|
||||
prev_point = self._polygonPath[-2]
|
||||
line = self._canvas.create_line(
|
||||
prev_point[0], prev_point[1], canvas_x, canvas_y,
|
||||
fill="red", width=2
|
||||
)
|
||||
self._polygonLines.append(line)
|
||||
|
||||
return True
|
||||
|
||||
# Handle rectangle/circle mode
|
||||
# Clear any existing selection
|
||||
self.clear_selection()
|
||||
@@ -262,6 +370,10 @@ class AreaSelectionHandler:
|
||||
callback()
|
||||
return True
|
||||
|
||||
# Handle polygon mode - complete polygon on double-click
|
||||
# (Polygon completion happens on double-click, not on mouse release)
|
||||
return True
|
||||
|
||||
# Handle rectangle/circle mode
|
||||
if self._selectionStartX is None:
|
||||
return False
|
||||
@@ -544,7 +656,14 @@ class AreaSelectionHandler:
|
||||
if self._lassoLine:
|
||||
self._canvas.delete(self._lassoLine)
|
||||
self._lassoLine = None
|
||||
for line in self._polygonLines:
|
||||
self._canvas.delete(line)
|
||||
for point in self._polygonPoints:
|
||||
self._canvas.delete(point)
|
||||
self._lassoPath = []
|
||||
self._polygonPath = []
|
||||
self._polygonLines = []
|
||||
self._polygonPoints = []
|
||||
self._selectionStartX = None
|
||||
self._selectionStartY = None
|
||||
self._selectionEndX = None
|
||||
@@ -599,6 +718,16 @@ class AreaSelectionHandler:
|
||||
*[coord for point in closed_path for coord in point],
|
||||
fill="red", width=3, smooth=False
|
||||
)
|
||||
elif self._selectionArea.shape == "polygon" and self._selectionArea.polygon_path:
|
||||
# Convert polygon path from image coordinates to canvas coordinates
|
||||
canvas_path = [(int(x * scale_x), int(y * scale_y)) for x, y in self._selectionArea.polygon_path]
|
||||
if len(canvas_path) >= 3:
|
||||
# Close the path by adding the first point at the end
|
||||
closed_path = canvas_path + [canvas_path[0]]
|
||||
self._canvas.create_line(
|
||||
*[coord for point in closed_path for coord in point],
|
||||
fill="red", width=3, smooth=False
|
||||
)
|
||||
elif self._selectionArea.shape == "circle":
|
||||
self._canvas.create_oval(
|
||||
canvas_left, canvas_top, canvas_right, canvas_bottom,
|
||||
|
||||
Reference in New Issue
Block a user