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>
24 #include <Qt3Support/Q3PointArray>
27 #include "YQMultiProgressMeter.h"
31 YQMultiProgressMeter::YQMultiProgressMeter( YWidget * parent,
33 const vector<float> & maxValues )
34 : QWidget( (QWidget *) parent->widgetRep() )
35 , YMultiProgressMeter( parent, dim, maxValues )
37 _triangularShaped = false;
43 YQMultiProgressMeter::~YQMultiProgressMeter()
49 void YQMultiProgressMeter::init()
52 _segmentMinLength = 12;
55 if ( triangularShaped() )
58 setTriThickness( -1 );
68 void YQMultiProgressMeter::setTriangularShaped( bool triangular )
70 _triangularShaped = triangular;
75 void YQMultiProgressMeter::doUpdate()
81 void YQMultiProgressMeter::paintEvent ( QPaintEvent * event )
86 QPainter painter( this );
88 // if ( ! event->erased() )
89 // painter.eraseRect( event->rect() );
91 int totalLength = horizontal() ? width() : height();
92 int thickness = horizontal() ? height() : width();
94 totalLength -= 2 * margin() + spacing() * ( segments()-1 );
95 thickness -= 2 * margin();
97 if ( triThickness() > 0 )
98 thickness -= 2 * triThickness() + 2 * triSpacing();
100 if ( totalLength < 1 || thickness < 1 || segments() < 1 )
104 // Add up the total sum of all maxValues
106 float totalSum = 0.0;
108 for( int i=0; i < segments(); i++ )
109 totalSum += maxValue( i );
112 // Figure out minimal segment length
114 int minLength = segmentMinLength();
117 // Limit the minimum if there isn't even that much space
119 if ( minLength * segments() > totalLength )
120 minLength = totalLength / ( 2 * segments() );
123 // First attempt of scaling factor from values to pixel coordinates
125 if ( totalSum == 0.0 )
127 y2error( "Avoiding division by zero: totalSum" );
131 float scale = ( (float) totalLength ) / totalSum;
132 float scaledMinLength = ( (float) minLength ) / scale;
135 // Check how many segments would become smaller than the minimum
137 int smallSegmentsCount = 0;
140 for ( int i=0; i < segments(); i++ )
142 if ( maxValue( i ) < scaledMinLength )
143 smallSegmentsCount++;
145 restSum += maxValue( i );
149 // Small segments that get at least minLength pixels consume more screen
150 // space than initially planned, so recompute what is left for the others
152 int distributableLength = totalLength - smallSegmentsCount * minLength;
154 if ( restSum == 0.0 )
156 y2error( "Avoiding division by zero: restSum" );
160 // Recompute scale to take small segments into account that now get screen
161 // space disproportional to their real size (maxValue).
162 scale = ( (float) distributableLength ) / ( restSum );
165 // Calculate indentation
167 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.
234 int border = margin();
236 if ( triThickness() > 0 )
237 border += triThickness() + triSpacing();
239 if ( currentValue( segment ) < maxValue( segment ) )
241 if ( maxValue( segment ) == 0.0 )
243 y2error( "Avoiding division by zero: maxValue[%d]", segment );
247 float emptyPart = 1.0 - ( currentValue( segment ) ) / ( maxValue( segment ) );
248 fillStart = (int) ( length * emptyPart );
249 fillHeight = (int) ( indent * emptyPart );
252 thickness--; // We always deal with tickness-1 anyway, so let's cut this short
254 if ( vertical() ) // fill thermometer-like from bottom to top
256 if ( fillStart < length )
258 Q3PointArray points( 4 );
261 points.setPoint( p++, offset + fillStart, border + fillHeight );
262 points.setPoint( p++, offset + fillStart, border + thickness - fillHeight );
263 points.setPoint( p++, offset + length, border + thickness - indent );
264 points.setPoint( p++, offset + length, border + indent );
266 painter.setBrush( palette().highlight() );
267 painter.setPen( Qt::NoPen );
268 painter.drawConvexPolygon( points );
271 else // horizontal - fill from left to right like a normal progress bar
275 Q3PointArray points( 4 );
278 points.setPoint( p++, offset, border + thickness );
279 points.setPoint( p++, offset, border );
280 points.setPoint( p++, offset + fillStart, border + fillHeight );
281 points.setPoint( p++, offset + fillStart, border + thickness - fillHeight );
283 painter.setBrush( palette().highlight() );
284 painter.setPen( Qt::NoPen );
285 painter.drawConvexPolygon( points );
294 const QBrush & dark = palette().dark();
295 const QBrush & light = palette().light();
297 // Draw arrow base (left)
299 painter.setBrush( dark );
300 painter.setPen( Qt::SolidLine );
301 painter.drawLine( offset, border,
302 offset, border + thickness );
305 // Draw upper outline
307 painter.drawLine( offset, border,
308 offset + length - 1, border + indent );
310 // Draw arrow point (right)
312 painter.setBrush( light );
313 painter.drawLine( offset + length - 1, border + indent,
314 offset + length - 1, border + thickness - indent );
316 // Draw lower outline
318 painter.drawLine( offset, border + thickness,
319 offset + length - 1, border + thickness - indent );
324 void YQMultiProgressMeter::drawMarkers( QPainter & painter, int offset, int thickness )
326 if ( triThickness() < 1 )
329 offset -= spacing() / 2 + 1; // integer division rounds down!
331 const QBrush & color = palette().foreground();
332 painter.setBrush( color );
333 // painter.setBrush( NoBrush );
336 // Draw upper marker triangle
338 int tri = triThickness();
339 Q3PointArray points( 3 );
342 points.setPoint( p++, offset - tri+1, margin() ); // top left (base)
343 points.setPoint( p++, offset, margin() + tri-1 ); // lower center (point)
344 points.setPoint( p++, offset + tri-1, margin() ); // top right (base)
346 painter.drawConvexPolygon( points );
349 // Draw lower marker triangle
351 int pointOffset = margin() + tri + thickness + 2 * triSpacing();
354 points.setPoint( p++, offset, pointOffset ); // top center (point)
355 points.setPoint( p++, offset + tri-1, pointOffset + tri-1 ); // top right (base)
356 points.setPoint( p++, offset - tri+1, pointOffset + tri-1 ); // bottom left (base)
358 painter.drawConvexPolygon( points );
362 int YQMultiProgressMeter::thickness()
364 int thickness = triangularShaped() ? 35 : 23;
365 thickness += 2 * margin();
367 if ( triThickness() > 0 )
368 thickness += 2 * triThickness() + 2 * triSpacing();
374 int YQMultiProgressMeter::length()
376 int length = 70 * segments() + 2 * margin();
382 void YQMultiProgressMeter::setTriThickness( int value )
384 _triThickness = value;
386 if ( _triThickness < 1 )
391 void YQMultiProgressMeter::setEnabled( bool enabled )
393 QWidget::setEnabled( enabled );
395 YWidget::setEnabled( enabled );
399 int YQMultiProgressMeter::preferredWidth()
401 return horizontal() ? length() : thickness();
405 int YQMultiProgressMeter::preferredHeight()
407 return horizontal() ? thickness() : length();
411 void YQMultiProgressMeter::setSize( int newWidth, int newHeight )
413 resize( newWidth, newHeight );
418 #include "YQMultiProgressMeter.moc"