Logo Search packages:      
Sourcecode: nedit version File versions  Download package

Progress.c

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla 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/MPL/
 *
 * 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 the Microline Widget Library, originally made available under the NPL by Neuron Data <http://www.neurondata.com>.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * In addition, as a special exception to the GNU GPL, the copyright holders
 * give permission to link the code of this program with the Motif and Open
 * Motif libraries (or with modified versions of these that use the same
 * license), and distribute linked combinations including the two. You
 * must obey the GNU General Public License in all respects for all of
 * the code used other than linking with Motif/Open Motif. If you modify
 * this file, you may extend this exception to your version of the file,
 * but you are not obligated to do so. If you do not wish to do so,
 * delete this exception statement from your version.
 *
 * ***** END LICENSE BLOCK ***** */

#include "ProgressP.h"
#include <stdio.h>
#include <sys/time.h>
#include <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);
      }



Generated by  Doxygen 1.6.0   Back to index