1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data <http://www.neurondata.com>.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * In addition, as a special exception to the GNU GPL, the copyright holders
38 * give permission to link the code of this program with the Motif and Open
39 * Motif libraries (or with modified versions of these that use the same
40 * license), and distribute linked combinations including the two. You
41 * must obey the GNU General Public License in all respects for all of
42 * the code used other than linking with Motif/Open Motif. If you modify
43 * this file, you may extend this exception to your version of the file,
44 * but you are not obligated to do so. If you do not wish to do so,
45 * delete this exception statement from your version.
47 * ***** END LICENSE BLOCK ***** */
49 #include "ProgressP.h"
54 static void ClassInitialize(void);
55 static void Initialize(Widget
, Widget
, ArgList
, Cardinal
*);
56 static void Resize(Widget
);
57 static void Destroy(Widget
);
58 static void Realize(Widget w
, XtValueMask
*valueMask
,
59 XSetWindowAttributes
*attr
);
60 static void Redisplay(Widget
, XEvent
*, Region
);
61 static Boolean
SetValues(Widget
, Widget
, Widget
, ArgList
, Cardinal
*);
62 static void CopyFontList(XmLProgressWidget p
);
63 static void TimeStr(char *, int);
64 static void DrawBarMeter(XmLProgressWidget p
, XRectangle
*rect
);
65 static void DrawBoxesMeter(XmLProgressWidget p
, XRectangle
*rect
);
66 static void DrawString(XmLProgressWidget
, XmString
, int, int,
67 int, XRectangle
*, XRectangle
*);
68 static Boolean
CvtStringToMeterStyle(Display
*dpy
, XrmValuePtr args
,
69 Cardinal
*numArgs
, XrmValuePtr fromVal
, XrmValuePtr toVal
,
72 static XtResource resources
[] =
75 XmNcompleteValue
, XmCCompleteValue
,
77 XtOffset(XmLProgressWidget
, progress
.completeValue
),
78 XtRImmediate
, (caddr_t
)100
81 XmNnumBoxes
, XmCNumBoxes
,
83 XtOffset(XmLProgressWidget
, progress
.numBoxes
),
84 XtRImmediate
, (caddr_t
)10
89 XtOffset(XmLProgressWidget
, progress
.value
),
90 XtRImmediate
, (caddr_t
)0
93 XmNfontList
, XmCFontList
,
94 XmRFontList
, sizeof(XmFontList
),
95 XtOffset(XmLProgressWidget
, progress
.fontList
),
96 XmRImmediate
, (XtPointer
)0,
99 XmNmeterStyle
, XmCMeterStyle
,
100 XmRMeterStyle
, sizeof(unsigned char),
101 XtOffset(XmLProgressWidget
, progress
.meterStyle
),
102 XmRImmediate
, (XtPointer
)XmMETER_BAR
,
105 XmNshowTime
, XmCShowTime
,
106 XmRBoolean
, sizeof(Boolean
),
107 XtOffset(XmLProgressWidget
, progress
.showTime
),
108 XmRImmediate
, (XtPointer
)False
111 XmNshowPercentage
, XmCShowPercentage
,
112 XmRBoolean
, sizeof(Boolean
),
113 XtOffset(XmLProgressWidget
, progress
.showPercentage
),
114 XmRImmediate
, (XtPointer
)True
118 XmLProgressClassRec xmlProgressClassRec
=
121 (WidgetClass
)&xmPrimitiveClassRec
, /* superclass */
122 "XmLProgress", /* class_name */
123 sizeof(XmLProgressRec
), /* widget_size */
124 ClassInitialize
, /* class_initialize */
125 NULL
, /* class_part_initialize */
126 FALSE
, /* class_inited */
127 (XtInitProc
)Initialize
, /* initialize */
128 NULL
, /* initialize_hook */
129 (XtRealizeProc
)Realize
, /* realize */
132 resources
, /* resources */
133 XtNumber(resources
), /* num_resources */
134 NULLQUARK
, /* xrm_class */
135 TRUE
, /* compress_motion */
136 FALSE
, /* compress_exposure */
137 TRUE
, /* compress_enterleave */
138 TRUE
, /* visible_interest */
139 (XtWidgetProc
)Destroy
, /* destroy */
140 (XtWidgetProc
)Resize
, /* resize */
141 (XtExposeProc
)Redisplay
, /* expose */
142 (XtSetValuesFunc
)SetValues
, /* set_values */
143 NULL
, /* set_values_hook */
144 XtInheritSetValuesAlmost
, /* set_values_almost */
145 NULL
, /* get_values_hook */
146 NULL
, /* accept_focus */
147 XtVersion
, /* version */
148 NULL
, /* callback_private */
149 XtInheritTranslations
, /* tm_table */
150 NULL
, /* query_geometry */
151 NULL
, /* display_accelerator */
152 NULL
, /* extension */
155 (XtWidgetProc
)_XtInherit
, /* border_highlight */
156 (XtWidgetProc
)_XtInherit
, /* border_unhighlight */
157 XtInheritTranslations
, /* translations */
158 NULL
, /* arm_and_activate */
159 NULL
, /* syn_resources */
160 0, /* num_syn_resources */
161 NULL
, /* extension */
168 WidgetClass xmlProgressWidgetClass
= (WidgetClass
)&xmlProgressClassRec
;
171 ClassInitialize(void)
175 XtSetTypeConverter(XmRString
, XmRMeterStyle
, CvtStringToMeterStyle
,
176 0, 0, XtCacheNone
, 0);
180 Initialize(Widget reqW
,
187 p
= (XmLProgressWidget
)newW
;
195 p
->progress
.startTime
= time(0);
197 if (p
->progress
.completeValue
< 1)
199 XmLWarning(newW
, "Initialize() - complete value can't be < 1");
200 p
->progress
.completeValue
= 1;
202 if (p
->progress
.numBoxes
< 1)
204 XmLWarning(newW
, "Initialize() - number of boxes can't be < 1");
205 p
->progress
.numBoxes
= 1;
207 if (p
->progress
.value
< 0)
209 XmLWarning(newW
, "Initialize() - value can't be < 0");
210 p
->progress
.value
= 0;
212 if (p
->progress
.value
> p
->progress
.completeValue
)
214 XmLWarning(newW
, "Initialize() - value can't be > completeValue");
215 p
->progress
.value
= p
->progress
.completeValue
;
217 XtVaSetValues(newW
, XmNtraversalOn
, False
, NULL
);
226 if (!XtIsRealized(w
))
230 XClearArea(dpy
, win
, 0, 0, 0, 0, True
);
239 p
= (XmLProgressWidget
)w
;
243 XFreeGC(dpy
, p
->progress
.gc
);
244 XFreeFont(dpy
, p
->progress
.fallbackFont
);
246 XmFontListFree(p
->progress
.fontList
);
251 XtValueMask
*valueMask
,
252 XSetWindowAttributes
*attr
)
256 WidgetClass superClass
;
257 XtRealizeProc realize
;
261 p
= (XmLProgressWidget
)w
;
263 superClass
= xmlProgressWidgetClass
->core_class
.superclass
;
264 realize
= superClass
->core_class
.realize
;
265 (*realize
)(w
, valueMask
, attr
);
269 p
->progress
.fallbackFont
= XLoadQueryFont(dpy
, "fixed");
270 values
.font
= p
->progress
.fallbackFont
->fid
;
271 p
->progress
.gc
= XCreateGC(dpy
, XtWindow(p
), GCFont
, &values
);
286 if (!XtIsRealized(w
) || !w
->core
.visible
)
289 p
= (XmLProgressWidget
)w
;
292 st
= p
->primitive
.shadow_thickness
;
295 rect
.width
= p
->core
.width
- st
* 2;
296 rect
.height
= p
->core
.height
- st
* 2;
298 if (p
->progress
.meterStyle
== XmMETER_BAR
)
299 DrawBarMeter(p
, &rect
);
300 else if (p
->progress
.meterStyle
== XmMETER_BOXES
)
301 DrawBoxesMeter(p
, &rect
);
304 _XmDrawShadow(dpy
, win
,
305 p
->primitive
.bottom_shadow_GC
,
306 p
->primitive
.top_shadow_GC
,
307 p
->primitive
.shadow_thickness
,
308 0, 0, p
->core
.width
, p
->core
.height
);
310 _XmDrawShadows(dpy
, win
,
311 p
->primitive
.top_shadow_GC
,
312 p
->primitive
.bottom_shadow_GC
,
313 0, 0, p
->core
.width
, p
->core
.height
,
314 p
->primitive
.shadow_thickness
,
320 DrawBoxesMeter(XmLProgressWidget p
,
325 int i
, j
, st
, nb
, x1
, x2
;
329 st
= p
->primitive
.shadow_thickness
;
330 nb
= p
->progress
.numBoxes
;
331 if (nb
* st
* 2 > (int)rect
->width
)
334 if (p
->progress
.completeValue
)
335 j
= (int)((long)nb
* (long)p
->progress
.value
/
336 (long)p
->progress
.completeValue
);
340 for (i
= 0; i
< nb
; i
++)
343 XSetForeground(dpy
, p
->progress
.gc
, p
->primitive
.foreground
);
345 XSetForeground(dpy
, p
->progress
.gc
, p
->core
.background_pixel
);
350 x2
= ((int)rect
->width
* (i
+ 1)) / nb
;
351 XFillRectangle(dpy
, win
, p
->progress
.gc
,
352 rect
->x
+ x1
+ st
, rect
->y
+ st
,
353 x2
- x1
- st
* 2, rect
->height
- st
* 2);
355 _XmDrawShadow(dpy
, win
,
356 p
->primitive
.bottom_shadow_GC
,
357 p
->primitive
.top_shadow_GC
,
358 p
->primitive
.shadow_thickness
,
359 rect
->x
+ x1
, rect
->y
,
360 x2
- x1
, rect
->height
);
362 _XmDrawShadows(dpy
, win
,
363 p
->primitive
.top_shadow_GC
,
364 p
->primitive
.bottom_shadow_GC
,
365 rect
->x
+ x1
, rect
->y
,
366 x2
- x1
, rect
->height
,
367 p
->primitive
.shadow_thickness
,
374 DrawBarMeter(XmLProgressWidget p
,
379 int timeLeft
, timeSoFar
;
382 Dimension strWidth
, strHeight
;
383 XRectangle lRect
, rRect
;
392 if (p
->progress
.completeValue
)
393 l
= (long)rect
->width
* (long)p
->progress
.value
/
394 (long)p
->progress
.completeValue
;
399 lRect
.width
= (Dimension
)l
;
400 lRect
.height
= rect
->height
;
401 XSetForeground(dpy
, p
->progress
.gc
, p
->primitive
.foreground
);
402 XFillRectangle(dpy
, win
, p
->progress
.gc
, lRect
.x
, lRect
.y
,
403 lRect
.width
, lRect
.height
);
406 rRect
.x
= rect
->x
+ (int)l
;
408 rRect
.width
= rect
->width
- (Dimension
)l
;
409 rRect
.height
= rect
->height
;
410 XSetForeground(dpy
, p
->progress
.gc
, p
->core
.background_pixel
);
411 XFillRectangle(dpy
, win
, p
->progress
.gc
, rRect
.x
, rRect
.y
,
412 rRect
.width
, rRect
.height
);
414 if (p
->progress
.completeValue
)
415 percent
= (int)(((long)p
->progress
.value
* 100) /
416 (long)p
->progress
.completeValue
);
420 /* percent complete */
421 sprintf(c
, "%d%c", percent
, '%');
422 str
= XmStringCreateSimple(c
);
423 XmStringExtent(p
->progress
.fontList
, str
, &strWidth
, &strHeight
);
424 if (p
->progress
.showPercentage
)
425 DrawString(p
, str
, rect
->x
+ rect
->width
/ 2 - (int)strWidth
/ 2,
426 rect
->y
+ rect
->height
/ 2 - (int)strHeight
/ 2, strWidth
,
431 currentTime
= time(0);
432 timeSoFar
= (int)(currentTime
- p
->progress
.startTime
);
433 if (p
->progress
.showTime
&& p
->progress
.value
&&
434 p
->progress
.value
!= p
->progress
.completeValue
&& timeSoFar
)
436 TimeStr(c
, timeSoFar
);
437 str
= XmStringCreateSimple(c
);
438 XmStringExtent(p
->progress
.fontList
, str
,
439 &strWidth
, &strHeight
);
440 DrawString(p
, str
, rect
->x
+ 5, rect
->y
+ rect
->height
/ 2 -
441 (int)strHeight
/ 2, strWidth
, &lRect
, &rRect
);
448 timeLeft
= (timeSoFar
* 100 / percent
) - timeSoFar
;
449 if (p
->progress
.showTime
&& percent
&& percent
!= 100 && timeLeft
)
451 TimeStr(c
, timeLeft
);
452 str
= XmStringCreateSimple(c
);
453 XmStringExtent(p
->progress
.fontList
, str
,
454 &strWidth
, &strHeight
);
455 DrawString(p
, str
, rect
->x
+ rect
->width
- strWidth
- 5,
456 rect
->y
+ rect
->height
/ 2 - (int)strHeight
/ 2,
457 strWidth
, &lRect
, &rRect
);
463 DrawString(XmLProgressWidget p
,
476 if (lRect
->width
&& lRect
->height
)
478 XSetForeground(dpy
, p
->progress
.gc
, p
->core
.background_pixel
);
479 XSetClipRectangles(dpy
, p
->progress
.gc
, 0, 0, lRect
, 1, Unsorted
);
480 XmStringDraw(dpy
, win
, p
->progress
.fontList
, str
,
481 p
->progress
.gc
, x
, y
, strWidth
, XmALIGNMENT_BEGINNING
,
482 XmSTRING_DIRECTION_L_TO_R
, 0);
483 XSetClipMask(dpy
, p
->progress
.gc
, None
);
485 if (rRect
->width
&& rRect
->height
)
487 XSetForeground(dpy
, p
->progress
.gc
, p
->primitive
.foreground
);
488 XSetClipRectangles(dpy
, p
->progress
.gc
, 0, 0, rRect
, 1, Unsorted
);
489 XmStringDraw(dpy
, win
, p
->progress
.fontList
, str
,
490 p
->progress
.gc
, x
, y
, strWidth
, XmALIGNMENT_BEGINNING
,
491 XmSTRING_DIRECTION_L_TO_R
, 0);
492 XSetClipMask(dpy
, p
->progress
.gc
, None
);
510 sprintf(c
, "%d:0%d hr", h
, m
);
512 sprintf(c
, "%d:%d hr", h
, m
);
513 else if (m
> 0 && s
< 10)
514 sprintf(c
, "%d:0%d min", m
, s
);
516 sprintf(c
, "%d:%d min", m
, s
);
518 sprintf(c
, "%d sec", s
);
522 SetValues(Widget curW
,
528 XmLProgressWidget cur
, p
;
531 cur
= (XmLProgressWidget
)curW
;
532 p
= (XmLProgressWidget
)newW
;
533 app
= XtWidgetToApplicationContext(curW
);
534 if (p
->progress
.value
== 0)
535 p
->progress
.startTime
= time(0);
536 if (p
->progress
.completeValue
< 1)
538 XmLWarning(newW
, "SetValues() - complete value can't be < 1");
539 p
->progress
.completeValue
= 1;
541 if (p
->progress
.numBoxes
< 1)
543 XmLWarning(newW
, "SetValues() - number of boxes can't be < 1");
544 p
->progress
.numBoxes
= 1;
546 if (p
->progress
.value
< 0)
548 XmLWarning(newW
, "SetValues() - value can't be < 0");
549 p
->progress
.value
= 0;
551 if (p
->progress
.value
> p
->progress
.completeValue
)
553 XmLWarning(newW
, "SetValues() - value can't be > completeValue");
554 p
->progress
.value
= p
->progress
.completeValue
;
556 if (p
->progress
.fontList
!= cur
->progress
.fontList
)
558 XmFontListFree(cur
->progress
.fontList
);
561 /* display changes immediately since we may be not get back
562 to XNextEvent if the calling application is computing */
563 if (p
->core
.background_pixel
!= cur
->core
.background_pixel
||
564 p
->primitive
.foreground
!= cur
->primitive
.foreground
||
565 p
->progress
.value
!= cur
->progress
.value
||
566 p
->progress
.completeValue
!= cur
->progress
.completeValue
||
567 p
->progress
.fontList
!= cur
->progress
.fontList
||
568 p
->progress
.showTime
!= cur
->progress
.showTime
||
569 p
->progress
.showPercentage
!= cur
->progress
.showPercentage
||
570 p
->progress
.meterStyle
!= cur
->progress
.meterStyle
||
571 p
->progress
.numBoxes
!= cur
->progress
.numBoxes
||
572 p
->primitive
.shadow_thickness
!= cur
->primitive
.shadow_thickness
)
574 Redisplay(newW
, 0, 0);
575 XFlush(XtDisplay(newW
));
576 XmUpdateDisplay(newW
);
582 CopyFontList(XmLProgressWidget p
)
584 if (!p
->progress
.fontList
)
585 p
->progress
.fontList
= XmLFontListCopyDefault((Widget
)p
);
587 p
->progress
.fontList
= XmFontListCopy(p
->progress
.fontList
);
588 if (!p
->progress
.fontList
)
589 XmLWarning((Widget
)p
, "- fatal error - font list NULL");
593 CvtStringToMeterStyle(Display
*dpy
,
600 static XmLStringToUCharMap map
[] =
602 { "METER_BAR", XmMETER_BAR
},
603 { "METER_BOXES", XmMETER_BOXES
},
607 return XmLCvtStringToUChar(dpy
, "XmRMeterStyle", map
, fromVal
, toVal
);
615 XmLCreateProgress(Widget parent
,
620 return XtCreateWidget(name
, xmlProgressWidgetClass
, parent
,