libyui-qt  2.53.0
YQMultiProgressMeter.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YQMultiProgressMeter.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 
26 #define YUILogComponent "qt-ui"
27 #include <yui/YUILog.h>
28 
29 #include <qevent.h>
30 #include <QPointF>
31 #include <QStyleOptionProgressBar>
32 #include <QDebug>
33 #include "YQUI.h"
34 #include "YQMultiProgressMeter.h"
35 #include <yui/YDialog.h>
36 
37 using std::endl;
38 
39 
40 
42  YUIDimension dim,
43  const vector<float> & maxValues )
44  : QWidget( (QWidget *) parent->widgetRep() )
45  , YMultiProgressMeter( parent, dim, maxValues )
46 {
47  init();
48  setWidgetRep( this );
49 }
50 
51 
53 {
54  // NOP
55 }
56 
57 
59 {
60  _margin = 2;
61  _segmentMinLength = 12;
62  _triSpacing = 1;
63  _spacing = 2;
64  setTriThickness( 4 );
65 }
66 
67 
69 {
70  QWidget::update();
71 }
72 
73 
74 void YQMultiProgressMeter::paintEvent ( QPaintEvent * event )
75 {
76  if ( ! event )
77  return;
78 
79  QPainter painter( this );
80 
81 // if ( ! event->erased() )
82 // painter.eraseRect( event->rect() );
83 
84  int totalLength = horizontal() ? width() : height();
85  int thickness = horizontal() ? height() : width();
86 
87  totalLength -= 2 * margin() + spacing() * ( segments()-1 );
88  thickness -= 2 * margin();
89 
90  if ( triThickness() > 0 )
91  thickness -= 2 * triThickness() + 2 * triSpacing();
92 
93  if ( totalLength < 1 || thickness < 1 || segments() < 1 )
94  return;
95 
96 
97  // Add up the total sum of all maxValues
98 
99  float totalSum = 0.0;
100 
101  for( int i=0; i < segments(); i++ )
102  totalSum += maxValue( i );
103 
104 
105  // Figure out minimal segment length
106 
107  int minLength = segmentMinLength();
108 
109 
110  // Limit the minimum if there isn't even that much space
111 
112  if ( minLength * segments() > totalLength )
113  minLength = totalLength / ( 2 * segments() );
114 
115 
116  // First attempt of scaling factor from values to pixel coordinates
117 
118  if ( totalSum == 0.0 )
119  {
120  yuiError() << "Avoiding division by zero: totalSum" << endl;
121  return;
122  }
123 
124  float scale = ( (float) totalLength ) / totalSum;
125  float scaledMinLength = ( (float) minLength ) / scale;
126 
127 
128  // Check how many segments would become smaller than the minimum
129 
130  int smallSegmentsCount = 0;
131  float restSum = 0.0;
132 
133  for ( int i=0; i < segments(); i++ )
134  {
135  if ( maxValue( i ) < scaledMinLength )
136  smallSegmentsCount++;
137  else
138  restSum += maxValue( i );
139  }
140 
141 
142  // Small segments that get at least minLength pixels consume more screen
143  // space than initially planned, so recompute what is left for the others.
144 
145  int distributableLength = totalLength - smallSegmentsCount * minLength;
146 
147  if ( restSum == 0.0 )
148  {
149  yuiError() << "Avoiding division by zero: restSum" << endl;
150  return;
151  }
152 
153  // Recompute scale to take small segments into account that now get screen
154  // space disproportional to their real size (maxValue).
155  scale = ( (float) distributableLength ) / ( restSum );
156 
157  // Set up painter
158 
159  if ( vertical() )
160  {
161  painter.rotate( 90 );
162  painter.scale( 1.0, -1.0 );
163  }
164 
165  int offset = margin();
166 
167  // Draw each segment in turn
168 
169  for ( int i=0; i < segments(); i++ )
170  {
171  int length;
172 
173  if ( maxValue( i ) < scaledMinLength )
174  length = minLength;
175  else
176  length = (int) ( maxValue( i ) * scale + 0.5 );
177 
178  drawSegment( i, painter, offset, length, thickness );
179 
180  if ( i > 0 )
181  drawMarkers( painter, offset, thickness );
182 
183  offset += length + spacing();
184  }
185 }
186 
187 
189  QPainter & painter,
190  int offset,
191  int length,
192  int thickness )
193 {
194  //
195  // Fill segment
196  //
197  // Vertical MultiProgressMeters will be filled thermometer-like from bottom
198  // to top, horizontal ones like normal progress bars from left to right,
199  // i.e. just the opposite way.
200  //
201 
202  int border = margin();
203 
204  if ( triThickness() > 0 )
205  border += triThickness() + triSpacing();
206 
207  if ( maxValue( segment ) == 0.0 )
208  {
209  yuiError() << "Avoiding division by zero: maxValue[" << segment << "]" << endl;
210  return;
211  }
212 
213  // Use 0..1000 range to avoid overflow with huge numbers (Gigabytes).
214  const int scaledMax = 1000;
215  int scaledProgress =
216  (int) ( 0.5 + ( currentValue( segment ) / maxValue( segment ) ) * ( (float) scaledMax ) );
217 
218  if ( vertical() ) // fill thermometer-like from bottom to top
219  {
220  QStyleOptionProgressBar opts;
221  opts.initFrom(this);
222  opts.progress = scaledMax - scaledProgress;
223  opts.minimum = 0;
224  opts.maximum = scaledMax;
225  opts.invertedAppearance = true;
226  opts.rect = QRect( offset, border, length, thickness );
227  style()->drawControl(QStyle::CE_ProgressBarGroove, &opts, &painter, this);
228 
229  if ( opts.progress > 0 )
230  style()->drawControl(QStyle::CE_ProgressBarContents, &opts, &painter, this);
231  }
232  else // horizontal - fill from left to right like a normal progress bar
233  {
234  QStyleOptionProgressBar opts;
235  opts.initFrom(this);
236  opts.progress = scaledProgress;
237  opts.minimum = 0;
238  opts.maximum = scaledMax;
239  opts.rect = QRect( offset, border, length, thickness );
240 
241  style()->drawControl(QStyle::CE_ProgressBarGroove, &opts, &painter, this);
242  if ( opts.progress > 0 )
243  style()->drawControl(QStyle::CE_ProgressBarContents, &opts, &painter, this);
244  }
245 }
246 
247 
248 void YQMultiProgressMeter::drawMarkers( QPainter & painter, int offset, int thickness )
249 {
250  if ( triThickness() < 1 )
251  return;
252 
253  offset -= spacing() / 2 + 1; // integer division rounds down!
254 
255  const QBrush & color = palette().windowText();
256  painter.setBrush( color );
257  // painter.setBrush( NoBrush );
258 
259 
260  // Draw upper marker triangle
261 
262  int tri = triThickness();
263 
264  QPointF points[3] =
265  {
266  QPointF( offset - tri+1, margin() ), // top left (base)
267  QPointF( offset, margin() + tri-1 ), // lower center (point)
268  QPointF( offset + tri-1, margin() ) // top right (base)
269  };
270 
271  painter.drawConvexPolygon( points, 3 );
272 
273  // Draw lower marker triangle
274 
275  int pointOffset = margin() + tri + thickness + 2 * triSpacing();
276 
277  QPointF points2[3] =
278  {
279  QPointF( offset, pointOffset ), // top center (point)
280  QPointF( offset + tri-1, pointOffset + tri-1 ), // top right (base)
281  QPointF( offset - tri+1, pointOffset + tri-1 ) // bottom left (base)
282  };
283 
284  painter.drawConvexPolygon( points2, 3 );
285 }
286 
287 
289 {
290  int thickness = 23;
291  thickness += 2 * margin();
292 
293  if ( triThickness() > 0 )
294  thickness += 2 * triThickness() + 2 * triSpacing();
295 
296  return thickness;
297 }
298 
299 
301 {
302  int length = 70 * segments() + 2 * margin();
303 
304  return length;
305 }
306 
307 
309 {
310  _triThickness = value;
311 
312  if ( _triThickness < 1 )
313  setTriSpacing( 0 );
314 }
315 
316 
318 {
319  QWidget::setEnabled( enabled );
320  QWidget::update();
321  YWidget::setEnabled( enabled );
322 }
323 
324 
326 {
327  return horizontal() ? length() : thickness();
328 }
329 
330 
332 {
333  return horizontal() ? thickness() : length();
334 }
335 
336 
337 void YQMultiProgressMeter::setSize( int newWidth, int newHeight )
338 {
339  resize( newWidth, newHeight );
340  doUpdate();
341 }
YQMultiProgressMeter::length
int length()
Overall length (in pixels) of the MultiProgressMeter.
Definition: YQMultiProgressMeter.cc:300
YQMultiProgressMeter::drawMarkers
void drawMarkers(QPainter &painter, int offset, int thickness)
Draw markers between segments (or beside that spacing).
Definition: YQMultiProgressMeter.cc:248
YQMultiProgressMeter::setTriSpacing
void setTriSpacing(int value)
Sets the spacing between the segment indicators and the small triangles next to the spacing between s...
Definition: YQMultiProgressMeter.h:131
YQMultiProgressMeter::segmentMinLength
int segmentMinLength() const
Returns the minimal length of a segment in pixels.
Definition: YQMultiProgressMeter.h:94
YQMultiProgressMeter::setTriThickness
void setTriThickness(int value)
Set the thickness (base to point) of the small triangles next to the spacing between individual segme...
Definition: YQMultiProgressMeter.cc:308
YQMultiProgressMeter::triThickness
int triThickness() const
Returns the thickness (base to point) of the small triangles next to the spacing between individual s...
Definition: YQMultiProgressMeter.h:107
YQMultiProgressMeter::init
void init()
Common initialization.
Definition: YQMultiProgressMeter.cc:58
YQMultiProgressMeter::setEnabled
virtual void setEnabled(bool enabled)
Set enabled/disabled state.
Definition: YQMultiProgressMeter.cc:317
YQMultiProgressMeter::triSpacing
int triSpacing() const
Returns the spacing between the segment indicators and the small triangles next to the spacing betwee...
Definition: YQMultiProgressMeter.h:125
YQMultiProgressMeter::drawSegment
void drawSegment(int segment, QPainter &painter, int offset, int length, int thickness)
Draw segment number 'segment' with pixel length 'length' from pixel coordinate 'offset' on and fill i...
Definition: YQMultiProgressMeter.cc:188
YQMultiProgressMeter::YQMultiProgressMeter
YQMultiProgressMeter(YWidget *parent, YUIDimension dim, const vector< float > &maxValues)
Constructor.
Definition: YQMultiProgressMeter.cc:41
YQMultiProgressMeter::preferredHeight
virtual int preferredHeight()
Preferred height of the widget.
Definition: YQMultiProgressMeter.cc:331
YQMultiProgressMeter::setSize
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
Definition: YQMultiProgressMeter.cc:337
YQMultiProgressMeter::thickness
int thickness()
Overall thickness (in pixels) of the MultiProgressMeter.
Definition: YQMultiProgressMeter.cc:288
YQMultiProgressMeter::spacing
int spacing() const
Returns the spacing between segments in pixels.
Definition: YQMultiProgressMeter.h:83
YQMultiProgressMeter::preferredWidth
virtual int preferredWidth()
Preferred width of the widget.
Definition: YQMultiProgressMeter.cc:325
YQMultiProgressMeter::doUpdate
virtual void doUpdate()
Perform a visual update on the screen.
Definition: YQMultiProgressMeter.cc:68
YQMultiProgressMeter::~YQMultiProgressMeter
virtual ~YQMultiProgressMeter()
Destructor.
Definition: YQMultiProgressMeter.cc:52
YQMultiProgressMeter::margin
int margin() const
Returns the margin around the widget contents.
Definition: YQMultiProgressMeter.h:72
YQMultiProgressMeter::paintEvent
virtual void paintEvent(QPaintEvent *)
Paint the widget's contents.
Definition: YQMultiProgressMeter.cc:74