1 /*
2 * Copyright (C) 2011, 2012, 2013 Nicolas Bonnefon and other contributors
3 *
4 * This file is part of glogg.
5 *
6 * glogg 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 3 of the License, or
9 * (at your option) any later version.
10 *
11 * glogg 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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with glogg. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 // This file implements OverviewWidget. This class is responsable for
21 // managing and painting the matches overview widget.
22
23 #include <QPainter>
24 #include <QMouseEvent>
25 #include <cassert>
26
27 #include "log.h"
28
29 #include "overviewwidget.h"
30
31 #include "overview.h"
32
33 // Graphic parameters
34 const int OverviewWidget::LINE_MARGIN = 4;
35 const int OverviewWidget::STEP_DURATION_MS = 30;
36 const int OverviewWidget::INITIAL_TTL_VALUE = 5;
37
38 #define HIGHLIGHT_XPM_WIDTH 27
39 #define HIGHLIGHT_XPM_HEIGHT 9
40
41 #define S(x) #x
42 #define SX(x) S(x)
43
44 // width height colours char/pixel
45 // Colours
46 #define HIGHLIGHT_XPM_LEAD_LINE SX(HIGHLIGHT_XPM_WIDTH) " " SX(HIGHLIGHT_XPM_HEIGHT) " 2 1",\
47 " s mask c none",\
48 "x c #572F80"
49
50 const char* const highlight_xpm[][14] = {
51 {
52 HIGHLIGHT_XPM_LEAD_LINE,
53 " ",
54 " ",
55 " xxxxxxxxxxxxxxxxxxxxx ",
56 " xxxxxxxxxxxxxxxxxxxxx ",
57 " xx xx ",
58 " xx xx ",
59 " xx xx ",
60 " xxxxxxxxxxxxxxxxxxxxx ",
61 " xxxxxxxxxxxxxxxxxxxxx ",
62 " ",
63 " ",
64 },
65 {
66 HIGHLIGHT_XPM_LEAD_LINE,
67 " ",
68 " xxxxxxxxxxxxxxxxxxxxxxx ",
69 " xxxxxxxxxxxxxxxxxxxxxxx ",
70 " xxxxxxxxxxxxxxxxxxxxxxx ",
71 " xxx xxx ",
72 " xxx xxx ",
73 " xxx xxx ",
74 " xxxxxxxxxxxxxxxxxxxxxxx ",
75 " xxxxxxxxxxxxxxxxxxxxxxx ",
76 " xxxxxxxxxxxxxxxxxxxxxxx ",
77 " ",
78 },
79 {
80 HIGHLIGHT_XPM_LEAD_LINE,
81 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
82 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
83 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
84 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
85 " xxxx xxxx ",
86 " xxxx xxxx ",
87 " xxxx xxxx ",
88 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
89 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
90 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
91 " xxxxxxxxxxxxxxxxxxxxxxxxx ",
92 },
93 {
94 HIGHLIGHT_XPM_LEAD_LINE,
95 " ",
96 " xxxxxxxxxxxxxxxxxxxxxxx ",
97 " xxxxxxxxxxxxxxxxxxxxxxx ",
98 " xxxxxxxxxxxxxxxxxxxxxxx ",
99 " xxx xxx ",
100 " xxx xxx ",
101 " xxx xxx ",
102 " xxxxxxxxxxxxxxxxxxxxxxx ",
103 " xxxxxxxxxxxxxxxxxxxxxxx ",
104 " xxxxxxxxxxxxxxxxxxxxxxx ",
105 " ",
106 },
107 {
108 HIGHLIGHT_XPM_LEAD_LINE,
109 " ",
110 " ",
111 " xxxxxxxxxxxxxxxxxxxxx ",
112 " xxxxxxxxxxxxxxxxxxxxx ",
113 " xx xx ",
114 " xx xx ",
115 " xx xx ",
116 " xxxxxxxxxxxxxxxxxxxxx ",
117 " xxxxxxxxxxxxxxxxxxxxx ",
118 " ",
119 " ",
120 },
121 {
122 HIGHLIGHT_XPM_LEAD_LINE,
123 " ",
124 " ",
125 " ",
126 " xxxxxxxxxxxxxxxxxxx ",
127 " x x ",
128 " x x ",
129 " x x ",
130 " xxxxxxxxxxxxxxxxxxx ",
131 " ",
132 " ",
133 " ",
134 },
135 };
136
OverviewWidget(QWidget * parent)137 OverviewWidget::OverviewWidget( QWidget* parent ) :
138 QWidget( parent ), highlightTimer_()
139 {
140 overview_ = NULL;
141
142 setBackgroundRole( QPalette::Window );
143
144 // Highlight
145 highlightedLine_ = -1;
146 highlightedTTL_ = 0;
147
148 // We should be hidden by default (e.g. for the FilteredView)
149 hide();
150 }
151
paintEvent(QPaintEvent *)152 void OverviewWidget::paintEvent( QPaintEvent* /* paintEvent */ )
153 {
154 static const QColor match_color("red");
155 static const QColor mark_color("dodgerblue");
156
157 static const QPixmap highlight_pixmap[] = {
158 QPixmap( highlight_xpm[0] ),
159 QPixmap( highlight_xpm[1] ),
160 QPixmap( highlight_xpm[2] ),
161 QPixmap( highlight_xpm[3] ),
162 QPixmap( highlight_xpm[4] ),
163 QPixmap( highlight_xpm[5] ), };
164
165 // We must be hidden until we have an Overview
166 assert( overview_ != NULL );
167
168 overview_->updateView( height() );
169
170 {
171 QPainter painter( this );
172
173 painter.fillRect( painter.viewport(), painter.background() );
174
175 // The line separating from the main view
176 painter.setPen( palette().color(QPalette::Text) );
177 painter.drawLine( 0, 0, 0, height() );
178
179 // The 'match' lines
180 painter.setPen( match_color );
181 foreach (Overview::WeightedLine line, *(overview_->getMatchLines()) ) {
182 painter.setOpacity( ( 1.0 / Overview::WeightedLine::WEIGHT_STEPS )
183 * ( line.weight() + 1 ) );
184 // (allow multiple matches to look 'darker' than a single one.)
185 painter.drawLine( 1 + LINE_MARGIN,
186 line.position(), width() - LINE_MARGIN - 1, line.position() );
187 }
188
189 // The 'mark' lines
190 painter.setPen( mark_color );
191 foreach (Overview::WeightedLine line, *(overview_->getMarkLines()) ) {
192 painter.setOpacity( ( 1.0 / Overview::WeightedLine::WEIGHT_STEPS )
193 * ( line.weight() + 1 ) );
194 // (allow multiple matches to look 'darker' than a single one.)
195 painter.drawLine( 1 + LINE_MARGIN,
196 line.position(), width() - LINE_MARGIN - 1, line.position() );
197 }
198
199 // The 'view' lines
200 painter.setOpacity( 1 );
201 painter.setPen( palette().color(QPalette::Text) );
202 std::pair<int,int> view_lines = overview_->getViewLines();
203 painter.drawLine( 1, view_lines.first, width(), view_lines.first );
204 painter.drawLine( 1, view_lines.second, width(), view_lines.second );
205
206 // The highlight
207 if ( highlightedLine_ >= 0 ) {
208 /*
209 QPen highlight_pen( palette().color(QPalette::Text) );
210 highlight_pen.setWidth( 4 - highlightedTTL_ );
211 painter.setOpacity( 1 );
212 painter.setPen( highlight_pen );
213 painter.drawRect( 2, position - 2, width() - 2 - 2, 4 );
214 */
215 int position = overview_->yFromFileLine( highlightedLine_ );
216 painter.drawPixmap(
217 ( width() - HIGHLIGHT_XPM_WIDTH ) / 2,
218 position - ( HIGHLIGHT_XPM_HEIGHT / 2 ),
219 highlight_pixmap[ INITIAL_TTL_VALUE - highlightedTTL_ ] );
220 }
221 }
222 }
223
mousePressEvent(QMouseEvent * mouseEvent)224 void OverviewWidget::mousePressEvent( QMouseEvent* mouseEvent )
225 {
226 if ( mouseEvent->button() == Qt::LeftButton )
227 handleMousePress( mouseEvent->y() );
228 }
229
mouseMoveEvent(QMouseEvent * mouseEvent)230 void OverviewWidget::mouseMoveEvent( QMouseEvent* mouseEvent )
231 {
232 if ( mouseEvent->buttons().testFlag( Qt::LeftButton ) )
233 handleMousePress( mouseEvent->y() );
234 }
235
handleMousePress(int position)236 void OverviewWidget::handleMousePress( int position )
237 {
238 int line = overview_->fileLineFromY( position );
239 LOG(logDEBUG) << "OverviewWidget::handleMousePress y=" << position << " line=" << line;
240 emit lineClicked( line );
241 }
242
highlightLine(qint64 line)243 void OverviewWidget::highlightLine( qint64 line )
244 {
245 highlightTimer_.stop();
246
247 highlightedLine_ = line;
248 highlightedTTL_ = INITIAL_TTL_VALUE;
249
250 update();
251 highlightTimer_.start( STEP_DURATION_MS, this );
252 }
253
removeHighlight()254 void OverviewWidget::removeHighlight()
255 {
256 highlightTimer_.stop();
257
258 highlightedLine_ = -1;
259 update();
260 }
261
timerEvent(QTimerEvent * event)262 void OverviewWidget::timerEvent( QTimerEvent* event )
263 {
264 if ( event->timerId() == highlightTimer_.timerId() ) {
265 LOG(logDEBUG) << "OverviewWidget::timerEvent";
266 if ( highlightedTTL_ > 0 ) {
267 --highlightedTTL_;
268 update();
269 }
270 else {
271 highlightTimer_.stop();
272 }
273 }
274 else {
275 QObject::timerEvent( event );
276 }
277 }
278