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 <q3pointarray.h>
30 #include "YQMultiProgressMeter.h"
34 YQMultiProgressMeter::YQMultiProgressMeter( YWidget * parent,
36 const vector<float> & maxValues )
37 : QWidget( (QWidget *) parent->widgetRep() )
38 , YMultiProgressMeter( parent, dim, maxValues )
40 _triangularShaped = false;
46 YQMultiProgressMeter::~YQMultiProgressMeter()
52 void YQMultiProgressMeter::init()
55 _segmentMinLength = 12;
58 if ( triangularShaped() )
61 setTriThickness( -1 );
71 void YQMultiProgressMeter::setTriangularShaped( bool triangular )
73 _triangularShaped = triangular;
78 void YQMultiProgressMeter::doUpdate()
84 void YQMultiProgressMeter::paintEvent ( QPaintEvent * event )
89 QPainter painter( this );
91 // if ( ! event->erased() )
92 // painter.eraseRect( event->rect() );
94 int totalLength = horizontal() ? width() : height();
95 int thickness = horizontal() ? height() : width();
97 totalLength -= 2 * margin() + spacing() * ( segments()-1 );
98 thickness -= 2 * margin();
100 if ( triThickness() > 0 )
101 thickness -= 2 * triThickness() + 2 * triSpacing();
103 if ( totalLength < 1 || thickness < 1 || segments() < 1 )
107 // Add up the total sum of all maxValues
109 float totalSum = 0.0;
111 for( int i=0; i < segments(); i++ )
112 totalSum += maxValue( i );
115 // Figure out minimal segment length
117 int minLength = segmentMinLength();
120 // Limit the minimum if there isn't even that much space
122 if ( minLength * segments() > totalLength )
123 minLength = totalLength / ( 2 * segments() );
126 // First attempt of scaling factor from values to pixel coordinates
128 if ( totalSum == 0.0 )
130 y2error( "Avoiding division by zero: totalSum" );
134 float scale = ( (float) totalLength ) / totalSum;
135 float scaledMinLength = ( (float) minLength ) / scale;
138 // Check how many segments would become smaller than the minimum
140 int smallSegmentsCount = 0;
143 for ( int i=0; i < segments(); i++ )
145 if ( maxValue( i ) < scaledMinLength )
146 smallSegmentsCount++;
148 restSum += maxValue( i );
152 // Small segments that get at least minLength pixels consume more screen
153 // space than initially planned, so recompute what is left for the others
155 int distributableLength = totalLength - smallSegmentsCount * minLength;
157 if ( restSum == 0.0 )
159 y2error( "Avoiding division by zero: restSum" );
163 // Recompute scale to take small segments into account that now get screen
164 // space disproportional to their real size (maxValue).
165 scale = ( (float) distributableLength ) / ( restSum );
168 // Calculate indentation
170 int indent = triangularShaped() ? (int) ( thickness * 0.37 ) : 0;
177 painter.rotate( 90 );
178 painter.scale( 1.0, -1.0 );
181 int offset = margin();
183 // Draw each segment in turn
185 for ( int i=0; i < segments(); i++ )
189 if ( maxValue( i ) < scaledMinLength )
192 length = (int) ( maxValue( i ) * scale + 0.5 );
194 drawSegment( i, painter, offset, length, thickness, indent );
197 drawMarkers( painter, offset, thickness );
199 offset += length + spacing();
204 void YQMultiProgressMeter::mouseDoubleClickEvent ( QMouseEvent * event )
206 if ( event && event->button() == Qt::RightButton )
208 // Easter egg: Switch between rectangular and triangular shape
210 y2milestone( "Switching shape" );
211 setTriangularShaped( ! triangularShaped() );
212 setSize( vertical() ? preferredWidth() : width(),
213 horizontal() ? preferredHeight() : height() );
214 YQUI::ui()->evaluateRecalcLayout();
220 void YQMultiProgressMeter::drawSegment( int segment,
230 // Vertical MultiProgressMeters will be filled thermometer-like from bottom
231 // to top, horizontal ones like normal progress bars from left to right,
232 // i.e. just the opposite way.
237 int border = margin();
239 if ( triThickness() > 0 )
240 border += triThickness() + triSpacing();
242 if ( currentValue( segment ) < maxValue( segment ) )
244 if ( maxValue( segment ) == 0.0 )
246 y2error( "Avoiding division by zero: maxValue[%d]", segment );
250 float emptyPart = 1.0 - ( currentValue( segment ) ) / ( maxValue( segment ) );
251 fillStart = (int) ( length * emptyPart );
252 fillHeight = (int) ( indent * emptyPart );
255 thickness--; // We always deal with tickness-1 anyway, so let's cut this short
257 if ( vertical() ) // fill thermometer-like from bottom to top
259 if ( fillStart < length )
261 Q3PointArray points( 4 );
264 points.setPoint( p++, offset + fillStart, border + fillHeight );
265 points.setPoint( p++, offset + fillStart, border + thickness - fillHeight );
266 points.setPoint( p++, offset + length, border + thickness - indent );
267 points.setPoint( p++, offset + length, border + indent );
269 painter.setBrush( palette().highlight() );
270 painter.setPen( Qt::NoPen );
271 painter.drawConvexPolygon( points );
274 else // horizontal - fill from left to right like a normal progress bar
278 Q3PointArray points( 4 );
281 points.setPoint( p++, offset, border + thickness );
282 points.setPoint( p++, offset, border );
283 points.setPoint( p++, offset + fillStart, border + fillHeight );
284 points.setPoint( p++, offset + fillStart, border + thickness - fillHeight );
286 painter.setBrush( palette().highlight() );
287 painter.setPen( Qt::NoPen );
288 painter.drawConvexPolygon( points );
297 const QBrush & dark = palette().dark();
298 const QBrush & light = palette().light();
300 // Draw arrow base (left)
302 painter.setBrush( dark );
303 painter.setPen( Qt::SolidLine );
304 painter.drawLine( offset, border,
305 offset, border + thickness );
308 // Draw upper outline
310 painter.drawLine( offset, border,
311 offset + length - 1, border + indent );
313 // Draw arrow point (right)
315 painter.setBrush( light );
316 painter.drawLine( offset + length - 1, border + indent,
317 offset + length - 1, border + thickness - indent );
319 // Draw lower outline
321 painter.drawLine( offset, border + thickness,
322 offset + length - 1, border + thickness - indent );
327 void YQMultiProgressMeter::drawMarkers( QPainter & painter, int offset, int thickness )
329 if ( triThickness() < 1 )
332 offset -= spacing() / 2 + 1; // integer division rounds down!
334 const QBrush & color = palette().foreground();
335 painter.setBrush( color );
336 // painter.setBrush( NoBrush );
339 // Draw upper marker triangle
341 int tri = triThickness();
342 Q3PointArray points( 3 );
345 points.setPoint( p++, offset - tri+1, margin() ); // top left (base)
346 points.setPoint( p++, offset, margin() + tri-1 ); // lower center (point)
347 points.setPoint( p++, offset + tri-1, margin() ); // top right (base)
349 painter.drawConvexPolygon( points );
352 // Draw lower marker triangle
354 int pointOffset = margin() + tri + thickness + 2 * triSpacing();
357 points.setPoint( p++, offset, pointOffset ); // top center (point)
358 points.setPoint( p++, offset + tri-1, pointOffset + tri-1 ); // top right (base)
359 points.setPoint( p++, offset - tri+1, pointOffset + tri-1 ); // bottom left (base)
361 painter.drawConvexPolygon( points );
365 int YQMultiProgressMeter::thickness()
367 int thickness = triangularShaped() ? 35 : 23;
368 thickness += 2 * margin();
370 if ( triThickness() > 0 )
371 thickness += 2 * triThickness() + 2 * triSpacing();
377 int YQMultiProgressMeter::length()
379 int length = 70 * segments() + 2 * margin();
385 void YQMultiProgressMeter::setTriThickness( int value )
387 _triThickness = value;
389 if ( _triThickness < 1 )
394 void YQMultiProgressMeter::setEnabled( bool enabled )
396 QWidget::setEnabled( enabled );
398 YWidget::setEnabled( enabled );
402 int YQMultiProgressMeter::preferredWidth()
404 return horizontal() ? length() : thickness();
408 int YQMultiProgressMeter::preferredHeight()
410 return horizontal() ? thickness() : length();
414 void YQMultiProgressMeter::setSize( int newWidth, int newHeight )
416 resize( newWidth, newHeight );
421 #include "YQMultiProgressMeter.moc"