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