1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2014 by Wilbert Berendsen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# See http://www.gnu.org/licenses/ for more information.
"""
Shortly blinks a region on a widget.
"""
from PyQt5.QtCore import QTimer, pyqtSignal
from PyQt5.QtGui import QColor, QFontMetrics, QPainter, QPalette, QPen
from PyQt5.QtWidgets import QWidget
class Blinker(QWidget):
"""Can draw a blinking region above its parent widget."""
finished = pyqtSignal()
lineWidth = 3
radius = 3
@classmethod
def blink(cls, widget, rect=None, color=None):
"""Shortly blinks a rectangular region on a widget.
If rect is not given, the full rect() of the widget is used.
If color is not given, the highlight color of the widget is used.
This method instantiates a Blinker widget and discards it after use.
"""
window = widget.window()
if rect is None:
rect = widget.rect()
rect.moveTo(widget.mapTo(window, rect.topLeft()))
b = cls(window)
p = widget.palette()
if color:
p.setColor(QPalette.Highlight, color)
b.setPalette(p)
b.start(rect)
b.finished.connect(b.deleteLater)
@classmethod
def blink_cursor(cls, textedit, color=None):
"""Highlights the cursor in a Q(Plain)TextEdit."""
metrics = QFontMetrics(textedit.textCursor().charFormat().font())
width = metrics.boundingRect("m").width()
rect = textedit.cursorRect().normalized().adjusted(0, 0, width, 0)
cls.blink(textedit, rect.translated(textedit.viewport().pos()), color)
def __init__(self, widget):
"""Initializes ourselves to draw on the widget."""
super(Blinker, self).__init__(widget)
self._color = None
self._animation = ()
self._timer = QTimer(singleShot=True, timeout=self._updateAnimation)
def start(self, rect):
"""Starts blinking the specified rectangle."""
self._blink_rect = rect
adj = self.lineWidth
self.setGeometry(rect.adjusted(-adj, -adj, adj, adj))
self.show()
self._animation = self.animateColor()
self._updateAnimation()
def done(self):
"""(Internal) Called when the animation ends."""
self.hide()
self._animation = ()
self.finished.emit()
def _updateAnimation(self):
for delta, self._color in self._animation:
self.update()
self._timer.start(delta)
return
self.done()
def animateColor(self):
"""A generator yielding tuples (msec_delta, color) to animate colors.
When the generator exits, the animation ends.
The color is taken from the Highlight palette value.
"""
color = self.palette().color(QPalette.Highlight)
for delta, alpha in self.animateAlpha():
color.setAlpha(alpha)
yield delta, color
def animateAlpha(self):
"""A generator yielding (msec_delta, alpha) tuples."""
for alpha in (255, 0, 255, 0, 255):
yield 120, alpha
for alpha in range(255, 0, -15):
yield 40, alpha
def paintEvent(self, ev):
color = self._color
if not color or color.alpha() == 0:
return
painter = QPainter(self)
adj = self.lineWidth // 2
rect = self.rect().adjusted(adj, adj, -adj, -adj)
pen = QPen(color)
pen.setWidth(self.lineWidth)
painter.setPen(pen)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.drawRoundedRect(rect, self.radius, self.radius)
|