Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #97

Merged
merged 4 commits into from
Dec 31, 2024
Merged

Dev #97

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion coralnet_toolbox/QtAnnotationWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,6 @@ def select_annotation(self, annotation, ctrl_pressed=False):
self.main_window.confidence_window.display_cropped_image(annotation)

if len(self.selected_annotations) > 1:
self.main_window.label_window.unlock_label_lock()
self.main_window.label_window.deselect_active_label()
self.main_window.confidence_window.clear_display()

Expand Down
5 changes: 5 additions & 0 deletions coralnet_toolbox/QtLabelWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,11 @@ def handle_wasd_key(self, key):

def toggle_label_lock(self, checked):
"""Toggle between lock and unlock states"""
# Check if select tool is active, if not, revert the button state and return
if self.main_window.annotation_window.selected_tool != "select":
self.label_lock_button.setChecked(False) # Revert the toggle
return

if checked:
self.label_lock_button.setIcon(self.main_window.lock_icon)
self.label_lock_button.setToolTip("Label Locked") # Changed
Expand Down
23 changes: 17 additions & 6 deletions coralnet_toolbox/QtMainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -724,37 +724,41 @@ def toggle_tool(self, state):
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)
self.label_window.unlock_label_lock()
self.toolChanged.emit("select")
else:
self.label_window.unlock_label_lock()

self.toolChanged.emit(None)
elif action == self.patch_tool_action:
if state:
self.label_window.unlock_label_lock()

self.select_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)
self.label_window.unlock_label_lock()
self.toolChanged.emit("patch")
else:
self.toolChanged.emit(None)
elif action == self.rectangle_tool_action:
if state:
self.label_window.unlock_label_lock()

self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)
self.label_window.unlock_label_lock()
self.toolChanged.emit("rectangle")
else:
self.toolChanged.emit(None)
elif action == self.polygon_tool_action:
if state:
self.label_window.unlock_label_lock()

self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)
self.label_window.unlock_label_lock()
self.toolChanged.emit("polygon")
else:
self.toolChanged.emit(None)
Expand All @@ -766,13 +770,16 @@ def toggle_tool(self, state):
"You must deploy a Predictor before using the SAM tool.")
return
if state:
self.label_window.unlock_label_lock()

self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.label_window.unlock_label_lock()
self.toolChanged.emit("sam")
else:
self.label_window.unlock_label_lock()

self.toolChanged.emit(None)

def untoggle_all_tools(self):
Expand All @@ -796,41 +803,45 @@ def handle_tool_changed(self, tool):
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)
self.label_window.unlock_label_lock()
elif tool == "patch":
self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(True)
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)

self.label_window.unlock_label_lock()
elif tool == "rectangle":
self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(True)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)

self.label_window.unlock_label_lock()
elif tool == "polygon":
self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(True)
self.sam_tool_action.setChecked(False)

self.label_window.unlock_label_lock()
elif tool == "sam":
self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(True)

self.label_window.unlock_label_lock()
else:
self.select_tool_action.setChecked(False)
self.patch_tool_action.setChecked(False)
self.rectangle_tool_action.setChecked(False)
self.polygon_tool_action.setChecked(False)
self.sam_tool_action.setChecked(False)

self.label_window.unlock_label_lock()

def toggle_device(self):
Expand Down
42 changes: 35 additions & 7 deletions coralnet_toolbox/Tools/QtSelectTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,20 @@ def keyReleaseEvent(self, event):
if not event.modifiers() & Qt.ShiftModifier:
self.remove_resize_handles()

def get_locked_label(self):
"""Get the locked label if it exists."""
return self.annotation_window.main_window.label_window.locked_label

def get_clickable_items(self, position):
"""Get items that can be clicked in the scene."""
items = self.annotation_window.scene.items(position)
return [item for item in items if isinstance(item, (QGraphicsRectItem, QGraphicsPolygonItem))]

def select_annotation(self, position, items, modifiers):
"""Select an annotation based on the click position."""
# Get the locked label if it exists
locked_label = self.get_locked_label()

center_proximity_items = []
for item in items:
if self.is_annotation_clickable(item, position):
Expand All @@ -122,11 +129,19 @@ def select_annotation(self, position, items, modifiers):
# Sort by proximity to the center
center_proximity_items.sort(key=lambda x: x[1])

