]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/YQMultiProgressMeter.cc
unhide some virtual overloads - fixing Huha's only complaint :)
[duncan/yast2-qt4.git] / src / YQMultiProgressMeter.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQMultiProgressMeter.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17 /-*/
18
19
20 #define y2log_component "qt-ui"
21 #include <ycp/y2log.h>
22
23 #include <qevent.h>
24 //Added by qt3to4:
25 #include <q3pointarray.h>
26 #include <qevent.h>
27 #include <qevent.h>
28
29 #include "YQUI.h"
30 #include "YQMultiProgressMeter.h"
31
32
33
34 YQMultiProgressMeter::YQMultiProgressMeter( YWidget *                   parent,
35                                             YUIDimension                dim,
36                                             const vector<float> &       maxValues )
37     : QWidget( (QWidget *) parent->widgetRep() )
38     , YMultiProgressMeter( parent, dim, maxValues )
39 {
40     _triangularShaped = false;
41     init();
42     setWidgetRep( this );
43 }
44
45
46 YQMultiProgressMeter::~YQMultiProgressMeter()
47 {
48     // NOP
49 }
50
51
52 void YQMultiProgressMeter::init()
53 {
54     _margin             = 2;
55     _segmentMinLength   = 12;
56     _triSpacing         = 1;
57
58     if ( triangularShaped() )
59     {
60         _spacing        = 0;
61         setTriThickness( -1 );
62     }
63     else
64     {
65         _spacing        = 2;
66         setTriThickness( 4 );
67     }
68 }
69
70
71 void YQMultiProgressMeter::setTriangularShaped( bool triangular )
72 {
73     _triangularShaped = triangular;
74     init();
75 }
76
77
78 void YQMultiProgressMeter::doUpdate()
79 {
80     QWidget::update();
81 }
82
83
84 void YQMultiProgressMeter::paintEvent ( QPaintEvent * event )
85 {
86     if ( ! event )
87         return;
88
89     QPainter painter( this );
90
91     if ( ! event->erased() )
92         painter.eraseRect( event->rect() );
93
94     int totalLength     = horizontal() ? width() : height();
95     int thickness       = horizontal() ? height() : width();
96
97     totalLength         -= 2 * margin() + spacing() * ( segments()-1 );
98     thickness           -= 2 * margin();
99
100     if ( triThickness() > 0 )
101         thickness -= 2 * triThickness() + 2 * triSpacing();
102
103     if ( totalLength < 1 || thickness < 1 || segments() < 1 )
104         return;
105
106
107     // Add up the total sum of all maxValues
108
109     float totalSum = 0.0;
110
111     for( int i=0; i < segments(); i++ )
112         totalSum += maxValue( i );
113
114
115     // Figure out minimal segment length
116
117     int minLength = segmentMinLength();
118
119
120     // Limit the minimum if there isn't even that much space
121
122     if ( minLength * segments() > totalLength )
123         minLength = totalLength / ( 2 * segments() );
124
125
126     // First attempt of scaling factor from values to pixel coordinates
127
128     if ( totalSum == 0.0 )
129     {
130         y2error( "Avoiding division by zero: totalSum" );
131         return;
132     }
133
134     float scale = ( (float) totalLength ) / totalSum;
135     float scaledMinLength = ( (float) minLength ) / scale;
136
137
138     // Check how many segments would become smaller than the minimum
139
140     int smallSegmentsCount = 0;
141     float restSum = 0.0;
142
143     for ( int i=0; i < segments(); i++ )
144     {
145         if ( maxValue( i ) < scaledMinLength )
146             smallSegmentsCount++;
147         else
148             restSum += maxValue( i );
149     }
150
151
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
154
155     int distributableLength = totalLength - smallSegmentsCount * minLength;
156
157     if ( restSum == 0.0 )
158     {
159         y2error( "Avoiding division by zero: restSum" );
160         return;
161     }
162
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 );
166
167
168     // Calculate indentation
169
170     int indent = triangularShaped() ? (int) ( thickness * 0.37 ) : 0;
171
172
173     // Set up painter
174
175     if ( vertical() )
176     {
177         painter.rotate( 90 );
178         painter.scale( 1.0, -1.0 );
179     }
180
181     int offset = margin();
182
183     // Draw each segment in turn
184
185     for ( int i=0; i < segments(); i++ )
186     {
187         int length;
188
189         if ( maxValue( i ) < scaledMinLength )
190             length = minLength;
191         else
192             length = (int) ( maxValue( i ) * scale + 0.5 );
193
194         drawSegment( i, painter, offset, length, thickness, indent );
195
196         if ( i > 0 )
197             drawMarkers( painter, offset, thickness );
198
199         offset += length + spacing();
200     }
201 }
202
203
204 void YQMultiProgressMeter::mouseDoubleClickEvent ( QMouseEvent * event )
205 {
206     if ( event && event->button() == Qt::RightButton )
207     {
208         // Easter egg: Switch between rectangular and triangular shape
209
210         y2milestone( "Switching shape" );
211         setTriangularShaped( ! triangularShaped() );
212         setSize( vertical()   ? preferredWidth()  : width(),
213                  horizontal() ? preferredHeight() : height() );
214         YQUI::ui()->evaluateRecalcLayout();
215         QWidget::update();
216     }
217 }
218
219
220 void YQMultiProgressMeter::drawSegment( int segment,
221                                         QPainter & painter,
222                                         int offset,
223                                         int length,
224                                         int thickness,
225                                         int indent )
226 {
227     //
228     // Fill segment
229     //
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.
233     //
234
235     int fillStart  = 0;
236     int fillHeight = 0;
237     int border = margin();
238
239     if ( triThickness() > 0 )
240         border += triThickness() + triSpacing();
241
242     if ( currentValue( segment ) < maxValue( segment ) )
243     {
244         if ( maxValue( segment ) == 0.0 )
245         {
246             y2error( "Avoiding division by zero: maxValue[%d]", segment );
247             return;
248         }
249
250         float emptyPart = 1.0 - ( currentValue( segment ) ) / ( maxValue( segment ) );
251         fillStart  = (int) ( length * emptyPart );
252         fillHeight = (int) ( indent * emptyPart );
253     }
254
255     thickness--; // We always deal with tickness-1 anyway, so let's cut this short
256
257     if ( vertical() )   // fill thermometer-like from bottom to top
258     {
259         if ( fillStart < length )
260         {
261             Q3PointArray points( 4 );
262             int p=0;
263     
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 );
268
269             painter.setBrush( palette().active().highlight() );
270             painter.setPen( Qt::NoPen );
271             painter.drawConvexPolygon( points );
272         }
273     }
274     else        // horizontal - fill from left to right like a normal progress bar
275     {
276         if ( fillStart > 0 )
277         {
278             Q3PointArray points( 4 );
279             int p=0;
280     
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 );
285
286             painter.setBrush( palette().active().highlight() );
287             painter.setPen( Qt::NoPen );
288             painter.drawConvexPolygon( points );
289         }
290     }
291
292
293     //
294     // Draw outline
295     //
296
297     const QColor & dark  = palette().active().dark();
298     const QColor & light = palette().active().light();
299
300     // Draw arrow base (left)
301
302     painter.setPen( dark );
303     painter.setPen( Qt::SolidLine );
304     painter.drawLine( offset, border,
305                       offset, border + thickness );
306
307
308     // Draw upper outline
309
310     painter.drawLine( offset, border,
311                       offset + length - 1, border + indent );
312
313     // Draw arrow point (right)
314
315     painter.setPen( light );
316     painter.drawLine( offset + length - 1, border + indent,
317                       offset + length - 1, border + thickness - indent );
318
319     // Draw lower outline
320
321     painter.drawLine( offset, border + thickness,
322                       offset + length - 1, border + thickness - indent );
323
324 }
325
326
327 void YQMultiProgressMeter::drawMarkers( QPainter & painter, int offset, int thickness )
328 {
329     if ( triThickness() < 1 )
330         return;
331
332     offset -= spacing() / 2 + 1;        // integer division rounds down!
333
334     const QColor & color = palette().active().foreground();
335     painter.setPen( color );
336     painter.setPen( Qt::SolidLine );
337     painter.setBrush( color );
338     // painter.setBrush( NoBrush );
339     
340
341     // Draw upper marker triangle
342
343     int tri = triThickness();
344     Q3PointArray points( 3 );
345
346     int p=0;
347     points.setPoint( p++, offset - tri+1,       margin() );             // top left (base)
348     points.setPoint( p++, offset,               margin() + tri-1 );     // lower center (point)
349     points.setPoint( p++, offset + tri-1,       margin() );             // top right (base)
350
351     painter.drawConvexPolygon( points );
352
353
354     // Draw lower marker triangle
355
356     int pointOffset = margin() + tri + thickness + 2 * triSpacing();
357
358     p=0;
359     points.setPoint( p++, offset,               pointOffset );          // top center (point)
360     points.setPoint( p++, offset + tri-1,       pointOffset + tri-1 );  // top right (base)
361     points.setPoint( p++, offset - tri+1,       pointOffset + tri-1 );  // bottom left (base)
362
363     painter.drawConvexPolygon( points );
364 }
365
366
367 int YQMultiProgressMeter::thickness()
368 {
369     int thickness = triangularShaped() ? 35 : 23;
370     thickness += 2 * margin();
371
372     if ( triThickness() > 0 )
373         thickness += 2 * triThickness() + 2 * triSpacing();
374
375     return thickness;
376 }
377
378
379 int YQMultiProgressMeter::length()
380 {
381     int length = 70 * segments() + 2 * margin();
382
383     return length;
384 }
385
386
387 void YQMultiProgressMeter::setTriThickness( int value )
388 {
389     _triThickness = value;
390
391     if ( _triThickness < 1 )
392         setTriSpacing( 0 );
393 }
394
395
396 void YQMultiProgressMeter::setEnabled( bool enabled )
397 {
398     QWidget::setEnabled( enabled );
399     QWidget::update();
400     YWidget::setEnabled( enabled );
401 }
402
403
404 int YQMultiProgressMeter::preferredWidth()
405 {
406     return horizontal() ? length() : thickness();
407 }
408
409
410 int YQMultiProgressMeter::preferredHeight()
411 {
412     return horizontal() ? thickness() : length();
413 }
414
415
416 void YQMultiProgressMeter::setSize( int newWidth, int newHeight )
417 {
418     resize( newWidth, newHeight );
419     doUpdate();
420 }
421
422
423 #include "YQMultiProgressMeter.moc"