libyui-qt
2.43.5
|
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"