# Select the closest annotation
for item, _ in center_proximity_items:
# Get the annotation object from the item
annotation_id = item.data(0)
selected_annotation = self.annotation_window.annotations_dict.get(annotation_id)

if selected_annotation:
# Check if a label is locked
if locked_label:
# If locked_label is set, select only annotations with this label
if selected_annotation.label.id != locked_label.id:
continue # Skip annotations with a different label

ctrl_pressed = modifiers & Qt.ControlModifier
if selected_annotation in self.annotation_window.selected_annotations and ctrl_pressed:
# Unselect the annotation if Ctrl is pressed and it is already selected
Expand All @@ -146,12 +161,17 @@ def update_selection_rectangle(self, current_pos):

def finalize_selection_rectangle(self):
"""Finalize the selection rectangle and select annotations within it."""
locked_label = self.get_locked_label()

if self.selection_rectangle:
rect = self.selection_rectangle.rect()
# Don't clear previous selection when using rectangle selection
for annotation in self.annotation_window.get_image_annotations():
if rect.contains(annotation.center_xy):
# Always add to selection when using rectangle
# Check if a label is locked, and only select annotations with this label
if locked_label and annotation.label.id != locked_label.id:
continue
# Always *add* to selection when using rectangle
self.annotation_window.select_annotation(annotation, True)

def get_item_center(self, item):
Expand All @@ -172,8 +192,10 @@ def is_annotation_clickable(self, item, position):

def handle_selection(self, selected_annotation, modifiers):
"""Handle annotation selection logic."""
locked_label = self.get_locked_label()
ctrl_pressed = modifiers & Qt.ControlModifier

# TODO this keeping the rectangle selection from *adding* all
if selected_annotation in self.annotation_window.selected_annotations:
if ctrl_pressed:
# Toggle selection when Ctrl is pressed
Expand All @@ -189,8 +211,14 @@ def handle_selection(self, selected_annotation, modifiers):
if not ctrl_pressed:
# Clear selection if Ctrl is not pressed
self.annotation_window.unselect_annotations()

# Check if a label is locked
if locked_label and selected_annotation.label.id != locked_label.id:
return None

# Add to selection
self.annotation_window.select_annotation(selected_annotation, True)

return selected_annotation

def init_drag_or_resize(self, selected_annotation, position, modifiers):
Expand All @@ -208,8 +236,8 @@ def init_drag_or_resize(self, selected_annotation, position, modifiers):
def handle_move(self, current_pos):
"""Handle moving the selected annotation."""
if not len(self.annotation_window.selected_annotations):
return
return

selected_annotation = self.annotation_window.selected_annotations[0]
delta = current_pos - self.move_start_pos
new_center = selected_annotation.center_xy + delta
Expand All @@ -225,11 +253,11 @@ def handle_resize(self, current_pos):
"""Handle resizing the selected annotation."""
if not len(self.annotation_window.selected_annotations):
return

selected_annotation = self.annotation_window.selected_annotations[0]
if not self.annotation_window.is_annotation_moveable(selected_annotation):
return

self.resize_annotation(selected_annotation, current_pos)
self.display_resize_handles(selected_annotation)

Expand Down Expand Up @@ -293,7 +321,7 @@ def display_resize_handles(self, annotation):
point.y() - handle_size // 2,
handle_size,
handle_size)

ellipse.setPen(QPen(annotation.label.color))
ellipse.setBrush(QBrush(annotation.label.color))
self.annotation_window.scene.addItem(ellipse)
Expand All @@ -308,4 +336,4 @@ def remove_resize_handles(self):
"""Remove any displayed resize handles."""
for handle in self.resize_handles:
self.annotation_window.scene.removeItem(handle)
self.resize_handles.clear()
self.resize_handles.clear()
2 changes: 1 addition & 1 deletion coralnet_toolbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from coralnet_toolbox.main import run

__version__ = "0.0.18"
__version__ = "0.0.19"
__author__ = "Jordan Pierce"
__email__ = "[email protected]"
__credits__ = "National Center for Coastal and Ocean Sciences (NCCOS)"
Binary file modified figures/toolbox_qt.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "coralnet-toolbox"
version = "0.0.18"
version = "0.0.19"
dynamic = [
"dependencies",
]
Expand Down Expand Up @@ -48,7 +48,7 @@ universal = true


[tool.bumpversion]
current_version = "0.0.18"
current_version = "0.0.19"
commit = true
tag = true

Expand Down
Loading