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