File: qprogres.cpp

package info (click to toggle)
explorer 0.72-2.1
  • links: PTS
  • area: contrib
  • in suites: hamm, slink
  • size: 1,556 kB
  • ctags: 1,203
  • sloc: cpp: 10,226; makefile: 384; sh: 206; ansic: 106; lex: 95; csh: 6
file content (513 lines) | stat: -rw-r--r-- 12,881 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
/////////////////// QProgressCtrl widget class //////////////////////
//
// for making Win95-style progress bars, as well as options for
// blocked/solid bar style, vertical/horizontal alignment, 
// bar/background colors
//
// Copyright (C) 1996 Tim D. Gilman
// This version of the class is the first release.  Please
// send comments/suggestions/bug reports to <tdgilman@best.com>
//
// This class was written using Qt 1.0 (http://www.troll.no)
//
// You may freely use this source code without permission for 
// non-commercial development.


#include <qwidget.h>
#include <qframe.h>
#include <qpainter.h>
#include <qcolor.h>

#include "qprogres.h"

#define BRD 2   // pixel width between frame and progress bar and between blocks

#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a)   ((a)>0?(a):(-1*a))


/////////////// Construction //////////////

QProgressCtrl::QProgressCtrl(QWidget *parent, 
			     ProgressStyle style,
			     const QColor &barColor,
			     const QColor &backColor,
			     ProgressOrient orient, 
			     const char *name)
             :QFrame(parent,name)
{
   // default behavior
   m_nLower = 0;  m_nUpper = 100;
   m_nPos = 0;
   m_nStep = 10;
   m_nSolidLen = 0;  // current width of the bar
   m_nNumBlocks = 0; // current number of bar blocks (for blockedBar style)
   m_barColor = new QColor(barColor);
   m_orient = orient;
   m_style = style;
   
   setBackgroundColor(backColor);
   
   init();
}

void QProgressCtrl::init()
{
   initMetaObject();
   int fs;
   switch( style() ) {
    case WindowsStyle:
    case MotifStyle:
      fs = QFrame::Panel | QFrame::Sunken;
      break;
    /*
     * I have noticed that any style other than Windows or Motif
     * breaks the behavior of QProgressCtrl.  I think it is from
     * lack of support from Qt.  Do not try it yet.
     */
    default:  
      fs = QFrame::Panel | QFrame::Plain;
   }
   setLineWidth(2);
   setMidLineWidth(3);
   setFrameStyle( fs );
   
   if (m_style == blockedBar) {
      m_nBlockWidth = calcBlockLen();
   }
   
}


///////////////  Attributes ////////////////

/*
 * Parameters
 *  nLower	Specifies the lower limit of the range (default is zero)
 *  nUpper	Specifies the upper limit of the range (default is 100)
 *
 * Description
 *  Sets the min and max ranges for a progress bar control and
 *  redraws the bar to reflect the new changes.
 */
void QProgressCtrl::setRange(int nLower, int nUpper)
{
   int nOldSolidLen = m_nSolidLen;
   int nOldNumBlocks = m_nNumBlocks;

   m_nLower = nLower;
   m_nUpper = nUpper;

   switch (m_style) {
    case solidBar:
      m_nSolidLen = calcSolidBarLen(m_nPos);
      paintSolidBar(nOldSolidLen, m_nSolidLen);
      break;
    case blockedBar:
      m_nNumBlocks = calcNumBlocks(m_nPos);
      paintBlockedBars(nOldNumBlocks, m_nNumBlocks);
      break;
   }
}

/*
 * Returns
 *  The previous position in the progress bar control.
 *
 * Parameters
 *  nPos		New position of the progress bar control.
 *
 * Description
 *  Sets the current position for a progress bar control and redraws
 *  the bar to reflect the new position.
 */
