Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / editors / sc-ide / widgets / code_editor / overlay.cpp
blob10bd2abf01a7ab3f8eaab11350db09b69546b6c7
1 /*
2 SuperCollider Qt IDE
3 Copyright (c) 2012 Jakob Leben & Tim Blechmann
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "overlay.hpp"
22 #include "sc_editor.hpp"
23 #include "../../core/main.hpp"
25 #include <QTextDocument>
26 #include <QTextLayout>
27 #include <QTextBlock>
28 #include <QPainter>
29 #include <QPropertyAnimation>
30 #include <QtCore/qmath.h>
31 #include <QDebug>
33 namespace ScIDE {
35 void ScCodeEditor::blinkCode( const QTextCursor & c )
37 if( !c.document() || !c.hasSelection() ) return;
39 Settings::Manager *settings = Main::settings();
40 settings->beginGroup("IDE/editor/colors");
41 QTextCharFormat evalCodeTextFormat = settings->value("evaluatedCode").value<QTextCharFormat>();
42 settings->endGroup();
44 QTextDocument *doc = c.document();
46 int startPos = c.selectionStart();
47 int endPos = c.selectionEnd();
48 QTextBlock startBlock = doc->findBlock(startPos);
49 QTextBlock endBlock = doc->findBlock(endPos);
50 startPos -= startBlock.position();
51 endPos -= endBlock.position();
53 // Get the bounds of visible blocks within the cursor's selection:
55 QTextBlock block = firstVisibleBlock();
56 int idx = block.blockNumber();
57 int sidx = startBlock.blockNumber();
59 QTextBlock firstBlock, lastBlock;
60 firstBlock = lastBlock = block;
62 QRectF geom = blockBoundingGeometry(block).translated(contentOffset());
63 qreal top = geom.top();
64 qreal bottom = top;
65 qreal width=0;
67 while(block.isValid() && bottom < viewport()->rect().height())
69 if(block.isVisible())
71 QTextLayout *l = block.layout();
72 QRectF r = l->boundingRect();
73 bottom += r.height();
74 if(idx < sidx) {
75 // Block not within the selection. Will skip it.
76 top = bottom;
78 else {
79 // Block within the selection.
80 width = qMax(width, l->maximumWidth() + r.left());
84 if(block == endBlock) break;
86 block = block.next();
87 ++idx;
88 if(top == bottom)
89 firstBlock = block;
92 lastBlock = block;
94 if(bottom == top) {
95 //qDebug("no visible block.");
96 return;
99 // Construct a pixmap to render the code on:
101 QPixmap pix( QSize(qCeil(width), qCeil(bottom - top)) );
102 pix.fill(QColor(0,0,0,0));
104 // Render the visible blocks:
106 QPainter painter(&pix);
107 QVector<QTextLayout::FormatRange> selections;
108 block = firstBlock;
109 int y=0;
110 while( block.isValid() )
112 if (block.isVisible())
114 QRectF blockRect = block.layout()->boundingRect();
116 // Use extra char formatting to hide code outside of selection
117 // and modify the appearance of selected code:
119 QTextLayout::FormatRange range;
120 selections.clear();
122 int start = 0;
123 if(block == startBlock) {
124 range.start = 0;
125 range.length = startPos;
126 range.format.setForeground(QColor(0,0,0,0));
127 range.format.setBackground(Qt::NoBrush);
128 selections.append(range);
129 start = startPos;
132 range.start = start;
133 range.length = (block == endBlock ? endPos : block.length() - 1) - range.start;
134 range.format = evalCodeTextFormat;
135 selections.append(range);
137 if(block == endBlock) {
138 range.start = range.start + range.length;
139 range.length = block.length() - 1 - range.start;
140 range.format.setForeground(QColor(0,0,0,0));
141 range.format.setBackground(Qt::NoBrush);
142 selections.append(range);
145 block.layout()->draw(&painter, QPointF(0,y), selections);
147 y += blockRect.height();
150 if(block == lastBlock) break;
152 block = block.next();
155 // Create an overlay item to display the pixmap, and animate it:
157 CodeFragmentOverlay *item = new CodeFragmentOverlay();
158 item->setPixmap(pix);
159 item->setPos(geom.left(), top);
161 mOverlay->addItem(item);
163 QPropertyAnimation *anim = new QPropertyAnimation(item, "opacity", item);
164 anim->setDuration(mBlinkDuration);
165 anim->setStartValue(1.0);
166 anim->setEndValue(0.0);
167 anim->setEasingCurve( QEasingCurve::InCubic );
168 anim->start();
170 connect(anim, SIGNAL(finished()), item, SLOT(deleteLater()));
173 } // namespace ScIDE