Milán Major

netscape-revival

1 branch
Code

cmd/xfe/Microline/XmL/Progress.c

/*
(c) Copyright 1994, 1995, Microline Software, Inc.  ALL RIGHTS RESERVED
  
THIS PROGRAM BELONGS TO MICROLINE SOFTWARE.  IT IS CONSIDERED A TRADE
SECRET AND IS NOT TO BE DIVULGED OR USED BY PARTIES WHO HAVE NOT
RECEIVED WRITTEN AUTHORIZATION FROM THE OWNER.

THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE COPIED AND USED 
ONLY IN ACCORDANCE WITH THE TERMS OF THAT LICENSE AND WITH THE INCLUSION
OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE AND DOCUMENTATION, AND ITS 
COPYRIGHTS ARE OWNED BY MICROLINE SOFTWARE AND ARE PROTECTED BY UNITED
STATES COPYRIGHT LAWS AND INTERNATIONAL TREATY PROVISIONS.
 
THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY MICROLINE SOFTWARE.

THIS SOFTWARE AND REFERENCE MATERIALS ARE PROVIDED "AS IS" WITHOUT
WARRANTY AS TO THEIR PERFORMANCE, MERCHANTABILITY, FITNESS FOR ANY 
PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT.  MICROLINE SOFTWARE
ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE THIS 
SOFTWARE.

MICROLINE SOFTWARE SHALL NOT BE LIABLE FOR INDIRECT, SPECIAL OR
CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OF THIS PRODUCT. SOME 
STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATIONS MIGHT NOT APPLY TO
YOU.

MICROLINE SOFTWARE SHALL HAVE NO LIABILITY OR RESPONSIBILITY FOR SOFTWARE
ALTERED, MODIFIED, OR CONVERTED BY YOU OR A THIRD PARTY, DAMAGES
RESULTING FROM ACCIDENT, ABUSE OR MISAPPLICATION, OR FOR PROBLEMS DUE
TO THE MALFUNCTION OF YOUR EQUIPMENT OR SOFTWARE NOT SUPPLIED BY
MICROLINE SOFTWARE.
  
U.S. GOVERNMENT RESTRICTED RIGHTS
This Software and documentation are provided with RESTRICTED RIGHTS.
Use, duplication or disclosure by the Government is subject to
restrictions as set forth in subparagraph (c)(1) of the Rights in
Technical Data and Computer Software Clause at DFARS 252.227-7013 or
subparagraphs (c)(1)(ii) and (2) of Commercial Computer Software -
Restricted Rights at 48 CFR 52.227-19, as applicable, supplier is
Microline Software, 41 Sutter St Suite 1374, San Francisco, CA 94104.
*/

#include "ProgressP.h"
#include <stdio.h>
#include <sys/time.h>

#if defined(_STDC_) || defined(__cplusplus) || defined(c_plusplus)

static void ClassInitialize();
static void Initialize(Widget , Widget);
static void Resize(Widget);
static void Destroy(Widget);
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);

#else

static void ClassInitialize();
static void Initialize();
static void Resize();
static void Destroy();
static void Redisplay();
static Boolean SetValues();
static void CopyFontList();
static void DrawBarMeter();
static void DrawBoxesMeter();
static void TimeStr();
static void DrawString();
static Boolean CvtStringToMeterStyle();

#endif

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 */
	XtInheritRealize,                           /* 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()
	{
	XtSetTypeConverter(XmRString, XmRMeterStyle, CvtStringToMeterStyle,
		0, 0, XtCacheNone, 0);
	}

static void Initialize(reqW, newW, args, narg)
Widget reqW, newW;
ArgList args;
Cardinal *narg;
	{
	XmLProgressWidget p;
	XGCValues values;
	Display *dpy;
	Window root;

	p = (XmLProgressWidget)newW;
	dpy = XtDisplay(newW);

	if (!p->core.width)
		p->core.width = 200;
	if (!p->core.height)
		p->core.height = 30;

	root = RootWindowOfScreen(XtScreen(newW));
	p->progress.fallbackFont = XLoadQueryFont(dpy, "fixed");
	values.font = p->progress.fallbackFont->fid;
	p->progress.gc = XCreateGC(dpy, root, GCFont, &values);
	p->progress.startTime = time(0);
	CopyFontList(p);
	XtVaSetValues(newW, XmNtraversalOn, False, NULL);
	}

static void Resize(w)
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(w)
Widget w;
	{
	Display *dpy;
	XmLProgressWidget p;

	p = (XmLProgressWidget)w;
	dpy = XtDisplay(w);
	XFreeGC(dpy, p->progress.gc);
	XmFontListFree(p->progress.fontList);
	XFreeFont(dpy, p->progress.fallbackFont);
	}

static void Redisplay(w, event, region)
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(p, rect)
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(p, rect)
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 = XmStringCreate(c, XmSTRING_DEFAULT_CHARSET);
	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 = XmStringCreate(c, XmSTRING_DEFAULT_CHARSET);
		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 = XmStringCreate(c, XmSTRING_DEFAULT_CHARSET);
		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(p, str, x, y, strWidth, lRect, rRect)
XmLProgressWidget p;
XmString str;
int x, y, strWidth;
XRectangle *lRect, *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(c, seconds)
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(curW, reqW, newW, args, narg)
Widget curW, reqW, 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 cannot be < 1");
		p->progress.completeValue = 1;
		}
	if (p->progress.numBoxes < 1)
		{
		XmLWarning(newW, "SetValues() - number of boxes cannot be < 1");
		p->progress.numBoxes = 1;
		}
	if (p->progress.value < 0)
		{
		XmLWarning(newW, "SetValues() - value cannot be < 0");
		p->progress.value = 0;
		}
	if (p->progress.value > p->progress.completeValue)
		{
		XmLWarning(newW, "SetValues() - value cannot 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(p)
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(dpy, args, narg, fromVal, toVal, data)
Display *dpy;
XrmValuePtr args;
Cardinal *narg;
XrmValuePtr fromVal, toVal;
XtPointer *data;
	{
	char *from;
	int i, num, valid;
	static struct styleStruct
		{ char *name; unsigned char val; } styles[] =
		{
		{ "METER_BAR", XmMETER_BAR },
		{ "METER_BOXES", XmMETER_BOXES },
		};

	valid = 0;
	from = (char *)fromVal->addr;
	num = sizeof(styles) / sizeof(struct styleStruct);
	for (i = 0; i < num; i++)
		if (!strcmp(from, styles[i].name))
			{
			valid = 1;
			break;
			}
	if (!valid)
		{
		XtDisplayStringConversionWarning(dpy, from, "XmRMeterStyle");
		toVal->size = 0;
		toVal->addr = 0;
		return False;
		}
	toVal->size = sizeof(unsigned char);
	toVal->addr = (caddr_t)&styles[i].val;
	return True;
	}

/*
   Public Functions
*/

Widget XmLCreateProgress(parent, name, arglist, argcount)
Widget parent;
char *name;
ArgList arglist;
Cardinal argcount;
	{
	return XtCreateWidget(name, xmlProgressWidgetClass, parent,
		arglist, argcount);
	}