int QProgressCtrl::setPos(int nPos)
{
   int nOldPos = m_nPos;
   int nOldSolidLen = m_nSolidLen;
   int nOldNumBlocks = m_nNumBlocks;
   
   m_nPos = nPos;

   switch (m_style) {
    case solidBar:
      m_nSolidLen = calcSolidBarLen(m_nPos);
      paintSolidBar(nOldSolidLen, m_nSolidLen);
      break;
    case blockedBar:
      m_nNumBlocks = calcNumBlocks(m_nPos);
      paintBlockedBars(nOldNumBlocks, m_nNumBlocks);
      break;
   }
      
   return nOldPos;
}

/*
 * Returns
 *  The previous position in the progress bar control.
 *
 * Parameters
 *  nPos		Amount to advance the position.
 *
 * Description
 *  Advances the current position of a progress bar control by a specified
 *  increment and redraws the bar to reflect the new position.
 */ 
int QProgressCtrl::offsetPos(int nPos)
{
   int nOldPos = m_nPos;
   int nOldSolidLen = m_nSolidLen;
   int nOldNumBlocks = m_nNumBlocks;
   
   m_nPos += nPos;
   
   switch (m_style) {
    case solidBar:
      m_nSolidLen = calcSolidBarLen(m_nPos);
      paintSolidBar(nOldSolidLen, m_nSolidLen);
      break;
    case blockedBar:
      m_nNumBlocks = calcNumBlocks(m_nPos);
      paintBlockedBars(nOldNumBlocks, m_nNumBlocks);
      break;
   }
   
   return nOldPos;
}

/*
 * Returns
 * The previous step increment.
 *
 * Parameters
 *  nStep		New step increment.
 *
 * Description
 *  Specifies the step increment for a progress bar control.  The step
 *  increment is used by stepIt() to increase the progress bar's position.
 *
 *  The default step increment is 10.
 */
int QProgressCtrl::setStep(int nStep)
{
   int oldStep = m_nStep;
   m_nStep = nStep;
   return oldStep;
}


///////////////// Operations //////////////////

/*
 * Returns
 *  The previous position of the progress bar control.
 *
 * Description
 *  Advances the current position for a progress bar control by the
 *  step increment (see setStep()) and redraws the bar to reflect
 *  the new position.
 */
int QProgressCtrl::stepIt()
{
   int nOldPos = m_nPos;
   int nOldSolidLen = m_nSolidLen;
   int nOldNumBlocks = m_nNumBlocks;
   
   m_nPos += m_nStep;
   
   switch (m_style) {
    case solidBar:
      m_nSolidLen = calcSolidBarLen(m_nPos);
      paintSolidBar(nOldSolidLen, m_nSolidLen);
      break;
    case blockedBar:
      m_nNumBlocks = calcNumBlocks(m_nPos);
      paintBlockedBars(nOldNumBlocks, m_nNumBlocks);
      break;
   }

   return nOldPos;
}

//////////////// Private Stuff //////////////

/*
 * calculates the solid bar length based on the position nPos
 */
int QProgressCtrl::calcSolidBarLen(int nPos)
{
   int len=0;
   
   // what total length are we dealing with here?
   switch (m_orient) {
    case horizBar:
      len = width()-2*frameWidth();
      break;
    case vertBar:
      len = height()-2*frameWidth();
      break;
   }

   // calculate the pixel length by scaling the position to the 
   // range along length
   if (nPos <= m_nLower)
     return 0;
   else if (nPos >= m_nUpper)
     return (len);
   else
     return ( (int)((float)(m_nPos-m_nLower)/(float)(m_nUpper-m_nLower)
		       *(float)len) );

}

/*
 * calculate the number of blocks that should be drawn based on
 * the position nPos.  That is, the number of blocks that first
 * exceeds or equals the exact length.
 */
