Skip to content
Open
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
104 changes: 62 additions & 42 deletions TutorialMaker/Lib/Annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def __init__(self,
self.boundingBoxBottomRight = [0,0]
self.__selectionSlideEffect = 0

self.caretVisible = True
self.caretPosition = len(self.text)

# Need to change this later, make it loaded through resources
self.icon_click = qt.QImage(os.path.dirname(__file__) + '/../Resources/Icons/Painter/click_icon.png')
self.icon_click = self.icon_click.scaled(20,30)
Expand All @@ -70,7 +73,7 @@ def getSelectionBoundingBoxSize(self):
return [self.boundingBoxBottomRight[0] - self.boundingBoxTopLeft[0], self.boundingBoxBottomRight[1] - self.boundingBoxTopLeft[1]]

def wantsOptHelper(self):
return self.type in AnnotationType.Arrow | AnnotationType.TextBox | AnnotationType.ArrowText
return self.type in AnnotationType.Arrow | AnnotationType.ArrowText

def wantsOffsetHelper(self):
return self.type in AnnotationType.Click | AnnotationType.TextBox
Expand Down Expand Up @@ -109,6 +112,26 @@ def penConfig(self, color, fontSize, thickness, brush = None, pen = None):
self.fontSize = fontSize
pass

def drawCaret(self, painter, fontMetrics, textStart, textLines):

if not getattr(self, "caretVisible", True):
return

caretLine = min(self.text[:self.caretPosition].count('\n'), max(len(textLines)-1, 0))
lineStartIndex = sum(len(l)+1 for l in textLines[:caretLine])
caretCol = self.caretPosition - lineStartIndex
caretCol = max(0, min(caretCol, len(textLines[caretLine])))

caretX = textStart[0] + fontMetrics.width(textLines[caretLine][:caretCol])
fHeight = fontMetrics.height()
lineSpacing = 2
caretYTop = textStart[1] - fHeight + lineSpacing + fHeight * caretLine
caretYBottom = caretYTop + fHeight

painter.drawLine(caretX, caretYTop, caretX, caretYBottom)



def draw(self, painter : qt.QPainter = None, pen : qt.QPen = None, brush :qt.QBrush = None):
#Maybe we can organize this better
targetPos = [self.target["position"][0] - self.annotationOffset[0] + self.offsetX,
Expand Down Expand Up @@ -265,6 +288,8 @@ def draw(self, painter : qt.QPainter = None, pen : qt.QPen = None, brush :qt.QBr
for lineIndex, line in enumerate(textLines):
painter.drawText(textStart[0], textStart[1] + lineSpacing + fHeight * lineIndex, line)

self.drawCaret(painter, fontMetrics, textStart, textLines)

self.setSelectionBoundingBox(arrowHead[0], arrowHead[1], arrowTail[0], arrowTail[1])


Expand All @@ -282,68 +307,63 @@ def draw(self, painter : qt.QPainter = None, pen : qt.QPen = None, brush :qt.QBr
elif self.type == AnnotationType.Circle:
pass
elif self.type == AnnotationType.TextBox:
# So the box will be filled
brush.setStyle(qt.Qt.SolidPattern)
painter.setBrush(brush)

# Padding

yPadding = 6
xPadding = 6
lineSpacing = 2

optX = self.optX - targetCenter[0]
optY = self.optY - targetCenter[1]

topLeft = qt.QPoint(targetPos[0], targetPos[1])
bottomRight = qt.QPoint(targetPos[0] + optX, targetPos[1] + optY)
rectToDraw = qt.QRect(topLeft,bottomRight)
painter.drawRect(rectToDraw)

# Calculate the text break and position
font = qt.QFont("Arial", self.fontSize)
painter.setFont(font)
pen.setColor(qt.Qt.black)
painter.setPen(pen)

fontMetrics = qt.QFontMetrics(font)
fHeight = fontMetrics.height()

textBoxBottomRight = [targetPos[0] + optX, targetPos[1] + optY]
textBoxTopLeft = [targetPos[0], targetPos[1]]
textToWrite = self.text if self.text else _("Write something here")
textTokens = textToWrite.splitlines(keepends=True)
textLines = []
line = ""
for token in textTokens:
if "\n" in token:
if line:
textLines.append(line)
textLines.append(token.rstrip("\n"))
line = ""
continue

if textBoxBottomRight[0] < textBoxTopLeft[0]:
tmp = textBoxTopLeft[0]
textBoxTopLeft[0] = textBoxBottomRight[0]
textBoxBottomRight[0] = tmp
if fontMetrics.width(line + token) > 200: # ancho por defecto inicial
if line:
textLines.append(line)
line = token
else:
line += token
if line:
textLines.append(line)

if textBoxBottomRight[1] < textBoxTopLeft[1]:
tmp = textBoxTopLeft[1]
textBoxTopLeft[1] = textBoxBottomRight[1]
textBoxBottomRight[1] = tmp
textWidth = max((fontMetrics.width(line) for line in textLines), default=0) + 2*xPadding
textHeight = len(textLines) * fHeight + (len(textLines)-1)*lineSpacing + 2*yPadding

textStart = [textBoxTopLeft[0] + xPadding,
textBoxTopLeft[1] + yPadding + fHeight]
if not hasattr(self, "_userSetSize"):
bottomRight = [targetPos[0] + textWidth, targetPos[1] + textHeight]
else:
bottomRight = [targetPos[0] + self.optX, targetPos[1] + self.optY]

textToWrite = self.text
if textToWrite == "":
textToWrite = _("Write something here")
topLeft = [targetPos[0], targetPos[1]]

textTokens = textToWrite.splitlines()
textLines = []
line = ""
for token in textTokens:
if fontMetrics.width(line + token) > textBoxBottomRight[0] - textBoxTopLeft[0] - xPadding:
textLines.append(copy.deepcopy(line))
line = f"{token} "
continue
line += f"{token} "
textLines.append(line)
rectToDraw = qt.QRect(qt.QPoint(*topLeft), qt.QPoint(*bottomRight))
painter.drawRect(rectToDraw)

textStart = [topLeft[0] + xPadding, topLeft[1] + yPadding + fHeight]

for lineIndex, line in enumerate(textLines):
painter.drawText(textStart[0], textStart[1] + lineSpacing + fHeight*lineIndex, line)
painter.drawText(textStart[0], textStart[1] + lineSpacing + fHeight * lineIndex, line)

self.drawCaret(painter, fontMetrics, textStart, textLines)

self.setSelectionBoundingBox(topLeft[0], topLeft[1], bottomRight[0], bottomRight[1])


self.setSelectionBoundingBox(targetPos[0], targetPos[1], targetPos[0] + optX, targetPos[1] + optY)

elif self.type == AnnotationType.Click:
bottomRight = [targetPos[0] + targetSize[0],
Expand Down
62 changes: 48 additions & 14 deletions TutorialMaker/Lib/TutorialGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,33 +757,65 @@ def keyboardEvent(self, event):
self.setFocus()
return False

if self.selectedAnnotationType == AnnotationType.Selected:
if self.selectedAnnotationType == AnnotationType.Selected and self.selectedAnnotation is not None:
ann = self.selectedAnnotation


if event.key() == qt.Qt.Key_Delete:
self.selectedAnnotation.PERSISTENT = False
ann.PERSISTENT = False
self.cancelCurrentAnnotation()

elif self.selectedAnnotation.type in [AnnotationType.TextBox, AnnotationType.ArrowText]:
# Detect command Ctrl+C copy text

elif ann.type in [AnnotationType.TextBox, AnnotationType.ArrowText]:

if event.key() == qt.Qt.Key_C and event.modifiers() & qt.Qt.ControlModifier:
qt.QApplication.clipboard().setText(self.selectedAnnotation.text)

# Detect command Ctl+v page text
qt.QApplication.clipboard().setText(ann.text)

elif event.key() == qt.Qt.Key_V and event.modifiers() & qt.Qt.ControlModifier:
self.selectedAnnotation.text += qt.QApplication.clipboard().text()
ann.text = ann.text[:ann.caretPosition] + qt.QApplication.clipboard().text() + ann.text[ann.caretPosition:]
ann.caretPosition += len(qt.QApplication.clipboard().text())
ann.caretPosition = max(0, min(ann.caretPosition, len(ann.text)))

# Detect Enter to add a line break
elif event.key() in [qt.Qt.Key_Return, qt.Qt.Key_Enter]:
self.selectedAnnotation.text += "\n"
try:
ann.text = ann.text[:ann.caretPosition] + "\n" + ann.text[ann.caretPosition:]
ann.caretPosition += 1
ann.caretPosition = max(0, min(ann.caretPosition, len(ann.text)))
except Exception as e:
import traceback
traceback.print_exc()

# Detect Backspace
elif event.key() == qt.Qt.Key_Backspace:
self.selectedAnnotation.text = self.selectedAnnotation.text[:-1]
if ann.caretPosition > 0:
ann.text = ann.text[:ann.caretPosition-1] + ann.text[ann.caretPosition:]
ann.caretPosition -= 1
ann.caretPosition = max(0, min(ann.caretPosition, len(ann.text)))

elif event.key() == qt.Qt.Key_Left:
ann.caretPosition -= 1
ann.caretPosition = max(0, ann.caretPosition)
elif event.key() == qt.Qt.Key_Right:
ann.caretPosition += 1
ann.caretPosition = min(len(ann.text), ann.caretPosition)
elif event.key() == qt.Qt.Key_Home:
lines = ann.text.splitlines(keepends=True)
lineIndex = ann.text[:ann.caretPosition].count('\n')
lineStart = sum(len(l) for l in lines[:lineIndex])
ann.caretPosition = lineStart
elif event.key() == qt.Qt.Key_End:
lines = ann.text.splitlines(keepends=True)
lineIndex = ann.text[:ann.caretPosition].count('\n')
lineStart = sum(len(l) for l in lines[:lineIndex])
ann.caretPosition = lineStart + len(lines[lineIndex])

else:
self.selectedAnnotation.text += event.text()
ann.text = ann.text[:ann.caretPosition] + event.text() + ann.text[ann.caretPosition:]
ann.caretPosition += len(event.text())
ann.caretPosition = max(0, min(ann.caretPosition, len(ann.text)))

return True
return True

# --- Navegar entre anotaciones con flechas ---
elif self.selectedAnnotator is not None and self.selectedAnnotation is not None:
if event.key() == qt.Qt.Key_Up:
self.selectorParentDelta(-1)
Expand All @@ -795,6 +827,8 @@ def keyboardEvent(self, event):
return False




def selectorParentDelta(self, delta : int):
self.selectorParentCount += delta
self.previewAnnotation(self.lastAppPos)
Expand Down
Loading