mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-12 14:37:50 +00:00
606 lines
16 KiB
C
606 lines
16 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
/*
|
|
* The following source code is part of the Microline Widget Library.
|
|
* The Microline widget library is made available to Mozilla developers
|
|
* under the Netscape Public License (NPL) by Neuron Data. To learn
|
|
* more about Neuron Data, please visit the Neuron Data Home Page at
|
|
* http://www.neurondata.com.
|
|
*/
|
|
|
|
#include "ProgressP.h"
|
|
#include <stdio.h>
|
|
#include <sys/time.h>
|
|
|
|
static void ClassInitialize(void);
|
|
static void Initialize(Widget , Widget, ArgList, Cardinal *);
|
|
static void Resize(Widget);
|
|
static void Destroy(Widget);
|
|
static void Realize(Widget w, XtValueMask *valueMask,
|
|
XSetWindowAttributes *attr);
|
|
static void Redisplay(Widget, XEvent *, Region);
|
|
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
|
|
static void CopyFontList(XmLProgressWidget p);
|
|
static void TimeStr(char *, int);
|
|
static void DrawBarMeter(XmLProgressWidget p, XRectangle *rect);
|
|
static void DrawBoxesMeter(XmLProgressWidget p, XRectangle *rect);
|
|
static void DrawString(XmLProgressWidget, XmString, int, int,
|
|
int, XRectangle *, XRectangle *);
|
|
static Boolean CvtStringToMeterStyle(Display *dpy, XrmValuePtr args,
|
|
Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal,
|
|
XtPointer *data);
|
|
|
|
static XtResource resources[] =
|
|
{
|
|
{
|
|
XmNcompleteValue, XmCCompleteValue,
|
|
XtRInt, sizeof(int),
|
|
XtOffset(XmLProgressWidget, progress.completeValue),
|
|
XtRImmediate, (caddr_t)100
|
|
},
|
|
{
|
|
XmNnumBoxes, XmCNumBoxes,
|
|
XtRInt, sizeof(int),
|
|
XtOffset(XmLProgressWidget, progress.numBoxes),
|
|
XtRImmediate, (caddr_t)10
|
|
},
|
|
{
|
|
XmNvalue, XmCValue,
|
|
XtRInt, sizeof(int),
|
|
XtOffset(XmLProgressWidget, progress.value),
|
|
XtRImmediate, (caddr_t)0
|
|
},
|
|
{
|
|
XmNfontList, XmCFontList,
|
|
XmRFontList, sizeof(XmFontList),
|
|
XtOffset(XmLProgressWidget, progress.fontList),
|
|
XmRImmediate, (XtPointer)0,
|
|
},
|
|
{
|
|
XmNmeterStyle, XmCMeterStyle,
|
|
XmRMeterStyle, sizeof(unsigned char),
|
|
XtOffset(XmLProgressWidget, progress.meterStyle),
|
|
XmRImmediate, (XtPointer)XmMETER_BAR,
|
|
},
|
|
{
|
|
XmNshowTime, XmCShowTime,
|
|
XmRBoolean, sizeof(Boolean),
|
|
XtOffset(XmLProgressWidget, progress.showTime),
|
|
XmRImmediate, (XtPointer)False
|
|
},
|
|
{
|
|
XmNshowPercentage, XmCShowPercentage,
|
|
XmRBoolean, sizeof(Boolean),
|
|
XtOffset(XmLProgressWidget, progress.showPercentage),
|
|
XmRImmediate, (XtPointer)True
|
|
}
|
|
};
|
|
|
|
XmLProgressClassRec xmlProgressClassRec =
|
|
{
|
|
{ /* Core */
|
|
(WidgetClass)&xmPrimitiveClassRec, /* superclass */
|
|
"XmLProgress", /* class_name */
|
|
sizeof(XmLProgressRec), /* widget_size */
|
|
ClassInitialize, /* class_initialize */
|
|
NULL, /* class_part_initialize */
|
|
FALSE, /* class_inited */
|
|
(XtInitProc)Initialize, /* initialize */
|
|
NULL, /* initialize_hook */
|
|
(XtRealizeProc)Realize, /* realize */
|
|
NULL, /* actions */
|
|
0, /* num_actions */
|
|
resources, /* resources */
|
|
XtNumber(resources), /* num_resources */
|
|
NULLQUARK, /* xrm_class */
|
|
TRUE, /* compress_motion */
|
|
FALSE, /* compress_exposure */
|
|
TRUE, /* compress_enterleave */
|
|
TRUE, /* visible_interest */
|
|
(XtWidgetProc)Destroy, /* destroy */
|
|
(XtWidgetProc)Resize, /* resize */
|
|
(XtExposeProc)Redisplay, /* expose */
|
|
(XtSetValuesFunc)SetValues, /* set_values */
|
|
NULL, /* set_values_hook */
|
|
XtInheritSetValuesAlmost, /* set_values_almost */
|
|
NULL, /* get_values_hook */
|
|
NULL, /* accept_focus */
|
|
XtVersion, /* version */
|
|
NULL, /* callback_private */
|
|
XtInheritTranslations, /* tm_table */
|
|
NULL, /* query_geometry */
|
|
NULL, /* display_accelerator */
|
|
NULL, /* extension */
|
|
},
|
|
{ /* Primitive */
|
|
(XtWidgetProc)_XtInherit, /* border_highlight */
|
|
(XtWidgetProc)_XtInherit, /* border_unhighlight */
|
|
XtInheritTranslations, /* translations */
|
|
NULL, /* arm_and_activate */
|
|
NULL, /* syn_resources */
|
|
0, /* num_syn_resources */
|
|
NULL, /* extension */
|
|
},
|
|
{ /* Progress */
|
|
0, /* unused */
|
|
}
|
|
};
|
|
|
|
WidgetClass xmlProgressWidgetClass = (WidgetClass)&xmlProgressClassRec;
|
|
|
|
static void
|
|
ClassInitialize(void)
|
|
{
|
|
XmLInitialize();
|
|
|
|
XtSetTypeConverter(XmRString, XmRMeterStyle, CvtStringToMeterStyle,
|
|
0, 0, XtCacheNone, 0);
|
|
}
|
|
|
|
static void
|
|
Initialize(Widget reqW,
|
|
Widget newW,
|
|
ArgList args,
|
|
Cardinal *narg)
|
|
{
|
|
XmLProgressWidget p;
|
|
|
|
p = (XmLProgressWidget)newW;
|
|
|
|
if (!p->core.width)
|
|
p->core.width = 200;
|
|
if (!p->core.height)
|
|
p->core.height = 30;
|
|
|
|
p->progress.gc = 0;
|
|
p->progress.startTime = time(0);
|
|
CopyFontList(p);
|
|
if (p->progress.completeValue < 1)
|
|
{
|
|
XmLWarning(newW, "Initialize() - complete value can't be < 1");
|
|
p->progress.completeValue = 1;
|
|
}
|
|
if (p->progress.numBoxes < 1)
|
|
{
|
|
XmLWarning(newW, "Initialize() - number of boxes can't be < 1");
|
|
p->progress.numBoxes = 1;
|
|
}
|
|
if (p->progress.value < 0)
|
|
{
|
|
XmLWarning(newW, "Initialize() - value can't be < 0");
|
|
p->progress.value = 0;
|
|
}
|
|
if (p->progress.value > p->progress.completeValue)
|
|
{
|
|
XmLWarning(newW, "Initialize() - value can't be > completeValue");
|
|
p->progress.value = p->progress.completeValue;
|
|
}
|
|
XtVaSetValues(newW, XmNtraversalOn, False, NULL);
|
|
}
|
|
|
|
static void
|
|
Resize(Widget w)
|
|
{
|
|
Display *dpy;
|
|
Window win;
|
|
|
|
if (!XtIsRealized(w))
|
|
return;
|
|
dpy = XtDisplay(w);
|
|
win = XtWindow(w);
|
|
XClearArea(dpy, win, 0, 0, 0, 0, True);
|
|
}
|
|
|
|
static void
|
|
Destroy(Widget w)
|
|
{
|
|
Display *dpy;
|
|
XmLProgressWidget p;
|
|
|
|
p = (XmLProgressWidget)w;
|
|
dpy = XtDisplay(w);
|
|
if (p->progress.gc)
|
|
{
|
|
XFreeGC(dpy, p->progress.gc);
|
|
XFreeFont(dpy, p->progress.fallbackFont);
|
|
}
|
|
XmFontListFree(p->progress.fontList);
|
|
}
|
|
|
|
static void
|
|
Realize(Widget w,
|
|
XtValueMask *valueMask,
|
|
XSetWindowAttributes *attr)
|
|
{
|
|
XmLProgressWidget p;
|
|
Display *dpy;
|
|
WidgetClass superClass;
|
|
XtRealizeProc realize;
|
|
XGCValues values;
|
|
/* XtGCMask mask;*/
|
|
|
|
p = (XmLProgressWidget)w;
|
|
dpy = XtDisplay(p);
|
|
superClass = xmlProgressWidgetClass->core_class.superclass;
|
|
realize = superClass->core_class.realize;
|
|
(*realize)(w, valueMask, attr);
|
|
|
|
if (!p->progress.gc)
|
|
{
|
|
p->progress.fallbackFont = XLoadQueryFont(dpy, "fixed");
|
|
values.font = p->progress.fallbackFont->fid;
|
|
p->progress.gc = XCreateGC(dpy, XtWindow(p), GCFont, &values);
|
|
}
|
|
}
|
|
|
|
static void
|
|
Redisplay(Widget w,
|
|
XEvent *event,
|
|
Region region)
|
|
{
|
|
XmLProgressWidget p;
|
|
Display *dpy;
|
|
Window win;
|
|
XRectangle rect;
|
|
int st;
|
|
|
|
if (!XtIsRealized(w) || !w->core.visible)
|
|
return;
|
|
|
|
p = (XmLProgressWidget)w;
|
|
dpy = XtDisplay(w);
|
|
win = XtWindow(w);
|
|
st = p->primitive.shadow_thickness;
|
|
rect.x = st;
|
|
rect.y = st;
|
|
rect.width = p->core.width - st * 2;
|
|
rect.height = p->core.height - st * 2;
|
|
|
|
if (p->progress.meterStyle == XmMETER_BAR)
|
|
DrawBarMeter(p, &rect);
|
|
else if (p->progress.meterStyle == XmMETER_BOXES)
|
|
DrawBoxesMeter(p, &rect);
|
|
|
|
#ifdef MOTIF11
|
|
_XmDrawShadow(dpy, win,
|
|
p->primitive.bottom_shadow_GC,
|
|
p->primitive.top_shadow_GC,
|
|
p->primitive.shadow_thickness,
|
|
0, 0, p->core.width, p->core.height);
|
|
#else
|
|
_XmDrawShadows(dpy, win,
|
|
p->primitive.top_shadow_GC,
|
|
p->primitive.bottom_shadow_GC,
|
|
0, 0, p->core.width, p->core.height,
|
|
p->primitive.shadow_thickness,
|
|
XmSHADOW_IN);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
DrawBoxesMeter(XmLProgressWidget p,
|
|
XRectangle *rect)
|
|
{
|
|
Display *dpy;
|
|
Window win;
|
|
int i, j, st, nb, x1, x2;
|
|
|
|
dpy = XtDisplay(p);
|
|
win = XtWindow(p);
|
|
st = p->primitive.shadow_thickness;
|
|
nb = p->progress.numBoxes;
|
|
if (nb * st * 2 > (int)rect->width)
|
|
return;
|
|
|
|
if (p->progress.completeValue)
|
|
j = (int)((long)nb * (long)p->progress.value /
|
|
(long)p->progress.completeValue);
|
|
else
|
|
j = 0;
|
|
x2 = 0;
|
|
for (i = 0; i < nb; i++)
|
|
{
|
|
if (i < j)
|
|
XSetForeground(dpy, p->progress.gc, p->primitive.foreground);
|
|
else
|
|
XSetForeground(dpy, p->progress.gc, p->core.background_pixel);
|
|
x1 = x2;
|
|
if (i == nb - 1)
|
|
x2 = rect->width;
|
|
else
|
|
x2 = ((int)rect->width * (i + 1)) / nb;
|
|
XFillRectangle(dpy, win, p->progress.gc,
|
|
rect->x + x1 + st, rect->y + st,
|
|
x2 - x1 - st * 2, rect->height - st * 2);
|
|
#ifdef MOTIF11
|
|
_XmDrawShadow(dpy, win,
|
|
p->primitive.bottom_shadow_GC,
|
|
p->primitive.top_shadow_GC,
|
|
p->primitive.shadow_thickness,
|
|
rect->x + x1, rect->y,
|
|
x2 - x1, rect->height);
|
|
#else
|
|
_XmDrawShadows(dpy, win,
|
|
p->primitive.top_shadow_GC,
|
|
p->primitive.bottom_shadow_GC,
|
|
rect->x + x1, rect->y,
|
|
x2 - x1, rect->height,
|
|
p->primitive.shadow_thickness,
|
|
XmSHADOW_IN);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
DrawBarMeter(XmLProgressWidget p,
|
|
XRectangle *rect)
|
|
{
|
|
Display *dpy;
|
|
Window win;
|
|
int timeLeft, timeSoFar;
|
|
time_t currentTime;
|
|
XmString str;
|
|
Dimension strWidth, strHeight;
|
|
XRectangle lRect, rRect;
|
|
int percent;
|
|
char c[10];
|
|
long l;
|
|
|
|
dpy = XtDisplay(p);
|
|
win = XtWindow(p);
|
|
|
|
/* Left Rect */
|
|
if (p->progress.completeValue)
|
|
l = (long)rect->width * (long)p->progress.value /
|
|
(long)p->progress.completeValue;
|
|
else
|
|
l = 0;
|
|
lRect.x = rect->x;
|
|
lRect.y = rect->y;
|
|
lRect.width = (Dimension)l;
|
|
lRect.height = rect->height;
|
|
XSetForeground(dpy, p->progress.gc, p->primitive.foreground);
|
|
XFillRectangle(dpy, win, p->progress.gc, lRect.x, lRect.y,
|
|
lRect.width, lRect.height);
|
|
|
|
/* Right Rect */
|
|
rRect.x = rect->x + (int)l;
|
|
rRect.y = rect->y;
|
|
rRect.width = rect->width - (Dimension)l;
|
|
rRect.height = rect->height;
|
|
XSetForeground(dpy, p->progress.gc, p->core.background_pixel);
|
|
XFillRectangle(dpy, win, p->progress.gc, rRect.x, rRect.y,
|
|
rRect.width, rRect.height);
|
|
|
|
if (p->progress.completeValue)
|
|
percent = (int)(((long)p->progress.value * 100) /
|
|
(long)p->progress.completeValue);
|
|
else
|
|
percent = 0;
|
|
|
|
/* percent complete */
|
|
sprintf(c, "%d%c", percent, '%');
|
|
str = XmStringCreateSimple(c);
|
|
XmStringExtent(p->progress.fontList, str, &strWidth, &strHeight);
|
|
if (p->progress.showPercentage)
|
|
DrawString(p, str, rect->x + rect->width / 2 - (int)strWidth / 2,
|
|
rect->y + rect->height / 2 - (int)strHeight / 2, strWidth,
|
|
&lRect, &rRect);
|
|
XmStringFree(str);
|
|
|
|
/* Left Time */
|
|
currentTime = time(0);
|
|
timeSoFar = (int)(currentTime - p->progress.startTime);
|
|
if (p->progress.showTime && p->progress.value &&
|
|
p->progress.value != p->progress.completeValue && timeSoFar)
|
|
{
|
|
TimeStr(c, timeSoFar);
|
|
str = XmStringCreateSimple(c);
|
|
XmStringExtent(p->progress.fontList, str,
|
|
&strWidth, &strHeight);
|
|
DrawString(p, str, rect->x + 5, rect->y + rect->height / 2 -
|
|
(int)strHeight / 2, strWidth, &lRect, &rRect);
|
|
XmStringFree(str);
|
|
}
|
|
|
|
/* Right Time */
|
|
timeLeft = 0;
|
|
if (percent)
|
|
timeLeft = (timeSoFar * 100 / percent) - timeSoFar;
|
|
if (p->progress.showTime && percent && percent != 100 && timeLeft)
|
|
{
|
|
TimeStr(c, timeLeft);
|
|
str = XmStringCreateSimple(c);
|
|
XmStringExtent(p->progress.fontList, str,
|
|
&strWidth, &strHeight);
|
|
DrawString(p, str, rect->x + rect->width - strWidth - 5,
|
|
rect->y + rect->height / 2 - (int)strHeight / 2,
|
|
strWidth, &lRect, &rRect);
|
|
XmStringFree(str);
|
|
}
|
|
}
|
|
|
|
static void
|
|
DrawString(XmLProgressWidget p,
|
|
XmString str,
|
|
int x,
|
|
int y,
|
|
int strWidth,
|
|
XRectangle *lRect,
|
|
XRectangle *rRect)
|
|
{
|
|
Display *dpy;
|
|
Window win;
|
|
|
|
dpy = XtDisplay(p);
|
|
win = XtWindow(p);
|
|
if (lRect->width && lRect->height)
|
|
{
|
|
XSetForeground(dpy, p->progress.gc, p->core.background_pixel);
|
|
XSetClipRectangles(dpy, p->progress.gc, 0, 0, lRect, 1, Unsorted);
|
|
XmStringDraw(dpy, win, p->progress.fontList, str,
|
|
p->progress.gc, x, y, strWidth, XmALIGNMENT_BEGINNING,
|
|
XmSTRING_DIRECTION_L_TO_R, 0);
|
|
XSetClipMask(dpy, p->progress.gc, None);
|
|
}
|
|
if (rRect->width && rRect->height)
|
|
{
|
|
XSetForeground(dpy, p->progress.gc, p->primitive.foreground);
|
|
XSetClipRectangles(dpy, p->progress.gc, 0, 0, rRect, 1, Unsorted);
|
|
XmStringDraw(dpy, win, p->progress.fontList, str,
|
|
p->progress.gc, x, y, strWidth, XmALIGNMENT_BEGINNING,
|
|
XmSTRING_DIRECTION_L_TO_R, 0);
|
|
XSetClipMask(dpy, p->progress.gc, None);
|
|
}
|
|
}
|
|
|
|
static void
|
|
TimeStr(char *c,
|
|
int seconds)
|
|
{
|
|
int h, m, s;
|
|
|
|
s = seconds;
|
|
m = s / 60;
|
|
s -= m * 60;
|
|
h = m / 60;
|
|
m -= h * 60;
|
|
if (h > 99)
|
|
h = 99;
|
|
if (h > 0 && m < 10)
|
|
sprintf(c, "%d:0%d hr", h, m);
|
|
else if (h > 0)
|
|
sprintf(c, "%d:%d hr", h, m);
|
|
else if (m > 0 && s < 10)
|
|
sprintf(c, "%d:0%d min", m, s);
|
|
else if (m > 0)
|
|
sprintf(c, "%d:%d min", m, s);
|
|
else
|
|
sprintf(c, "%d sec", s);
|
|
}
|
|
|
|
static Boolean
|
|
SetValues(Widget curW,
|
|
Widget reqW,
|
|
Widget newW,
|
|
ArgList args,
|
|
Cardinal *narg)
|
|
{
|
|
XmLProgressWidget cur, p;
|
|
XtAppContext app;
|
|
|
|
cur = (XmLProgressWidget)curW;
|
|
p = (XmLProgressWidget)newW;
|
|
app = XtWidgetToApplicationContext(curW);
|
|
if (p->progress.value == 0)
|
|
p->progress.startTime = time(0);
|
|
if (p->progress.completeValue < 1)
|
|
{
|
|
XmLWarning(newW, "SetValues() - complete value can't be < 1");
|
|
p->progress.completeValue = 1;
|
|
}
|
|
if (p->progress.numBoxes < 1)
|
|
{
|
|
XmLWarning(newW, "SetValues() - number of boxes can't be < 1");
|
|
p->progress.numBoxes = 1;
|
|
}
|
|
if (p->progress.value < 0)
|
|
{
|
|
XmLWarning(newW, "SetValues() - value can't be < 0");
|
|
p->progress.value = 0;
|
|
}
|
|
if (p->progress.value > p->progress.completeValue)
|
|
{
|
|
XmLWarning(newW, "SetValues() - value can't be > completeValue");
|
|
p->progress.value = p->progress.completeValue;
|
|
}
|
|
if (p->progress.fontList != cur->progress.fontList)
|
|
{
|
|
XmFontListFree(cur->progress.fontList);
|
|
CopyFontList(p);
|
|
}
|
|
/* display changes immediately since we may be not get back
|
|
to XNextEvent if the calling application is computing */
|
|
if (p->core.background_pixel != cur->core.background_pixel ||
|
|
p->primitive.foreground != cur->primitive.foreground ||
|
|
p->progress.value != cur->progress.value ||
|
|
p->progress.completeValue != cur->progress.completeValue ||
|
|
p->progress.fontList != cur->progress.fontList ||
|
|
p->progress.showTime != cur->progress.showTime ||
|
|
p->progress.showPercentage != cur->progress.showPercentage ||
|
|
p->progress.meterStyle != cur->progress.meterStyle ||
|
|
p->progress.numBoxes != cur->progress.numBoxes ||
|
|
p->primitive.shadow_thickness != cur->primitive.shadow_thickness)
|
|
{
|
|
Redisplay(newW, 0, 0);
|
|
XFlush(XtDisplay(newW));
|
|
XmUpdateDisplay(newW);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
CopyFontList(XmLProgressWidget p)
|
|
{
|
|
if (!p->progress.fontList)
|
|
p->progress.fontList = XmLFontListCopyDefault((Widget)p);
|
|
else
|
|
p->progress.fontList = XmFontListCopy(p->progress.fontList);
|
|
if (!p->progress.fontList)
|
|
XmLWarning((Widget)p, "- fatal error - font list NULL");
|
|
}
|
|
|
|
static Boolean
|
|
CvtStringToMeterStyle(Display *dpy,
|
|
XrmValuePtr args,
|
|
Cardinal *narg,
|
|
XrmValuePtr fromVal,
|
|
XrmValuePtr toVal,
|
|
XtPointer *data)
|
|
{
|
|
static XmLStringToUCharMap map[] =
|
|
{
|
|
{ "METER_BAR", XmMETER_BAR },
|
|
{ "METER_BOXES", XmMETER_BOXES },
|
|
{ 0, 0 },
|
|
};
|
|
|
|
return XmLCvtStringToUChar(dpy, "XmRMeterStyle", map, fromVal, toVal);
|
|
}
|
|
|
|
/*
|
|
Public Functions
|
|
*/
|
|
|
|
Widget
|
|
XmLCreateProgress(Widget parent,
|
|
char *name,
|
|
ArgList arglist,
|
|
Cardinal argcount)
|
|
{
|
|
return XtCreateWidget(name, xmlProgressWidgetClass, parent,
|
|
arglist, argcount);
|
|
}
|
|
|
|
|