int QProgressCtrl::calcNumBlocks(int nPos)
{
   int totLen=0, pLen, nBlocks, nSep, sumLen;
   int edge = frameWidth()+BRD;
   
   switch (m_orient) {
    case horizBar:
      totLen = width()-2*edge;
      break;
    case vertBar:
      totLen = height()-2*edge;
      break;
   }
   
   // calculate the pixel length that is a percentage of len based on nPos
   if (nPos <= m_nLower)
     pLen = 0;
   else if (nPos >= m_nUpper)
     pLen = totLen;
   else
     pLen = ( (int)((float)(m_nPos-m_nLower)/(float)(m_nUpper-m_nLower)
		    *(float)totLen) );
   
   // find out how many blocks it takes to exceed or equal this pixel length pLen

   if (pLen == 0)
     return 0;
   
   nBlocks = 0;  
   do {
      nBlocks++;
      nSep = nBlocks-1;
      sumLen = nBlocks*m_nBlockWidth + nSep*BRD;
   } while (sumLen < pLen);
      
   return nBlocks;
}


/*
 * calculates the individual block length based on the total available
 * width of the frame.
 * 
 * To emulate the Win95 common progress control there will be a
 * border to separate the frame from the blocks and also a border
 * between each of the blocks themselves (BRD).
 */
int QProgressCtrl::calcBlockLen()
{
   const float aspect = 2.f/3.f;  // approximate aspect ratio for blocks
   int blockHeight=1, blockWidth=1;
   int edge = frameWidth()+BRD;
   
   switch (m_orient) {
    case horizBar:
      blockHeight = height()-2*edge;
      break;
    case vertBar:
      blockHeight = width()-2*edge;
      break;
   }
   
   blockWidth = (int)(aspect*(float)blockHeight);
   
   // never use zero length
   if (blockWidth < 1)
     blockWidth = 1;

   return ((int)(aspect*(float)blockHeight));
}

/*
 * updates the solid bar when the length has changed
 * this only repaints the portion needed and only erases
 * that part of the background if it moves backward
 */
void QProgressCtrl::paintSolidBar(int nOldLen, int nLen)
{
   switch (m_orient) {
    case horizBar:
      if (nLen > nOldLen) {        // do not erase, repaint needed area
	 repaint(frameWidth()+nOldLen, frameWidth(),
		 nLen-nOldLen, height()-2*frameWidth(), FALSE);
      }
      else if (nLen < nOldLen) {   // erase and repaint needed area
	 repaint(frameWidth()+nLen, frameWidth(),
		 nOldLen-nLen, height()-2*frameWidth(), TRUE);
      }
      // else do not repaint rectangle, it did not change
      break;
    case vertBar:
      if (nLen > nOldLen) {
	 repaint(frameWidth(), height()-(frameWidth()+nLen),
		 width()-2*frameWidth(), nLen-nOldLen, FALSE);
      }
      else if (nLen < nOldLen) {
	 repaint(frameWidth(), height()-(frameWidth()+nOldLen),
		 width()-2*frameWidth(), nOldLen-nLen, TRUE);
      }
      break;
   }
}

void QProgressCtrl::paintBlockedBars(int nOldNumBlocks, int nNumBlocks)
{
   int x=0, y=0, w=0, h=0;
   int edge = frameWidth()+BRD;
   
   // only repaint if the number of blocks changes and calculate the specific rectangle to erase
   // to avoid flickering.
   if (nOldNumBlocks != nNumBlocks) {
      switch (m_orient) {
       case horizBar:
	 x = edge+min(nOldNumBlocks,nNumBlocks)*(m_nBlockWidth+BRD);
	 y = edge;
	 w = abs(nNumBlocks-nOldNumBlocks)*m_nBlockWidth + abs(nNumBlocks-nOldNumBlocks-1)*BRD;
	 h = height()-2*edge;
	 if (w > 0) {
	    if ( (x+w) > (width()-frameWidth()-BRD) )
	      w = (width()-frameWidth()-BRD) - x;
	 }
	 break;
       case vertBar:
	 x = edge;
	 // y is top of the largest block number
	 y = height()                                    // bottom of the vertical bar
	   -edge                                         // subtract edge width
	   -max(nNumBlocks,nOldNumBlocks)*m_nBlockWidth  // subtract sum of blocks width
	   -(max(nNumBlocks,nOldNumBlocks)-1)*BRD;       // subtract sum of separators width
	 w = width()-2*edge;
	 h = abs(nNumBlocks-nOldNumBlocks)*m_nBlockWidth + abs(nNumBlocks-nOldNumBlocks-1)*BRD;
	 if (h > 0) {
	    if ( y < edge )
	      y = edge;
	 }
      }
   
      // if adding blocks, repaint invalid rectangle, but do not erase
      if (nNumBlocks > nOldNumBlocks)
	repaint(x, y, w, h, FALSE);
      // if removing blocks, erase invalid rectangle and repaint
      else if (nNumBlocks < nOldNumBlocks)
	repaint(x, y, w, h, TRUE);
   }

}
       

void QProgressCtrl::paintEvent( QPaintEvent * )
{
   QPainter p;
   int x, y, w, h, edge;
   
   p.begin(this);

   p.setBrush(*m_barColor);
   p.setPen(*m_barColor);
     
   switch (m_style) {
    case solidBar:
      if (m_nSolidLen > 0) {  // no point to drawing a zero-length rectangle
	 switch(m_orient) {
	  case horizBar:
	    p.drawRect(frameWidth(),frameWidth(),
		       m_nSolidLen,height()-2*frameWidth());
	    break;
	  case vertBar:
	    p.drawRect(frameWidth(),height()-(frameWidth()+m_nSolidLen),
		       width()-2*frameWidth(),m_nSolidLen);
	    break;
	 }
      }
      break;
    case blockedBar:
      edge = frameWidth()+BRD;
      switch(m_orient) {
       case horizBar:
	 for (int i=0; i<m_nNumBlocks; i++) {
	    x = edge+i*(m_nBlockWidth+BRD);
	    y = edge;
	    w = m_nBlockWidth;
	    h = height()-2*edge;

	    if (x < (width()-edge)) {
	       if ( (x+w) > (width()-edge) )
		 w = (width()-edge) - x;
	       p.drawRect(x, y, w, h);
	    }
	 }
	 break;
       case vertBar:
	 for (/*int IRIX DCC BUG! */ i=0; i<m_nNumBlocks; i++) {
	    x = edge;
	    y = height()-edge-i*(m_nBlockWidth+BRD)-m_nBlockWidth;
	    w = width()-2*edge;
	    h = m_nBlockWidth;
	    // do not draw beyond the boundary
	    if (y < edge) {
	       h = y+m_nBlockWidth-edge;
	       y = edge;
	    }
	    p.drawRect(x, y, w, h);
	 }
	 break;
      }

   }
      
   // paint the frame since we are overriding QWidget::paintEvent()
   drawFrame(&p);

   // add a black shadow on the top and left side of the frame.
   // this makes it look more like the Win95 style
   if (m_style == blockedBar) {

      p.setPen(black);
      p.drawLine(frameWidth(), height()-frameWidth()-2,
		 frameWidth(), frameWidth());
      p.drawLine(frameWidth(), frameWidth(),
		 width()-frameWidth()-2, frameWidth());
   }
   
   p.end();
}


/*
 * On a resize event the bar length needs to be recalculated
 * for a solid bar style and the block length and number of blocks to
 * paint needs to be calculated for a blocked bar style.
 */
void QProgressCtrl::resizeEvent( QResizeEvent * )
{
   switch (m_style) {
    case solidBar:
      m_nSolidLen = calcSolidBarLen(m_nPos);
      break;
    case blockedBar:
      m_nBlockWidth = calcBlockLen();
      m_nNumBlocks = calcNumBlocks(m_nPos);
      break;
   }
}