125 lines
4.7 KiB
Python
125 lines
4.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
This module contains the WordClickMode
|
|
"""
|
|
from pyqode.core.api.decoration import TextDecoration
|
|
from pyqode.core.api.mode import Mode
|
|
from pyqode.qt import QtCore, QtGui
|
|
from pyqode.core.api import TextHelper, DelayJobRunner
|
|
|
|
|
|
class WordClickMode(Mode, QtCore.QObject):
|
|
""" Adds support for word click events.
|
|
|
|
It will highlight the click-able word when the user press control and move
|
|
the mouse over a word.
|
|
|
|
Detecting whether a word is click-able is the responsability of the
|
|
subclasses. You must override ``_check_word_cursor`` and call
|
|
``_select_word_cursor`` if this is a click-able word (this
|
|
process might be asynchrone) otherwise _clear_selection.
|
|
|
|
:attr:`pyqode.core.modes.WordClickMode.word_clicked` is emitted
|
|
when the word is clicked by the user (while keeping control pressed).
|
|
"""
|
|
#: Signal emitted when a word is clicked. The parameter is a
|
|
#: QTextCursor with the clicked word set as the selected text.
|
|
word_clicked = QtCore.Signal(QtGui.QTextCursor)
|
|
|
|
def __init__(self):
|
|
QtCore.QObject.__init__(self)
|
|
Mode.__init__(self)
|
|
self._previous_cursor_start = -1
|
|
self._previous_cursor_end = -1
|
|
self._deco = None
|
|
self._cursor = None
|
|
self._timer = DelayJobRunner(delay=200)
|
|
|
|
def on_state_changed(self, state):
|
|
if state:
|
|
self.editor.mouse_moved.connect(self._on_mouse_moved)
|
|
self.editor.mouse_pressed.connect(self._on_mouse_pressed)
|
|
self.editor.key_released.connect(self._on_key_released)
|
|
self.editor.mouse_double_clicked.connect(
|
|
self._on_mouse_double_clicked)
|
|
else:
|
|
self.editor.mouse_moved.disconnect(self._on_mouse_moved)
|
|
self.editor.mouse_pressed.disconnect(self._on_mouse_pressed)
|
|
self.editor.mouse_double_clicked.disconnect(
|
|
self._on_mouse_double_clicked)
|
|
|
|
def _on_mouse_double_clicked(self):
|
|
self._timer.cancel_requests()
|
|
|
|
def _on_key_released(self, event):
|
|
if event.key() == QtCore.Qt.Key_Control:
|
|
self._clear_selection()
|
|
self._cursor = None
|
|
|
|
def _select_word_cursor(self):
|
|
""" Selects the word under the mouse cursor. """
|
|
cursor = TextHelper(self.editor).word_under_mouse_cursor()
|
|
if (self._previous_cursor_start != cursor.selectionStart() and
|
|
self._previous_cursor_end != cursor.selectionEnd()):
|
|
self._remove_decoration()
|
|
self._add_decoration(cursor)
|
|
self._previous_cursor_start = cursor.selectionStart()
|
|
self._previous_cursor_end = cursor.selectionEnd()
|
|
|
|
def _clear_selection(self):
|
|
try:
|
|
self._remove_decoration()
|
|
except ValueError:
|
|
pass
|
|
self.editor.set_mouse_cursor(QtCore.Qt.IBeamCursor)
|
|
self._previous_cursor_start = -1
|
|
self._previous_cursor_end = -1
|
|
|
|
def _on_mouse_moved(self, event):
|
|
""" mouse moved callback """
|
|
if event.modifiers() & QtCore.Qt.ControlModifier:
|
|
cursor = TextHelper(self.editor).word_under_mouse_cursor()
|
|
if (not self._cursor or
|
|
cursor.position() != self._cursor.position()):
|
|
self._check_word_cursor(cursor)
|
|
self._cursor = cursor
|
|
else:
|
|
self._cursor = None
|
|
self._clear_selection()
|
|
|
|
def _check_word_under_mouse_cursor(self, cursor):
|
|
raise NotImplementedError()
|
|
|
|
def _on_mouse_pressed(self, event):
|
|
""" mouse pressed callback """
|
|
if event.button() == 1 and self._deco:
|
|
cursor = TextHelper(self.editor).word_under_mouse_cursor()
|
|
if cursor and cursor.selectedText():
|
|
self._timer.request_job(
|
|
self.word_clicked.emit, cursor)
|
|
|
|
def _add_decoration(self, cursor):
|
|
"""
|
|
Adds a decoration for the word under ``cursor``.
|
|
"""
|
|
if self._deco is None:
|
|
if cursor.selectedText():
|
|
self._deco = TextDecoration(cursor)
|
|
if self.editor.background.lightness() < 128:
|
|
self._deco.set_foreground(QtGui.QColor('#0681e0'))
|
|
else:
|
|
self._deco.set_foreground(QtCore.Qt.blue)
|
|
self._deco.set_as_underlined()
|
|
self.editor.decorations.append(self._deco)
|
|
self.editor.set_mouse_cursor(QtCore.Qt.PointingHandCursor)
|
|
else:
|
|
self.editor.set_mouse_cursor(QtCore.Qt.IBeamCursor)
|
|
|
|
def _remove_decoration(self):
|
|
"""
|
|
Removes the word under cursor's decoration
|
|
"""
|
|
if self._deco is not None:
|
|
self.editor.decorations.remove(self._deco)
|
|
self._deco = None
|