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,2005 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.42.2.1 2005/10/31 00:27:40 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