1 /*---------------------------------------------------------------------\
3 | __ __ ____ _____ ____ |
4 | \ \ / /_ _/ ___|_ _|___ \ |
5 | \ V / _` \___ \ | | __) | |
6 | | | (_| |___) || | / __/ |
7 | |_|\__,_|____/ |_| |_____| |
11 \----------------------------------------------------------------------/
13 File: YQMultiProgressMeter.cc
15 Author: Stefan Hundhammer <sh@suse.de>
20 #define y2log_component "qt-ui"
21 #include <ycp/y2log.h>
25 #include <QStyleOptionProgressBarV2>
28 #include "YQMultiProgressMeter.h"
32 YQMultiProgressMeter::YQMultiProgressMeter( YWidget * parent,
34 const vector<float> & maxValues )
35 : QWidget( (QWidget *) parent->widgetRep() )
36 , YMultiProgressMeter( parent, dim, maxValues )
38 _triangularShaped = false;
44 YQMultiProgressMeter::~YQMultiProgressMeter()
50 void YQMultiProgressMeter::init()
53 _segmentMinLength = 12;
56 if ( triangularShaped() )
59 setTriThickness( -1 );
69 void YQMultiProgressMeter::setTriangularShaped( bool triangular )
71 _triangularShaped = triangular;
76 void YQMultiProgressMeter::doUpdate()
82 void YQMultiProgressMeter::paintEvent ( QPaintEvent * event )
87 QPainter painter( this );
89 // if ( ! event->erased() )
90 // painter.eraseRect( event->rect() );
92 int totalLength = horizontal() ? width() : height();
93 int thickness = horizontal() ? height() : width();
95 totalLength -= 2 * margin() + spacing() * ( segments()-1 );
96 thickness -= 2 * margin();
98 if ( triThickness() > 0 )
99 thickness -= 2 * triThickness() + 2 * triSpacing();
101 if ( totalLength < 1 || thickness < 1 || segments() < 1 )
105 // Add up the total sum of all maxValues
107 float totalSum = 0.0;
109 for( int i=0; i < segments(); i++ )
110 totalSum += maxValue( i );
113 // Figure out minimal segment length
115 int minLength = segmentMinLength();
118 // Limit the minimum if there isn't even that much space
120 if ( minLength * segments() > totalLength )
121 minLength = totalLength / ( 2 * segments() );
124 // First attempt of scaling factor from values to pixel coordinates
126 if ( totalSum == 0.0 )
128 y2error( "Avoiding division by zero: totalSum" );
132 float scale = ( (float) totalLength ) / totalSum;
133 float scaledMinLength = ( (float) minLength ) / scale;
136 // Check how many segments would become smaller than the minimum
138 int smallSegmentsCount = 0;
141 for ( int i=0; i < segments(); i++ )
143 if ( maxValue( i ) < scaledMinLength )
144 smallSegmentsCount++;
146 restSum += maxValue( i );
150 // Small segments that get at least minLength pixels consume more screen
151 // space than initially planned, so recompute what is left for the others
153 int distributableLength = totalLength - smallSegmentsCount * minLength;
155 if ( restSum == 0.0 )
157 y2error( "Avoiding division by zero: restSum" );
161 // Recompute scale to take small segments into account that now get screen
162 // space disproportional to their real size (maxValue).
163 scale = ( (float) distributableLength ) / ( restSum );
166 // Calculate indentation
168 int indent = triangularShaped() ? (int) ( thickness * 0.37 ) : 0;
174 painter.rotate( 90 );
175 painter.scale( 1.0, -1.0 );
178 int offset = margin();
180 // Draw each segment in turn
182 for ( int i=0; i < segments(); i++ )
186 if ( maxValue( i ) < scaledMinLength )
189 length = (int) ( maxValue( i ) * scale + 0.5 );
191 drawSegment( i, painter, offset, length, thickness, indent );
194 drawMarkers( painter, offset, thickness );
196 offset += length + spacing();
201 void YQMultiProgressMeter::mouseDoubleClickEvent ( QMouseEvent * event )
203 if ( event && event->button() == Qt::RightButton )
205 // Easter egg: Switch between rectangular and triangular shape
207 y2milestone( "Switching shape" );
208 setTriangularShaped( ! triangularShaped() );
209 setSize( vertical() ? preferredWidth() : width(),
210 horizontal() ? preferredHeight() : height() );
211 YQUI::ui()->evaluateRecalcLayout();
217 void YQMultiProgressMeter::drawSegment( int segment,
227 // Vertical MultiProgressMeters will be filled thermometer-like from bottom
228 // to top, horizontal ones like normal progress bars from left to right,
229 // i.e. just the opposite way.
232 int border = margin();
234 if ( triThickness() > 0 )
235 border += triThickness() + triSpacing();
237 if ( maxValue( segment ) == 0.0 )
239 y2error( "Avoiding division by zero: maxValue[%d]", segment );
243 if ( vertical() ) // fill thermometer-like from bottom to top
245 QStyleOptionProgressBarV2 opts;
247 opts.progress = currentValue( segment);
249 opts.maximum = maxValue( segment);
250 opts.invertedAppearance = true;
251 opts.rect = QRect( offset, border, length, thickness );
252 style()->drawControl(QStyle::CE_ProgressBarGroove, &opts, &painter, this);
254 if ( opts.progress > 0 )
255 style()->drawControl(QStyle::CE_ProgressBarContents, &opts, &painter, this);
257 else // horizontal - fill from left to right like a normal progress bar
259 QStyleOptionProgressBarV2 opts;
261 opts.progress = maxValue( segment) - currentValue( segment);
263 opts.maximum = maxValue( segment);
264 opts.rect = QRect( offset, border, length, thickness );
266 style()->drawControl(QStyle::CE_ProgressBarGroove, &opts, &painter, this);
267 if ( opts.progress > 0 )
268 style()->drawControl(QStyle::CE_ProgressBarContents, &opts, &painter, this);
273 void YQMultiProgressMeter::drawMarkers( QPainter & painter, int offset, int thickness )
275 if ( triThickness() < 1 )
278 offset -= spacing() / 2 + 1; // integer division rounds down!
280 const QBrush & color = palette().foreground();
281 painter.setBrush( color );
282 // painter.setBrush( NoBrush );
285 // Draw upper marker triangle
287 int tri = triThickness();
290 { QPointF( offset - tri+1, margin() ), // top left (base)
291 QPointF( offset, margin() + tri-1 ), // lower center (point)
292 QPointF( offset + tri-1, margin() ) // top right (base)
295 painter.drawConvexPolygon( points, 3 );
297 // Draw lower marker triangle
299 int pointOffset = margin() + tri + thickness + 2 * triSpacing();
302 { QPointF( offset, pointOffset ), // top center (point)
303 QPointF( offset + tri-1, pointOffset + tri-1 ), // top right (base)
304 QPointF( offset - tri+1, pointOffset + tri-1 ) // bottom left (base)
307 painter.drawConvexPolygon( points2, 3 );
311 int YQMultiProgressMeter::thickness()
313 int thickness = triangularShaped() ? 35 : 23;
314 thickness += 2 * margin();
316 if ( triThickness() > 0 )
317 thickness += 2 * triThickness() + 2 * triSpacing();
323 int YQMultiProgressMeter::length()
325 int length = 70 * segments() + 2 * margin();
331 void YQMultiProgressMeter::setTriThickness( int value )
333 _triThickness = value;
335 if ( _triThickness < 1 )
340 void YQMultiProgressMeter::setEnabled( bool enabled )
342 QWidget::setEnabled( enabled );
344 YWidget::setEnabled( enabled );
348 int YQMultiProgressMeter::preferredWidth()
350 return horizontal() ? length() : thickness();
354 int YQMultiProgressMeter::preferredHeight()
356 return horizontal() ? thickness() : length();
360 void YQMultiProgressMeter::setSize( int newWidth, int newHeight )
362 resize( newWidth, newHeight );
367 #include "YQMultiProgressMeter.moc"