xref: /glogg/src/overviewwidget.cpp (revision 8b11848fd9995077713535870cee0df00a8eeea0)
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 
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 
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         // The line separating from the main view
174         painter.setPen( palette().color(QPalette::Text) );
175         painter.drawLine( 0, 0, 0, height() );
176 
177         // The 'match' lines
178         painter.setPen( match_color );
179         foreach (Overview::WeightedLine line, *(overview_->getMatchLines()) ) {
180             painter.setOpacity( ( 1.0 / Overview::WeightedLine::WEIGHT_STEPS )
181                    * ( line.weight() + 1 ) );
182             // (allow multiple matches to look 'darker' than a single one.)
183             painter.drawLine( 1 + LINE_MARGIN,
184                     line.position(), width() - LINE_MARGIN - 1, line.position() );
185         }
186 
187         // The 'mark' lines
188         painter.setPen( mark_color );
189         foreach (Overview::WeightedLine line, *(overview_->getMarkLines()) ) {
190             painter.setOpacity( ( 1.0 / Overview::WeightedLine::WEIGHT_STEPS )
191                    * ( line.weight() + 1 ) );
192             // (allow multiple matches to look 'darker' than a single one.)
193             painter.drawLine( 1 + LINE_MARGIN,
194                     line.position(), width() - LINE_MARGIN - 1, line.position() );
195         }
196 
197         // The 'view' lines
198         painter.setOpacity( 1 );
199         painter.setPen( palette().color(QPalette::Text) );
200         std::pair<int,int> view_lines = overview_->getViewLines();
201         painter.drawLine( 1, view_lines.first, width(), view_lines.first );
202         painter.drawLine( 1, view_lines.second, width(), view_lines.second );
203 
204         // The highlight
205         if ( highlightedLine_ >= 0 ) {
206             /*
207             QPen highlight_pen( palette().color(QPalette::Text) );
208             highlight_pen.setWidth( 4 - highlightedTTL_ );
209             painter.setOpacity( 1 );
210             painter.setPen( highlight_pen );
211             painter.drawRect( 2, position - 2, width() - 2 - 2, 4 );
212             */
213             int position = overview_->yFromFileLine( highlightedLine_ );
214             painter.drawPixmap(
215                    ( width() - HIGHLIGHT_XPM_WIDTH ) / 2,
216                    position - ( HIGHLIGHT_XPM_HEIGHT / 2 ),
217                    highlight_pixmap[ INITIAL_TTL_VALUE - highlightedTTL_ ] );
218         }
219     }
220 }
221 
222 void OverviewWidget::mousePressEvent( QMouseEvent* mouseEvent )
223 {
224     if ( mouseEvent->button() == Qt::LeftButton )
225         handleMousePress( mouseEvent->y() );
226 }
227 
228 void OverviewWidget::mouseMoveEvent( QMouseEvent* mouseEvent )
229 {
230     if ( mouseEvent->buttons() |= Qt::LeftButton )
231         handleMousePress( mouseEvent->y() );
232 }
233 
234 void OverviewWidget::handleMousePress( int position )
235 {
236     int line = overview_->fileLineFromY( position );
237     LOG(logDEBUG) << "OverviewWidget::handleMousePress y=" << position << " line=" << line;
238     emit lineClicked( line );
239 }
240 
241 void OverviewWidget::highlightLine( qint64 line )
242 {
243     highlightTimer_.stop();
244 
245     highlightedLine_ = line;
246     highlightedTTL_  = INITIAL_TTL_VALUE;
247 
248     update();
249     highlightTimer_.start( STEP_DURATION_MS, this );
250 }
251 
252 void OverviewWidget::removeHighlight()
253 {
254     highlightTimer_.stop();
255 
256     highlightedLine_ = -1;
257     update();
258 }
259 
260 void OverviewWidget::timerEvent( QTimerEvent* event )
261 {
262     if ( event->timerId() == highlightTimer_.timerId() ) {
263         LOG(logDEBUG) << "OverviewWidget::timerEvent";
264         if ( highlightedTTL_ > 0 ) {
265             --highlightedTTL_;
266             update();
267         }
268         else {
269             highlightTimer_.stop();
270         }
271     }
272     else {
273         QObject::timerEvent( event );
274     }
275 }
276