File indexing completed on 2024-04-28 07:46:50
0001 /* 0002 SPDX-FileCopyrightText: 2013-2018 Dominik Haumann <dhaumann@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "katetextanimation.h" 0008 0009 #include "katerenderer.h" 0010 #include "kateview.h" 0011 #include "kateviewinternal.h" 0012 #include <ktexteditor/document.h> 0013 0014 #include <QPainter> 0015 #include <QPointF> 0016 #include <QRect> 0017 #include <QSizeF> 0018 #include <QTimeLine> 0019 0020 KateTextAnimation::KateTextAnimation(KTextEditor::Range range, KTextEditor::Attribute::Ptr attribute, KateViewInternal *view) 0021 : QObject(view) 0022 , m_range(range) 0023 , m_text(view->view()->document()->text(range)) 0024 , m_attribute(std::move(attribute)) 0025 , m_doc(view->view()->doc()) 0026 , m_view(view) 0027 , m_timeLine(new QTimeLine(250, this)) 0028 , m_value(0.0) 0029 { 0030 connect(m_timeLine, &QTimeLine::valueChanged, this, &KateTextAnimation::nextFrame); 0031 connect(m_timeLine, &QTimeLine::finished, this, &KateTextAnimation::deleteLater); 0032 0033 m_timeLine->setEasingCurve(QEasingCurve::SineCurve); 0034 m_timeLine->start(); 0035 0036 QObject::connect(view, &KTextEditor::View::destroyed, m_timeLine, &QTimeLine::stop); 0037 } 0038 0039 KateTextAnimation::~KateTextAnimation() 0040 { 0041 // if still running, we need to update the view a last time to avoid artifacts 0042 if (m_timeLine->state() == QTimeLine::Running) { 0043 m_timeLine->stop(); 0044 nextFrame(0.0); 0045 } 0046 } 0047 0048 QRectF KateTextAnimation::rectForText() 0049 { 0050 const QFontMetricsF fm = m_view->view()->renderer()->currentFontMetrics(); 0051 const int lineHeight = m_view->view()->renderer()->lineHeight(); 0052 QPoint pixelPos = m_view->cursorToCoordinate(m_range.start(), /*bool realCursor*/ true, /*bool includeBorder*/ false); 0053 0054 if (pixelPos.x() == -1 || pixelPos.y() == -1) { 0055 return QRectF(); 0056 } else { 0057 QRectF rect(pixelPos.x(), pixelPos.y(), fm.boundingRect(m_view->view()->document()->text(m_range)).width(), lineHeight); 0058 const QPointF center = rect.center(); 0059 const qreal factor = 1.0 + 0.5 * m_value; 0060 rect.setWidth(rect.width() * factor); 0061 rect.setHeight(rect.height() * factor); 0062 rect.moveCenter(center); 0063 return rect; 0064 } 0065 } 0066 0067 void KateTextAnimation::draw(QPainter &painter) 0068 { 0069 // could happen in corner cases: timeLine emitted finished(), but this object 0070 // is not yet deleted. Therefore, draw() might be called in paintEvent(). 0071 if (m_timeLine->state() == QTimeLine::NotRunning) { 0072 return; 0073 } 0074 0075 // get current rect and fill background 0076 QRectF rect = rectForText(); 0077 painter.fillRect(rect, m_attribute->background()); 0078 0079 // scale font with animation 0080 QFont f = m_view->view()->renderer()->currentFont(); 0081 f.setBold(m_attribute->fontBold()); 0082 f.setPointSizeF(f.pointSizeF() * (1.0 + 0.5 * m_value)); 0083 painter.setFont(f); 0084 0085 painter.setPen(m_attribute->foreground().color()); 0086 // finally draw contents on the view 0087 painter.drawText(rect, m_text); 0088 } 0089 0090 void KateTextAnimation::nextFrame(qreal value) 0091 { 0092 // cache previous rect for update 0093 const QRectF prevRect = rectForText(); 0094 0095 m_value = value; 0096 0097 // next rect is used to draw the text 0098 const QRectF nextRect = rectForText(); 0099 0100 // due to rounding errors, increase the rect 1px to avoid artifacts 0101 const QRect updateRect = nextRect.united(prevRect).adjusted(-1, -1, 1, 1).toRect(); 0102 0103 // request repaint 0104 m_view->update(updateRect); 0105 }