Ensure checkbox only can get checked on/off if it is clicked right on its block position, not any click on the whole line
This commit is contained in:
parent
dfde0d6e6c
commit
bc9fa86281
1 changed files with 66 additions and 26 deletions
|
|
@ -8,6 +8,7 @@ from PySide6.QtGui import (
|
|||
QColor,
|
||||
QFont,
|
||||
QFontDatabase,
|
||||
QFontMetrics,
|
||||
QImage,
|
||||
QPalette,
|
||||
QGuiApplication,
|
||||
|
|
@ -17,7 +18,7 @@ from PySide6.QtGui import (
|
|||
QSyntaxHighlighter,
|
||||
QTextImageFormat,
|
||||
)
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtCore import Qt, QRect
|
||||
from PySide6.QtWidgets import QTextEdit
|
||||
|
||||
from .theme import ThemeManager, Theme
|
||||
|
|
@ -525,34 +526,73 @@ class MarkdownEditor(QTextEdit):
|
|||
super().keyPressEvent(event)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""Handle mouse clicks - check for checkbox clicking."""
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
cursor = self.cursorForPosition(event.pos())
|
||||
cursor.select(QTextCursor.SelectionType.LineUnderCursor)
|
||||
line = cursor.selectedText()
|
||||
"""Toggle a checkbox only when the click lands on its icon."""
|
||||
if event.button() == Qt.LeftButton:
|
||||
pt = event.pos()
|
||||
|
||||
# Check if clicking on a checkbox line
|
||||
if (
|
||||
f"{self._CHECK_UNCHECKED_DISPLAY} " in line
|
||||
or f"{self._CHECK_CHECKED_DISPLAY} " in line
|
||||
):
|
||||
# Toggle the checkbox
|
||||
if f"{self._CHECK_UNCHECKED_DISPLAY} " in line:
|
||||
new_line = line.replace(
|
||||
f"{self._CHECK_UNCHECKED_DISPLAY} ",
|
||||
f"{self._CHECK_CHECKED_DISPLAY} ",
|
||||
)
|
||||
# Cursor and block under the mouse
|
||||
cur = self.cursorForPosition(pt)
|
||||
block = cur.block()
|
||||
text = block.text()
|
||||
|
||||
# The display tokens, e.g. "☐ " / "☑ " (icon + trailing space)
|
||||
unchecked = f"{self._CHECK_UNCHECKED_DISPLAY} "
|
||||
checked = f"{self._CHECK_CHECKED_DISPLAY} "
|
||||
|
||||
# Helper: rect for a single character at a given doc position
|
||||
def char_rect_at(doc_pos, ch):
|
||||
c = QTextCursor(self.document())
|
||||
c.setPosition(doc_pos)
|
||||
start_rect = self.cursorRect(
|
||||
c
|
||||
) # caret rect at char start (viewport coords)
|
||||
|
||||
# Use the actual font at this position for an accurate width
|
||||
fmt_font = (
|
||||
c.charFormat().font() if c.charFormat().isValid() else self.font()
|
||||
)
|
||||
fm = QFontMetrics(fmt_font)
|
||||
w = max(1, fm.horizontalAdvance(ch))
|
||||
return QRect(start_rect.x(), start_rect.y(), w, start_rect.height())
|
||||
|
||||
# Scan the line for any checkbox icons; toggle the one we clicked
|
||||
i = 0
|
||||
while i < len(text):
|
||||
icon = None
|
||||
if text.startswith(unchecked, i):
|
||||
icon = self._CHECK_UNCHECKED_DISPLAY
|
||||
elif text.startswith(checked, i):
|
||||
icon = self._CHECK_CHECKED_DISPLAY
|
||||
|
||||
if icon:
|
||||
doc_pos = (
|
||||
block.position() + i
|
||||
) # absolute document position of the icon
|
||||
r = char_rect_at(doc_pos, icon)
|
||||
|
||||
if r.contains(pt):
|
||||
# Build the replacement: swap ☐ <-> ☑ (keep trailing space)
|
||||
new_icon = (
|
||||
self._CHECK_CHECKED_DISPLAY
|
||||
if icon == self._CHECK_UNCHECKED_DISPLAY
|
||||
else self._CHECK_UNCHECKED_DISPLAY
|
||||
)
|
||||
edit = QTextCursor(self.document())
|
||||
edit.beginEditBlock()
|
||||
edit.setPosition(doc_pos)
|
||||
edit.movePosition(
|
||||
QTextCursor.Right, QTextCursor.KeepAnchor, len(icon) + 1
|
||||
) # icon + space
|
||||
edit.insertText(f"{new_icon} ")
|
||||
edit.endEditBlock()
|
||||
return # handled
|
||||
|
||||
# advance past this token
|
||||
i += len(icon) + 1
|
||||
else:
|
||||
new_line = line.replace(
|
||||
f"{self._CHECK_CHECKED_DISPLAY} ",
|
||||
f"{self._CHECK_UNCHECKED_DISPLAY} ",
|
||||
)
|
||||
i += 1
|
||||
|
||||
cursor.insertText(new_line)
|
||||
# Don't call super() - we handled the click
|
||||
return
|
||||
|
||||
# Default handling for non-checkbox clicks
|
||||
# Default handling for anything else
|
||||
super().mousePressEvent(event)
|
||||
|
||||
# ------------------------ Toolbar action handlers ------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue