1 /********************************************************************************
2 *                                                                               *
3 *                      P r o g r e s s B a r   W i d g e t                      *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1998,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXProgressBar.cpp,v 1.47 2006/01/22 17:58:37 fox Exp $                   *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXThread.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXRegistry.h"
35 #include "FXApp.h"
36 #include "FXDCWindow.h"
37 #include "FXFont.h"
38 #include "FXProgressBar.h"
39 
40 
41 /*
42   Notes:
43   - Reduced flicker by not drawing background at all.
44   - Reduced flicker by setting clip rectangle to only redraw interior.
45   - Progress bar has a target, as it can send update messages.
46 */
47 
48 #define PROGRESSBAR_MASK (PROGRESSBAR_PERCENTAGE|PROGRESSBAR_VERTICAL|PROGRESSBAR_DIAL)
49 
50 using namespace FX;
51 
52 /*******************************************************************************/
53 
54 namespace FX {
55 
56 
57 // Map
58 FXDEFMAP(FXProgressBar) FXProgressBarMap[]={
59   FXMAPFUNC(SEL_PAINT,0,FXProgressBar::onPaint),
60   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_SETVALUE,FXProgressBar::onCmdSetValue),
61   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_SETINTVALUE,FXProgressBar::onCmdSetIntValue),
62   FXMAPFUNC(SEL_COMMAND,FXWindow::ID_GETINTVALUE,FXProgressBar::onCmdGetIntValue),
63   };
64 
65 
66 // Object implementation
FXIMPLEMENT(FXProgressBar,FXFrame,FXProgressBarMap,ARRAYNUMBER (FXProgressBarMap))67 FXIMPLEMENT(FXProgressBar,FXFrame,FXProgressBarMap,ARRAYNUMBER(FXProgressBarMap))
68 
69 
70 
71 // Make progress bar
72 FXProgressBar::FXProgressBar(FXComposite* p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):
73   FXFrame(p,opts,x,y,w,h,pl,pr,pt,pb){
74   target=tgt;
75   message=sel;
76   progress=0;
77   total=100;
78   if(opts&PROGRESSBAR_DIAL){
79     textNumColor=FXRGB(255,255,255);
80     barBGColor=FXRGB(0,0,0);
81     barBGColor=getApp()->getBackColor();
82     textNumColor=FXRGB(0,0,255);
83     barsize=60;
84     }
85   else{
86     barBGColor=getApp()->getBackColor();
87     textNumColor=FXRGB(0,0,255);
88     barsize=5;
89     }
90   font=getApp()->getNormalFont();
91   barColor=FXRGB(0,0,255);
92   textAltColor=FXRGB(255,255,255);
93   backColor=barBGColor;
94   }
95 
96 
97 // Get minimum width
getDefaultWidth()98 FXint FXProgressBar::getDefaultWidth(){
99   FXint w=1,t;
100   if((options&PROGRESSBAR_VERTICAL) || (options&PROGRESSBAR_DIAL)){
101     w=barsize;
102     if(options&PROGRESSBAR_PERCENTAGE){
103       t=font->getTextWidth("100%",4);
104       if(w<t) w=t;
105       }
106     }
107   return w+padleft+padright+(border<<1);
108   }
109 
110 
111 // Get minimum height
getDefaultHeight()112 FXint FXProgressBar::getDefaultHeight(){
113   FXint h=1,t;
114   if(!(options&PROGRESSBAR_VERTICAL) || (options&PROGRESSBAR_DIAL)){
115     h=barsize;
116     if(options&PROGRESSBAR_PERCENTAGE){
117       t=font->getFontHeight();
118       if(h<t) h=t;
119       }
120     }
121   return h+padtop+padbottom+(border<<1);
122   }
123 
124 
125 // Create window
create()126 void FXProgressBar::create(){
127   FXFrame::create();
128   font->create();
129   }
130 
131 
132 // Detach window
detach()133 void FXProgressBar::detach(){
134   FXFrame::detach();
135   font->detach();
136   }
137 
138 
139 // Update progress value from a message
onCmdSetValue(FXObject *,FXSelector,void * ptr)140 long FXProgressBar::onCmdSetValue(FXObject*,FXSelector,void* ptr){
141   setProgress((FXuint)(FXival)ptr);
142   return 1;
143   }
144 
145 
146 // Set value
onCmdSetIntValue(FXObject *,FXSelector,void * ptr)147 long FXProgressBar::onCmdSetIntValue(FXObject*,FXSelector,void* ptr){
148   setProgress(*((FXint*)ptr));
149   return 1;
150   }
151 
152 
153 // Get value
onCmdGetIntValue(FXObject *,FXSelector,void * ptr)154 long FXProgressBar::onCmdGetIntValue(FXObject*,FXSelector,void* ptr){
155   *((FXint*)ptr)=getProgress();
156   return 1;
157   }
158 
159 
160 // Draw only the interior, i.e. the part that changes
drawInterior(FXDCWindow & dc)161 void FXProgressBar::drawInterior(FXDCWindow& dc){
162   FXint percent,barlength,barfilled,tx,ty,tw,th,n,d;
163   FXchar numtext[5];
164 
165   if(options&PROGRESSBAR_DIAL){
166 
167     // If total is 0, it's 100%
168     barfilled=23040;
169     percent=100;
170     if(total!=0){
171       barfilled=(FXuint) (((double)progress * (double)23040) / (double)total);
172       percent=(FXuint) (((double)progress * 100.0) / (double)total);
173       }
174 
175     tw=width-(border<<1)-padleft-padright;
176     th=height-(border<<1)-padtop-padbottom;
177     d=FXMIN(tw,th)-1;
178 
179     tx=border+padleft+((tw-d)/2);
180     ty=border+padtop+((th-d)/2);
181 
182     if(barfilled!=23040){
183       dc.setForeground(barBGColor);
184       dc.fillArc(tx,ty,d,d,5760,23040-barfilled);
185       }
186     if(barfilled!=0){
187       dc.setForeground(barColor);
188       dc.fillArc(tx,ty,d,d,5760,-barfilled);
189       }
190 
191     // Draw outside circle
192     dc.setForeground(borderColor);
193     dc.drawArc(tx+1,ty,d,d,90*64,45*64);
194     dc.drawArc(tx,ty+1,d,d,135*64,45*64);
195     dc.setForeground(baseColor);
196     dc.drawArc(tx-1,ty,d,d,270*64,45*64);
197     dc.drawArc(tx,ty-1,d,d,315*64,45*64);
198 
199     dc.setForeground(shadowColor);
200     dc.drawArc(tx,ty,d,d,45*64,180*64);
201     dc.setForeground(hiliteColor);
202     dc.drawArc(tx,ty,d,d,225*64,180*64);
203 
204     // Draw text
205     if(options&PROGRESSBAR_PERCENTAGE){
206       dc.setFont(font);
207       tw=font->getTextWidth("100%",4);
208       if(tw>(10*d)/16) return;
209       th=font->getFontHeight();
210       if(th>d/2) return;
211       sprintf(numtext,"%d%%",percent);
212       n=strlen(numtext);
213       tw=font->getTextWidth(numtext,n);
214       th=font->getFontHeight();
215       tx=tx+d/2-tw/2;
216       ty=ty+d/2+font->getFontAscent()+5;
217       //dc.setForeground(textNumColor);
218 #ifdef HAVE_XFT_H
219       dc.setForeground(barBGColor);             // Code for XFT until XFT can use BLT_SRC_XOR_DST
220       dc.drawText(tx-1,ty,numtext,n);
221       dc.drawText(tx+1,ty,numtext,n);
222       dc.drawText(tx,ty-1,numtext,n);
223       dc.drawText(tx,ty+1,numtext,n);
224       dc.setForeground(textNumColor);
225       dc.drawText(tx,ty,numtext,n);
226 #else
227       dc.setForeground(FXRGB(255,255,255));     // Original code
228       dc.setFunction(BLT_SRC_XOR_DST);
229       dc.drawText(tx,ty,numtext,n);
230 #endif
231       }
232     }
233 
234   // Vertical bar
235   else if(options&PROGRESSBAR_VERTICAL){
236 
237     // If total is 0, it's 100%
238     barlength=height-border-border;
239     barfilled=barlength;
240     percent=100;
241     if(total!=0){
242       barfilled=(FXuint) (((double)progress * (double)barlength) / (double)total);
243       percent=(FXuint) (((double)progress * 100.0) / (double)total);
244       }
245 
246     // Draw completed bar
247     if(0<barfilled){
248       dc.setForeground(barColor);
249       dc.fillRectangle(border,height-border-barfilled,width-(border<<1),barfilled);
250       }
251 
252     // Draw uncompleted bar
253     if(barfilled<barlength){
254       dc.setForeground(barBGColor);
255       dc.fillRectangle(border,border,width-(border<<1),barlength-barfilled);
256       }
257 
258     // Draw text
259     if(options&PROGRESSBAR_PERCENTAGE){
260       dc.setFont(font);
261       sprintf(numtext,"%d%%",percent);
262       n=strlen(numtext);
263       tw=font->getTextWidth(numtext,n);
264       th=font->getFontHeight();
265       ty=(height-th)/2+font->getFontAscent();
266       tx=(width-tw)/2;
267       if(height-border-barfilled>ty){           // In upper side
268         dc.setForeground(textNumColor);
269         dc.setClipRectangle(border,border,width-(border<<1),height-(border<<1));
270         dc.drawText(tx,ty,numtext,n);
271         }
272       else if(ty-th>height-border-barfilled){   // In lower side
273         dc.setForeground(textAltColor);
274         dc.setClipRectangle(border,border,width-(border<<1),height-(border<<1));
275         dc.drawText(tx,ty,numtext,n);
276         }
277       else{                                     // In between!
278         dc.setForeground(textAltColor);
279         dc.setClipRectangle(border,height-border-barfilled,width-(border<<1),barfilled);
280         dc.drawText(tx,ty,numtext,n);
281         dc.setForeground(textNumColor);
282         dc.setClipRectangle(border,border,width-(border<<1),barlength-barfilled);
283         dc.drawText(tx,ty,numtext,n);
284         dc.clearClipRectangle();
285         }
286       }
287     }
288 
289   // Horizontal bar
290   else{
291 
292     // If total is 0, it's 100%
293     barlength=width-border-border;
294     barfilled=barlength;
295     percent=100;
296     if(total!=0){
297       barfilled=(FXuint) (((double)progress * (double)barlength) / (double)total);
298       percent=(FXuint) (((double)progress * 100.0) / (double)total);
299       }
300 
301     // Draw completed bar
302     if(0<barfilled){
303       dc.setForeground(barColor);
304       dc.fillRectangle(border,border,barfilled,height-(border<<1));
305       }
306 
307     // Draw uncompleted bar
308     if(barfilled<barlength){
309       dc.setForeground(barBGColor);
310       dc.fillRectangle(border+barfilled,border,barlength-barfilled,height-(border<<1));
311       }
312 
313     // Draw text
314     if(options&PROGRESSBAR_PERCENTAGE){
315       dc.setFont(font);
316       sprintf(numtext,"%d%%",percent);
317       n=strlen(numtext);
318       tw=font->getTextWidth(numtext,n);
319       th=font->getFontHeight();
320       ty=(height-th)/2+font->getFontAscent();
321       tx=(width-tw)/2;
322       if(border+barfilled<=tx){           // In right side
323         dc.setForeground(textNumColor);
324         dc.setClipRectangle(border,border,width-(border<<1),height-(border<<1));
325         dc.drawText(tx,ty,numtext,n);
326         }
327       else if(tx+tw<=border+barfilled){   // In left side
328         dc.setForeground(textAltColor);
329         dc.setClipRectangle(border,border,width-(border<<1),height-(border<<1));
330         dc.drawText(tx,ty,numtext,n);
331         }
332       else{                               // In between!
333         dc.setForeground(textAltColor);
334         dc.setClipRectangle(border,border,barfilled,height);
335         dc.drawText(tx,ty,numtext,n);
336         dc.setForeground(textNumColor);
337         dc.setClipRectangle(border+barfilled,border,barlength-barfilled,height);
338         dc.drawText(tx,ty,numtext,n);
339         dc.clearClipRectangle();
340         }
341       }
342     }
343   }
344 
345 
346 // Draw the progress bar
onPaint(FXObject *,FXSelector,void * ptr)347 long FXProgressBar::onPaint(FXObject*,FXSelector,void *ptr){
348   FXEvent *event=(FXEvent*)ptr;
349   FXDCWindow dc(this,event);
350 
351   // Draw borders if any
352   drawFrame(dc,0,0,width,height);
353 
354   // Background
355   dc.setForeground(getBaseColor());
356   dc.fillRectangle(border,border,width-(border<<1),height-(border<<1));
357 
358   // Interior
359   drawInterior(dc);
360   return 1;
361   }
362 
363 
364 // Set amount of progress made
setProgress(FXuint value)365 void FXProgressBar::setProgress(FXuint value){
366   if(value>total) value=total;
367   if(value!=progress){
368     progress=value;
369     if(xid){
370       FXDCWindow dc(this);
371       drawInterior(dc);
372       }
373     getApp()->flush();
374     }
375   }
376 
377 
378 // Increment amount of progress
increment(FXuint value)379 void FXProgressBar::increment(FXuint value){
380   setProgress(progress+value);
381   }
382 
383 
384 // Set total amount to completion
setTotal(FXuint value)385 void FXProgressBar::setTotal(FXuint value){
386   if(value!=total){
387     total=value;
388     if(xid){
389       FXDCWindow dc(this);
390       drawInterior(dc);
391       }
392     getApp()->flush();
393     }
394   }
395 
396 
397 // Change bar color
setBarColor(FXColor clr)398 void FXProgressBar::setBarColor(FXColor clr){
399   if(barColor!=clr){
400     barColor=clr;
401     update(border,border,width-(border<<1),height-(border<<1));
402     }
403   }
404 
405 
406 // Change bar background color
setBarBGColor(FXColor clr)407 void FXProgressBar::setBarBGColor(FXColor clr){
408   if(barBGColor!=clr){
409     barBGColor=clr;
410     update(border,border,width-(border<<1),height-(border<<1));
411     }
412   }
413 
414 
415 // Change text foreground color
setTextColor(FXColor clr)416 void FXProgressBar::setTextColor(FXColor clr){
417   if(textNumColor!=clr){
418     textNumColor=clr;
419     update();
420     }
421   }
422 
423 
424 // Change alternate text color
setTextAltColor(FXColor clr)425 void FXProgressBar::setTextAltColor(FXColor clr){
426   if(textAltColor!=clr){
427     textAltColor=clr;
428     update();
429     }
430   }
431 
432 
433 // Hide percentage display
hideNumber()434 void FXProgressBar::hideNumber(){
435   if(options&PROGRESSBAR_PERCENTAGE){
436     options&=~PROGRESSBAR_PERCENTAGE;
437     recalc();
438     update();
439     }
440   }
441 
442 
443 // Show percentage display
showNumber()444 void FXProgressBar::showNumber(){
445   if(!(options&PROGRESSBAR_PERCENTAGE)){
446     options|=PROGRESSBAR_PERCENTAGE;
447     recalc();
448     update();
449     }
450   }
451 
452 
setBarSize(FXint size)453 void FXProgressBar::setBarSize(FXint size){
454   if(size<1){ fxerror("%s::setBarSize: zero or negative barsize specified.\n",getClassName()); }
455   if(barsize!=size){
456     barsize=size;
457     recalc();
458     update();
459     }
460   }
461 
462 
463 // Change the font
setFont(FXFont * fnt)464 void FXProgressBar::setFont(FXFont *fnt){
465   if(!fnt){ fxerror("%s::setFont: NULL font specified.\n",getClassName()); }
466   if(font!=fnt){
467     font=fnt;
468     recalc();
469     update();
470     }
471   }
472 
473 
474 // Change style of the bar widget
setBarStyle(FXuint style)475 void FXProgressBar::setBarStyle(FXuint style){
476   FXuint opts=(options&~PROGRESSBAR_MASK) | (style&PROGRESSBAR_MASK);
477   if(options!=opts){
478     options=opts;
479     recalc();
480     }
481   }
482 
483 
484 // Get style of the bar widget
getBarStyle() const485 FXuint FXProgressBar::getBarStyle() const {
486   return (options&PROGRESSBAR_MASK);
487   }
488 
489 
490 // Save object to stream
save(FXStream & store) const491 void FXProgressBar::save(FXStream& store) const {
492   FXFrame::save(store);
493   store << progress;
494   store << total;
495   store << barsize;
496   store << font;
497   store << barBGColor;
498   store << barColor;
499   store << textNumColor;
500   store << textAltColor;
501   }
502 
503 
504 // Load object from stream
load(FXStream & store)505 void FXProgressBar::load(FXStream& store){
506   FXFrame::load(store);
507   store >> progress;
508   store >> total;
509   store >> barsize;
510   store >> font;
511   store >> barBGColor;
512   store >> barColor;
513   store >> textNumColor;
514   store >> textAltColor;
515   }
516 
517 
518 
519 // Destroy
~FXProgressBar()520 FXProgressBar::~FXProgressBar(){
521   font=(FXFont*)-1L;
522   }
523 
524 }
525