Implemented Grabber Handles for easier usage.
This commit is contained in:
parent
7991aa751f
commit
415f1842cd
@ -32,7 +32,7 @@ pytesseract.pytesseract.tesseract_cmd = r"C:\\Program Files\\Tesseract-OCR\\tess
|
||||
|
||||
DEFAULT_WIDTH = 180
|
||||
DEFAULT_HEIGHT = 130
|
||||
HANDLE_SIZE = 8
|
||||
HANDLE_SIZE = 5
|
||||
LABEL_HEIGHT = 20
|
||||
|
||||
collector_mutex = QMutex()
|
||||
@ -196,9 +196,6 @@ def find_word_positions(region_id, word, offset_x=0, offset_y=0, margin=5, ocr_e
|
||||
print(f"[ERROR] Failed to capture OCR region: {e}")
|
||||
return []
|
||||
|
||||
|
||||
|
||||
|
||||
def draw_identification_boxes(region_id, positions, color=(0, 0, 255), thickness=2):
|
||||
"""
|
||||
Draws non-interactive rectangles at specified positions within the given OCR region.
|
||||
@ -236,6 +233,10 @@ class OCRRegionWidget(QWidget):
|
||||
self.previous_positions = [] # This prevents redundant redraws
|
||||
self.num_slices = 1 # Ensures slice count is initialized
|
||||
|
||||
# --- Initialization for interactive handles ---
|
||||
self.selected_handle = None # Tracks which handle is being dragged/resized
|
||||
self.drag_offset = None # Tracks the offset for moving the widget
|
||||
|
||||
self.show()
|
||||
|
||||
def paintEvent(self, event):
|
||||
@ -260,6 +261,13 @@ class OCRRegionWidget(QWidget):
|
||||
|
||||
for i in range(1, self.num_slices): # Do not draw the last one at the bottom
|
||||
painter.drawLine(0, i * strip_height, self.width(), i * strip_height)
|
||||
|
||||
# --- Draw interactive handles (grabbers) with reduced opacity (15%) ---
|
||||
# 15% opacity of 255 is approximately 38
|
||||
handle_color = QColor(0, 0, 0, 50)
|
||||
for handle in self._resize_handles():
|
||||
painter.fillRect(handle, handle_color)
|
||||
painter.drawRect(handle) # Optional: draw a border around the handle
|
||||
|
||||
def set_draw_positions(self, positions, color, thickness):
|
||||
"""
|
||||
@ -292,57 +300,99 @@ class OCRRegionWidget(QWidget):
|
||||
self.update()
|
||||
|
||||
def _resize_handles(self):
|
||||
"""
|
||||
Returns a list of QRect objects representing the interactive handles:
|
||||
- Index 0: Top-left (resize)
|
||||
- Index 1: Top-right (resize)
|
||||
- Index 2: Bottom-left (resize)
|
||||
- Index 3: Bottom-right (resize)
|
||||
- Index 4: Top-center (dragger)
|
||||
"""
|
||||
w, h = self.width(), self.height()
|
||||
return [
|
||||
QRect(0, 0, HANDLE_SIZE, HANDLE_SIZE), # Top-left
|
||||
QRect(w - HANDLE_SIZE, h - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE) # Bottom-right
|
||||
handles = [
|
||||
QRect(0, 0, HANDLE_SIZE, HANDLE_SIZE), # Top-left
|
||||
QRect(w - HANDLE_SIZE, 0, HANDLE_SIZE, HANDLE_SIZE), # Top-right
|
||||
QRect(0, h - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE), # Bottom-left
|
||||
QRect(w - HANDLE_SIZE, h - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE) # Bottom-right
|
||||
]
|
||||
# Top-center handle: centered along the top edge
|
||||
top_center_x = (w - HANDLE_SIZE) // 2
|
||||
top_center = QRect(top_center_x, 0, HANDLE_SIZE, HANDLE_SIZE)
|
||||
handles.append(top_center)
|
||||
return handles
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.LeftButton:
|
||||
# Check if any handle (including the new top-center) is clicked
|
||||
for i, handle in enumerate(self._resize_handles()):
|
||||
if handle.contains(event.pos()):
|
||||
self.selected_handle = i
|
||||
# For the top-center handle (index 4), initialize drag offset for moving
|
||||
if i == 4:
|
||||
self.drag_offset = event.pos()
|
||||
return
|
||||
|
||||
# If no handle is clicked, allow dragging by clicking anywhere in the widget
|
||||
self.drag_offset = event.pos()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self.selected_handle is not None:
|
||||
w, h = self.width(), self.height()
|
||||
if self.selected_handle == 0: # Top-left
|
||||
new_w = w + (self.x() - event.globalX())
|
||||
new_h = h + (self.y() - event.globalY())
|
||||
new_x = event.globalX()
|
||||
new_y = event.globalY()
|
||||
if self.selected_handle == 4:
|
||||
# --- Top-center handle dragging ---
|
||||
new_x = event.globalX() - self.drag_offset.x()
|
||||
new_y = event.globalY() - self.drag_offset.y()
|
||||
self.move(new_x, new_y)
|
||||
collector_mutex.lock()
|
||||
if self.region_id in regions:
|
||||
regions[self.region_id]["bbox"] = [new_x, new_y, self.width(), self.height()]
|
||||
collector_mutex.unlock()
|
||||
self.update()
|
||||
else:
|
||||
# --- Resizing logic for corner handles ---
|
||||
if self.selected_handle == 0: # Top-left
|
||||
new_w = self.width() + (self.x() - event.globalX())
|
||||
new_h = self.height() + (self.y() - event.globalY())
|
||||
new_x = event.globalX()
|
||||
new_y = event.globalY()
|
||||
elif self.selected_handle == 1: # Top-right
|
||||
new_w = event.globalX() - self.x()
|
||||
new_h = self.height() + (self.y() - event.globalY())
|
||||
new_x = self.x()
|
||||
new_y = event.globalY()
|
||||
elif self.selected_handle == 2: # Bottom-left
|
||||
new_w = self.width() + (self.x() - event.globalX())
|
||||
new_h = event.globalY() - self.y()
|
||||
new_x = event.globalX()
|
||||
new_y = self.y()
|
||||
elif self.selected_handle == 3: # Bottom-right
|
||||
new_w = event.globalX() - self.x()
|
||||
new_h = event.globalY() - self.y()
|
||||
new_x = self.x()
|
||||
new_y = self.y()
|
||||
|
||||
if new_w < 20:
|
||||
new_w = 20
|
||||
if new_h < 20:
|
||||
new_h = 20
|
||||
|
||||
self.setGeometry(new_x, new_y, new_w, new_h)
|
||||
elif self.selected_handle == 1: # Bottom-right
|
||||
new_w = event.globalX() - self.x()
|
||||
new_h = event.globalY() - self.y()
|
||||
if new_w < 20:
|
||||
new_w = 20
|
||||
if new_h < 20:
|
||||
new_h = 20
|
||||
self.setGeometry(self.x(), self.y(), new_w, new_h)
|
||||
|
||||
collector_mutex.lock()
|
||||
if self.region_id in regions:
|
||||
regions[self.region_id]["bbox"] = [self.x(), self.y(), self.width(), self.height()]
|
||||
collector_mutex.unlock()
|
||||
|
||||
self.update()
|
||||
collector_mutex.lock()
|
||||
if self.region_id in regions:
|
||||
regions[self.region_id]["bbox"] = [self.x(), self.y(), self.width(), self.height()]
|
||||
collector_mutex.unlock()
|
||||
self.update()
|
||||
elif self.drag_offset:
|
||||
# --- General widget dragging (if no handle was clicked) ---
|
||||
new_x = event.globalX() - self.drag_offset.x()
|
||||
new_y = event.globalY() - self.drag_offset.y()
|
||||
self.move(new_x, new_y)
|
||||
|
||||
collector_mutex.lock()
|
||||
if self.region_id in regions:
|
||||
regions[self.region_id]["bbox"] = [new_x, new_y, self.width(), self.height()]
|
||||
collector_mutex.unlock()
|
||||
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
"""
|
||||
Resets the drag/resize state once the mouse button is released.
|
||||
"""
|
||||
self.selected_handle = None
|
||||
self.drag_offset = None
|
||||
|
Loading…
x
Reference in New Issue
Block a user