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 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 224 void OverviewWidget::mousePressEvent( QMouseEvent* mouseEvent ) 225 { 226 if ( mouseEvent->button() == Qt::LeftButton ) 227 handleMousePress( mouseEvent->y() ); 228 } 229 230 void OverviewWidget::mouseMoveEvent( QMouseEvent* mouseEvent ) 231 { 232 if ( mouseEvent->buttons() |= Qt::LeftButton ) 233 handleMousePress( mouseEvent->y() ); 234 } 235 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 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 254 void OverviewWidget::removeHighlight() 255 { 256 highlightTimer_.stop(); 257 258 highlightedLine_ = -1; 259 update(); 260 } 261 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