libyui-qt  2.43.5
/usr/src/RPM/BUILD/libyui-qt-2.43.5/src/YQMultiProgressMeter.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:       YQMultiProgressMeter.cc
00020 
00021   Author:     Stefan Hundhammer <sh@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #define YUILogComponent "qt-ui"
00027 #include <yui/YUILog.h>
00028 
00029 #include <qevent.h>
00030 #include <QPointF>
00031 #include <QStyleOptionProgressBarV2>
00032 #include <QDebug>
00033 #include "YQUI.h"
00034 #include "YQMultiProgressMeter.h"
00035 #include <yui/YDialog.h>
00036 
00037 
00038 
00039 YQMultiProgressMeter::YQMultiProgressMeter( YWidget *                   parent,
00040                                             YUIDimension                dim,
00041                                             const vector<float> &       maxValues )
00042     : QWidget( (QWidget *) parent->widgetRep() )
00043     , YMultiProgressMeter( parent, dim, maxValues )
00044 {
00045     init();
00046     setWidgetRep( this );
00047 }
00048 
00049 
00050 YQMultiProgressMeter::~YQMultiProgressMeter()
00051 {
00052     // NOP
00053 }
00054 
00055 
00056 void YQMultiProgressMeter::init()
00057 {
00058     _margin             = 2;
00059     _segmentMinLength   = 12;
00060     _triSpacing         = 1;
00061     _spacing    = 2;
00062     setTriThickness( 4 );
00063 }
00064 
00065 
00066 void YQMultiProgressMeter::doUpdate()
00067 {
00068     QWidget::update();
00069 }
00070 
00071 
00072 void YQMultiProgressMeter::paintEvent ( QPaintEvent * event )
00073 {
00074     if ( ! event )
00075         return;
00076 
00077     QPainter painter( this );
00078 
00079 //     if ( ! event->erased() )
00080 //         painter.eraseRect( event->rect() );
00081 
00082     int totalLength     = horizontal() ? width() : height();
00083     int thickness       = horizontal() ? height() : width();
00084 
00085     totalLength         -= 2 * margin() + spacing() * ( segments()-1 );
00086     thickness           -= 2 * margin();
00087 
00088     if ( triThickness() > 0 )
00089         thickness -= 2 * triThickness() + 2 * triSpacing();
00090 
00091     if ( totalLength < 1 || thickness < 1 || segments() < 1 )
00092         return;
00093 
00094 
00095     // Add up the total sum of all maxValues
00096 
00097     float totalSum = 0.0;
00098 
00099     for( int i=0; i < segments(); i++ )
00100         totalSum += maxValue( i );
00101 
00102 
00103     // Figure out minimal segment length
00104 
00105     int minLength = segmentMinLength();
00106 
00107 
00108     // Limit the minimum if there isn't even that much space
00109 
00110     if ( minLength * segments() > totalLength )
00111         minLength = totalLength / ( 2 * segments() );
00112 
00113 
00114     // First attempt of scaling factor from values to pixel coordinates
00115 
00116     if ( totalSum == 0.0 )
00117     {
00118         yuiError() << "Avoiding division by zero: totalSum" << std::endl;
00119         return;
00120     }
00121 
00122     float scale = ( (float) totalLength ) / totalSum;
00123     float scaledMinLength = ( (float) minLength ) / scale;
00124 
00125 
00126     // Check how many segments would become smaller than the minimum
00127 
00128     int smallSegmentsCount = 0;
00129     float restSum = 0.0;
00130 
00131     for ( int i=0; i < segments(); i++ )
00132     {
00133         if ( maxValue( i ) < scaledMinLength )
00134             smallSegmentsCount++;
00135         else
00136             restSum += maxValue( i );
00137     }
00138 
00139 
00140     // Small segments that get at least minLength pixels consume more screen
00141     // space than initially planned, so recompute what is left for the others.
00142 
00143     int distributableLength = totalLength - smallSegmentsCount * minLength;
00144 
00145     if ( restSum == 0.0 )
00146     {
00147         yuiError() << "Avoiding division by zero: restSum" << std::endl;
00148         return;
00149     }
00150 
00151     // Recompute scale to take small segments into account that now get screen
00152     // space disproportional to their real size (maxValue).
00153     scale = ( (float) distributableLength ) / ( restSum );
00154 
00155     // Set up painter
00156 
00157     if ( vertical() )
00158     {
00159         painter.rotate( 90 );
00160         painter.scale( 1.0, -1.0 );
00161     }
00162 
00163     int offset = margin();
00164 
00165     // Draw each segment in turn
00166 
00167     for ( int i=0; i < segments(); i++ )
00168     {
00169         int length;
00170 
00171         if ( maxValue( i ) < scaledMinLength )
00172             length = minLength;
00173         else
00174             length = (int) ( maxValue( i ) * scale + 0.5 );
00175 
00176         drawSegment( i, painter, offset, length, thickness );
00177 
00178         if ( i > 0 )
00179             drawMarkers( painter, offset, thickness );
00180 
00181         offset += length + spacing();
00182     }
00183 }
00184 
00185 
00186 void YQMultiProgressMeter::drawSegment( int segment,
00187                                         QPainter & painter,
00188                                         int offset,
00189                                         int length,
00190                                         int thickness )
00191 {
00192     //
00193     // Fill segment
00194     //
00195     // Vertical MultiProgressMeters will be filled thermometer-like from bottom
00196     // to top, horizontal ones like normal progress bars from left to right,
00197     // i.e. just the opposite way.
00198     //
00199 
00200     int border = margin();
00201 
00202     if ( triThickness() > 0 )
00203         border += triThickness() + triSpacing();
00204 
00205     if ( maxValue( segment ) == 0.0 )
00206     {
00207         yuiError() << "Avoiding division by zero: maxValue[" << segment << "]" << std::endl;
00208         return;
00209     }
00210 
00211     // Use 0..1000 range to avoid overflow with huge numbers (Gigabytes).
00212     const int scaledMax = 1000;
00213     int scaledProgress =
00214         (int) ( 0.5 + ( currentValue( segment ) / maxValue( segment ) ) * ( (float) scaledMax ) );
00215 
00216     if ( vertical() )   // fill thermometer-like from bottom to top
00217     {
00218         QStyleOptionProgressBarV2 opts;
00219         opts.initFrom(this);
00220         opts.progress = scaledMax - scaledProgress;
00221         opts.minimum = 0;
00222         opts.maximum = scaledMax;
00223         opts.invertedAppearance = true;
00224         opts.rect = QRect( offset, border, length, thickness );
00225         style()->drawControl(QStyle::CE_ProgressBarGroove, &opts, &painter, this);
00226 
00227         if ( opts.progress > 0 )
00228             style()->drawControl(QStyle::CE_ProgressBarContents, &opts, &painter, this);
00229     }
00230     else        // horizontal - fill from left to right like a normal progress bar
00231     {
00232         QStyleOptionProgressBarV2 opts;
00233         opts.initFrom(this);
00234         opts.progress = scaledProgress;
00235         opts.minimum = 0;
00236         opts.maximum = scaledMax;
00237         opts.rect = QRect( offset, border, length, thickness );
00238 
00239         style()->drawControl(QStyle::CE_ProgressBarGroove, &opts, &painter, this);
00240         if ( opts.progress > 0 )
00241             style()->drawControl(QStyle::CE_ProgressBarContents, &opts, &painter, this);
00242     }
00243 }
00244 
00245 
00246 void YQMultiProgressMeter::drawMarkers( QPainter & painter, int offset, int thickness )
00247 {
00248     if ( triThickness() < 1 )
00249         return;
00250 
00251     offset -= spacing() / 2 + 1;        // integer division rounds down!
00252 
00253     const QBrush & color = palette().foreground();
00254     painter.setBrush( color );
00255     // painter.setBrush( NoBrush );
00256 
00257 
00258     // Draw upper marker triangle
00259 
00260     int tri = triThickness();
00261 
00262     QPointF points[3] =
00263         {
00264             QPointF( offset - tri+1,    margin() ),             // top left (base)
00265             QPointF( offset,            margin() + tri-1 ),     // lower center (point)
00266             QPointF( offset + tri-1,    margin() )              // top right (base)
00267         };
00268 
00269     painter.drawConvexPolygon( points, 3 );
00270 
00271     // Draw lower marker triangle
00272 
00273     int pointOffset = margin() + tri + thickness + 2 * triSpacing();
00274 
00275     QPointF points2[3] =
00276         {
00277             QPointF( offset,            pointOffset ),          // top center (point)
00278             QPointF( offset + tri-1,    pointOffset + tri-1 ),  // top right (base)
00279             QPointF( offset - tri+1,    pointOffset + tri-1 )   // bottom left (base)
00280         };
00281 
00282     painter.drawConvexPolygon( points2, 3 );
00283 }
00284 
00285 
00286 int YQMultiProgressMeter::thickness()
00287 {
00288     int thickness = 23;
00289     thickness += 2 * margin();
00290 
00291     if ( triThickness() > 0 )
00292         thickness += 2 * triThickness() + 2 * triSpacing();
00293 
00294     return thickness;
00295 }
00296 
00297 
00298 int YQMultiProgressMeter::length()
00299 {
00300     int length = 70 * segments() + 2 * margin();
00301 
00302     return length;
00303 }
00304 
00305 
00306 void YQMultiProgressMeter::setTriThickness( int value )
00307 {
00308     _triThickness = value;
00309 
00310     if ( _triThickness < 1 )
00311         setTriSpacing( 0 );
00312 }
00313 
00314 
00315 void YQMultiProgressMeter::setEnabled( bool enabled )
00316 {
00317     QWidget::setEnabled( enabled );
00318     QWidget::update();
00319     YWidget::setEnabled( enabled );
00320 }
00321 
00322 
00323 int YQMultiProgressMeter::preferredWidth()
00324 {
00325     return horizontal() ? length() : thickness();
00326 }
00327 
00328 
00329 int YQMultiProgressMeter::preferredHeight()
00330 {
00331     return horizontal() ? thickness() : length();
00332 }
00333 
00334 
00335 void YQMultiProgressMeter::setSize( int newWidth, int newHeight )
00336 {
00337     resize( newWidth, newHeight );
00338     doUpdate();
00339 }
00340 
00341 
00342 #include "YQMultiProgressMeter.moc"
 All Classes Functions Variables