static char *SccsId = "@(#)draw.c 4.24 (TU-Delft) 06/21/93";
/**********************************************************

Name/Version      : simeye/4.24

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Author(s)         : A.J. van Genderen
Creation date     : 29-May-1990
Modified by       : 
Modification date : 


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1990 , All rights reserved
**********************************************************/
#include <stdio.h>
#include <Intrinsic.h>
#define  XAW_BC  1        /* for sun */
#include <StringDefs.h>
#include <Command.h>
#include <Dialog.h>
#include <Text.h>
#include <AsciiText.h>

#include "define.h"
#include "type.h"
#include "extern.h"

extern Widget total;
extern Widget commands;
extern Widget canvas;
extern Widget resw;
extern Widget pltw;

extern int rdHandler;

extern struct signal *storedSig;
extern long storedT1;
extern long storedT2;
extern struct sig_value *storedVals;

extern int *SV;


#define MINPIXTIMESTEP  50
#define MINPIXGRID       5
#define MINPIXVOLTSTEP  15
#define MINPIXVOLTSPACE 25 /* below this value, only min-max levels are drawn */
#define MINPIXLEVELSPACE 8 /* below this value, no levels are drawn at all */

#define MAXSHOWYVALS    50 /* maximum nr. of signals for which y val can 
							       be displayed */

Grid drawP_x;
Grid drawP_y;

static XGCValues values;
static GC gc = NULL;
static Display *display;
static Window window;

static Arg args[10];

int fontWidth = 6;    /* font 6x13 */
int fontHeight = 8;

double grid_time;
double grid_volt;
double t_outunit;
double v_outunit;

Grid canvasHeight;
Grid canvasWidth; 
Grid canvasTop;
Grid canvasBottom; 
Grid canvasLeft;
Grid canvasRight;
Grid canvasNames;
Grid canvasVolts;

Grid sigSpace;
Grid axisLength;
Grid axisStart;
Grid axisY;
Grid oY;
double t_unit;
int tprecision;      /* for pointer info */
char tprec_str[16];
int tSprecision;     /* for the y-axis */
char tSprec_str[16];
double v_unit;      /* double ! */
int vprecision;
char vprec_str[16];
int vSprecision;
char vSprec_str[16];

struct signal *Top_signal;
struct signal *Bottom_signal;
int Curr_nr_signals;

long startTime;
long stopTime;

int curr_umin;
int curr_umax;

struct sig_value *Comb_vals_U[MAXSHOWYVALS + 1];
struct sig_value *Comb_vals_L[MAXSHOWYVALS + 1];

long normalColor;
long logicColor;
long logicxColor;
long analogColor;
long canvasBgColor;

int showVoltScale;
int showYValues;
int showYValuesPos;
int showYValuesOn = 0;

char windowMesBuf[128];
char windowListFn[128];
Grid windowMesX;

int stringValuesPresent;

void drawStartup ()
{
    int n;
    XrmDatabase db;
    XrmValue rmval;
    char str_type[128];
    XColor screenColor;
    XColor exactColor;

    window = XtWindow (canvas);
    display = XtDisplay (canvas);

    gc = XCreateGC (display, window, 0, &values);

    db = XtDatabase (display);

    if (XrmGetResource (db, "simeye.total.canvas.foreground", 
                            "Simeye.Form.Widget.Foreground",
  		    str_type, &rmval)) {
        XAllocNamedColor (display, 
  		  DefaultColormapOfScreen (DefaultScreenOfDisplay (display)),
  		  rmval.addr,
  		  &screenColor, &exactColor);
        normalColor = screenColor.pixel;
    }
    else {
#ifdef XtDefaultForeGround
        normalColor = XtDefaultForeGround;   /* for release 4 and higher */
#else
        normalColor = XBlackPixelOfScreen (XDefaultScreenOfDisplay (display));
#endif
    }

    if (XrmGetResource (db, "simeye.high_lowColor", "Simeye.Foreground", 
		        str_type, &rmval)) {
	XAllocNamedColor (display, 
		  DefaultColormapOfScreen (DefaultScreenOfDisplay (display)),
		  rmval.addr,
		  &screenColor, &exactColor);
	logicColor = screenColor.pixel;
    }
    else
	logicColor = normalColor;
		      
    if (XrmGetResource (db, "simeye.undefinedColor", "Simeye.Foreground", 
		        str_type, &rmval)) {
	XAllocNamedColor (display, 
		  DefaultColormapOfScreen (DefaultScreenOfDisplay (display)),
		  rmval.addr,
		  &screenColor, &exactColor);
	logicxColor = screenColor.pixel;
    }
    else
	logicxColor = logicColor;
		      
    if (XrmGetResource (db, "simeye.voltsColor", "Simeye.Foreground", 
		        str_type, &rmval)) {
	XAllocNamedColor (display, 
		  DefaultColormapOfScreen (DefaultScreenOfDisplay (display)),
		  rmval.addr,
		  &screenColor, &exactColor);
	analogColor = screenColor.pixel;
    }
    else 
	analogColor = normalColor;
		      
    XSetForeground (display, gc, normalColor);

    /* among other things for windowMessage: */

    n = 0;
    XtSetArg (args[n], XtNwidth, 0), n++;
    XtSetArg (args[n], XtNheight, 0), n++;
    XtSetArg (args[n], XtNbackground, 0), n++;
    XtGetValues (canvas, args, n);
    canvasWidth = args[0].value;
    canvasHeight = args[1].value;
    canvasTop = canvasHeight / 10;
    canvasBottom = canvasHeight / 8;
    canvasLeft = canvasWidth / 30;
    canvasRight = canvasWidth / 20;

    canvasBgColor = args[2].value;

    axisStart = 2 * canvasLeft;   /* for windowMessage */
    axisLength = canvasWidth - canvasRight - axisStart;

    windowMesBuf[0] = '\0';
    windowListFn[0] = '\0';
}

void draw (modif, x1, y1, x2, y2)
char modif;
Grid x1, y1, x2, y2;
{
    struct signal *sig;
    int inc_only;
    void ClickType ();
    int determWindow ();
    void clear ();
    void drawInit ();
    void drawSignal ();
    void windowMessage ();
    void windowList ();

    if (modif == 't')
	inc_only = 1;
    else
	inc_only = 0;

    if (rdHandler && windowListFn[0] != '\0') {
	windowList (windowListFn);   /* redraw window listing */
	rdHandler = 0;
	return;
    }
    else
	windowListFn[0] = '\0';

    if (Begin_signal == NULL) {
	windowMessage ("No signals loaded", -1);
	return;
    }

    if (Endtime <= 0) {
	if (editing) {
	    Endtime = 20;   /* just a useful value */
	    Begintime = 0;
	    startTime = Begintime; 
	    stopTime = Endtime;
	    SimEndtime = 0;
	}
	else {
	    windowMessage ("end of simulation time <= 0", -1);
	    return;
	}
    }
    else if (stopTime <= startTime) {
	/* This may occur if Endtime > 0 and first signal is created */
	startTime = Begintime; 
	stopTime = Endtime;
    }

#if 0
	if (currLogic && !Logic) {
	    ClickType (resw);  
	    /* this is a redraw after click has been modified */
	    /* and no successful read operation has been executed */
	}
	if (!currLogic && Logic) {
	    ClickType (pltw);        /* idem */
	}
#endif

    if (modif != 0) {
	if (modif != 'a' && modif != 'b' && modif != 't') {
	    if (determWindow (modif, x1, y1, x2, y2) == 0) {
		return;
	    }
	}

	if (modif == 'f' || modif == 'a' || modif == 'm'
	|| modif == 'l' || modif == 'r' || modif == 'd' || modif == 'u') {
	    clear ();
	}
    }

    if (!inc_only)
	drawInit ();

    sig = Top_signal; 
    while (sig != NULL && sig -> prev != Bottom_signal) {
	if (currLogic) {
	    drawSignal (sig, sig -> i, 0, 0, inc_only);
	    if (sig -> layover)
		drawSignal (sig -> layover, sig -> i, 0, 1, inc_only);
	}
	else {
	    drawSignal (sig, sig -> i, 'l', 0, inc_only);
	    if (sig -> layover)
		drawSignal (sig -> layover, sig -> i, 'l', 1, inc_only);
	    drawSignal (sig, sig -> i, 'u', 0, inc_only);
	    if (sig -> layover)
		drawSignal (sig -> layover, sig -> i, 'u', 1, inc_only);
	}
        sig = sig -> next;
    }

    if (rdHandler && windowMesBuf[0] != '\0')
	windowMessage (windowMesBuf, windowMesX);   /* redraw window message */
    else if (modif != 's' && modif != 't' && modif != 'b')
	windowMesBuf[0] = '\0';

    rdHandler = 0;

    XSync (display, False);
}

redrawListOrMessage ()
{
    if (windowListFn[0] != '\0') {
	windowList (windowListFn);   /* redraw window listing */
	return;
    }

    if (windowMesBuf[0] != '\0')
	windowMessage (windowMesBuf, windowMesX);   /* redraw window message */
}

int determWindow (modif, x1, y1, x2, y2)
char modif;
Grid x1, y1, x2, y2;
{
    int i;
    int new_nr_signals;
    long newStartTime;
    long newStopTime;
    double hFactor = 0.5;
    int new_umin;
    int new_umax;
    int d;

    if (modif == 'f' || modif == 's' || modif == 'm') {    
			    /* first draw ('f', 's') or full window ('m') */

        if (Top_signal == Begin_signal && Bottom_signal == End_signal
	&& startTime == Begintime && stopTime == Endtime && modif == 'm') {
	    return (0);
	}

	Top_signal = Begin_signal;
	Bottom_signal = End_signal;
	Curr_nr_signals = Nr_signals;

	startTime = Begintime;
	stopTime = Endtime;

	curr_umin = Global_umin;
	curr_umax = Global_umax;
    }
    else if (modif == 'i' || modif == 'I') {         /* zoom in */

	if (Curr_nr_signals > 1) {
	    new_nr_signals = Curr_nr_signals;

	    i = Curr_nr_signals * (Min (y1, y2) - canvasTop) 
		/ (canvasHeight - canvasTop - canvasBottom);
	    while (i > 0 && new_nr_signals > 1) {
		Top_signal = Top_signal -> next;
		new_nr_signals--;
		i--;
	    }

	    i = Curr_nr_signals * (canvasHeight - canvasBottom - Max (y1, y2))
		/ (canvasHeight - canvasTop - canvasBottom);
	    while (i > 0 && new_nr_signals > 1) {
		Bottom_signal = Bottom_signal -> prev;
		new_nr_signals--;
		i--;
	    }

	    Curr_nr_signals = new_nr_signals;
	}
	else if ((modif == 'I' || doDetailZoom) && !currLogic) {

            /* compute in double to prevent integer overflow */

	    new_umax = curr_umax 
			 - (double)(curr_umax - curr_umin) 
			     * (Min (y1, y2) - canvasTop - sigSpace / 8)
			     / (canvasHeight - canvasTop - canvasBottom 
							    - sigSpace / 4);

	    new_umin = curr_umin 
			 + (double)(curr_umax - curr_umin) 
			     * (canvasHeight - canvasBottom - Max (y1, y2) 
							       - sigSpace / 8)
			     / (canvasHeight - canvasTop - canvasBottom 
							       - sigSpace / 4);

	    if (new_umax < curr_umax)
		curr_umax = new_umax;
	    if (new_umin > curr_umin)
		curr_umin = new_umin;

	    if (curr_umin >= curr_umax)
		curr_umin = curr_umax - 1;
	}

	newStartTime = startTime +
		       (double)((Min (x1, x2) - axisStart) / (double)axisLength)
		       * (stopTime - startTime);

	newStopTime = startTime +
		      (double)((Max (x1, x2) - axisStart) / (double)axisLength)
		       * (stopTime - startTime);

	if (newStartTime >= startTime) 
	    startTime = newStartTime;

	if (newStopTime <= stopTime) 
	    stopTime = newStopTime;

	if (stopTime <= startTime) stopTime = startTime + 1;
    }
    else if (modif == 'o') {         /* zoom out */

	if (Curr_nr_signals == 1 && !currLogic
	    && (curr_umin > Global_umin || curr_umax < Global_umax)) {

            /* compute in double to prevent integer overflow */

            if (y1 == y2)
		d = 1;
	    else
		d = Max (y1, y2) - Min (y1, y2);

	    new_umax = curr_umax 
			 + (double)(curr_umax - curr_umin) 
			     * (Min (y1, y2) - canvasTop - sigSpace / 8)
			     / d;

	    new_umin = curr_umin 
			 - (double)(curr_umax - curr_umin) 
			     * (canvasHeight - canvasBottom - Max (y1, y2) 
							       - sigSpace / 8)
			     / d;

	    if (new_umax > curr_umax)
		curr_umax = new_umax;
	    if (new_umin < curr_umin)
		curr_umin = new_umin;

	    if (curr_umax > Global_umax)
		curr_umax = Global_umax;
	    if (curr_umin < Global_umin)
		curr_umin = Global_umin;
	}
	else {
	    curr_umin = Global_umin;
	    curr_umax = Global_umax;
	}

	if (!(Curr_nr_signals == 1 && !currLogic 
	    && (curr_umin > Global_umin || curr_umax < Global_umax))) {

	    new_nr_signals = Curr_nr_signals;

	    i = Curr_nr_signals * (Min (y1, y2) - canvasTop)
		/ (Max (y1, y2) - Min (y1, y2));
	    while (i > 0 && Top_signal != Begin_signal) {
		Top_signal = Top_signal -> prev;
		new_nr_signals++;
		i--;
	    }

	    i = Curr_nr_signals * (canvasHeight - canvasBottom - Max (y1, y2))
		/ (Max (y1, y2) - Min (y1, y2));
	    while (i > 0 && Bottom_signal != End_signal) {
		Bottom_signal = Bottom_signal -> next;
		new_nr_signals++;
		i--;
	    }

	    Curr_nr_signals = new_nr_signals;
	}

	if (x1 == x2)
	    d = 1;
	else
	    d = Max(x1, x2) - Min(x1, x2);

	newStartTime = stopTime -
		       (double)((Max (x1, x2) - axisStart) / (double)d)
		       * (stopTime - startTime);

	newStopTime = startTime +
		      (double)((axisStart + axisLength - Min (x1, x2)) 
			       / (double)d)
		       * (stopTime - startTime);

	if (newStartTime < Begintime) 
	    startTime = Begintime;
	else if (newStartTime < startTime)
	    startTime = newStartTime;

	if (newStopTime > Endtime && ! editing)   /* <== Notice !! */
	    stopTime = Endtime;
	else if (newStopTime > stopTime)
	    stopTime = newStopTime;

	if (stopTime <= startTime) stopTime = startTime + 1;
    }
    else if (modif == 'l') {      /* move left */

        if (startTime == Begintime)
	    return (0);

	newStartTime = startTime - hFactor * (stopTime - startTime);

	if (newStartTime < Begintime) 
	    newStartTime = Begintime;

	newStopTime = newStartTime + (stopTime - startTime);

        startTime = newStartTime;
        stopTime = newStopTime;
    }
    else if (modif == 'r') {      /* move right */

        if (stopTime == Endtime)
	    return (0);

	newStopTime = stopTime + hFactor * (stopTime - startTime);

	if (newStopTime > Endtime) 
	    newStopTime = Endtime;

	newStartTime = newStopTime - (stopTime - startTime);

        startTime = newStartTime;
        stopTime = newStopTime;
    }
    else if (modif == 'd') {      /* move down */

        if (Bottom_signal == End_signal)
	    return (0);

	i = Curr_nr_signals - 1;
	if (i < 1) i = 1;
	while (i > 0 && Bottom_signal != End_signal) {
	    Top_signal = Top_signal -> next;
	    Bottom_signal = Bottom_signal -> next;
	    i--;
	}
    }
    else if (modif == 'u') {      /* move up */

        if (Top_signal == Begin_signal)
	    return (0);

	i = Curr_nr_signals - 1;
	if (i < 1) i = 1;
	while (i > 0 && Top_signal != Begin_signal) {
	    Top_signal = Top_signal -> prev;
	    Bottom_signal = Bottom_signal -> prev;
	    i--;
	}
    }

    return (1);
}

void drawInit ()
{
    int n;
    int tdivider;
    char t_str[20];
    char t_str2[20];
    char v_str[20];
    char buf[32];
    double convdec ();
    Grid yb;
    int i;
    int len, maxlen;
    double help;
    int div2_5;
    struct signal *sig;
    void drawDottedLine ();
    void drawYScale ();


    n = 0;
    XtSetArg (args[n], XtNwidth, 0), n++;
    XtSetArg (args[n], XtNheight, 0), n++;
    XtGetValues (canvas, args, n);
    canvasWidth = args[0].value;
    canvasHeight = args[1].value;
    canvasTop = canvasHeight / 10;
    canvasBottom = canvasHeight / 8;
    canvasLeft = canvasWidth / 30;
    canvasRight = canvasWidth / 20;


    /* drawing of time axis */

    stringValuesPresent = 0;
    maxlen = 0;
    sig = Top_signal;
    for (i = 1; i <= Curr_nr_signals; i++) {
	len = strlen (sig -> name);
	if (len > maxlen)
	    maxlen = len;
	stringValuesPresent = stringValuesPresent || sig -> stringValue;
	sig = sig -> next;
    }
    if (maxlen < 5) maxlen = 5;

    canvasNames = (maxlen + 1) * fontWidth;

    sigSpace = (canvasHeight - canvasTop - canvasBottom) 
	       / (double)Curr_nr_signals;

    if (!currLogic
	&& sigSpace * 0.75 >= MINPIXVOLTSPACE
	&& sigSpace * 0.75 >= MINPIXLEVELSPACE)
	showVoltScale = 1;
    else
        showVoltScale = 0;

    if ((currLogic || (!currLogic && showVoltScale))
        && sigSpace * 0.75 >= MINPIXLEVELSPACE
        && Curr_nr_signals <= MAXSHOWYVALS) {
        showYValuesPos = 1;
    }
    else {
        showYValuesPos = 0;
    }

    if ((!currLogic && showVoltScale)
        || (currLogic && stringValuesPresent && showYValuesPos)) {
	canvasVolts = 5 * fontWidth;   /* just a guess of what is required */
    }
    else {
	canvasVolts = 2 * fontWidth;
    }

    axisY = canvasHeight - (3 * canvasBottom) / 4;

    axisStart = canvasLeft + canvasNames;
    axisLength = canvasWidth - canvasLeft - canvasNames 
			     - canvasRight - canvasVolts;

    grid_time = (double) (axisLength) / (double) (stopTime - startTime);

    XDrawLine (display, window, gc, axisStart, axisY,
				    axisStart + axisLength, axisY);

    t_unit = convdec ((double)(stopTime - startTime) * Timescaling);
    if (t_unit * grid_time / Timescaling < MINPIXTIMESTEP) 
	t_unit = t_unit * 10;

    while (t_unit * grid_time / Timescaling >= MINPIXTIMESTEP * 10) {
	t_unit = t_unit / 10;
    }

    if (t_unit / Timescaling >= 10) {
	if (t_unit * grid_time / Timescaling >= MINPIXTIMESTEP * 5) {
	    t_unit = t_unit / 5;
	    if (t_unit / Timescaling >= 10)
		tdivider = 4;
	    else
		tdivider = 2;
	}
	else if (t_unit * grid_time / Timescaling >= MINPIXTIMESTEP * 2) {
	    t_unit = t_unit / 2;
	    tdivider = 5;
	}
	else {
	    tdivider = 5;
	}
    }
    else {
	if (t_unit / Timescaling < 1)
	    t_unit = Timescaling;
	tdivider = 1;
    }

    t_outunit = convdec ((stopTime) * Timescaling);

    /* (Timescaling / grid_time) == Seconds per pixel */

    tprecision = 0;
    help = t_outunit / (Timescaling / grid_time);
    while (help > 1) {
	help = help / 10;
	tprecision++;
    }
    sprintf (tprec_str, "%%.%dlf", tprecision);

    tSprecision = 0;
    help = t_outunit / t_unit;
    while (help > 1) {
	help = help / 10;
	tSprecision++;
    }
    sprintf (tSprec_str, "%%.%dlf", tSprecision);

    sprintf (t_str, "%.0le", t_outunit);
    i = 0;
    while (t_str[i] != '\0') {     /* remove mantisse */
        t_str[i] = t_str[i + 1];
	i++;
    }
    XDrawString (display, window, gc, 
	    canvasLeft,
	    Min (canvasHeight - (2 * canvasBottom) / 9,
		 axisY + canvasBottom / 6 + 5 * fontHeight / 2),
	    t_str, strlen (t_str));

    i = startTime * Timescaling / t_unit;
    if (i * t_unit < startTime * Timescaling) i++;
    while (i * t_unit < stopTime * Timescaling + Timescaling / grid_time) { 

	drawDottedLine (display, window, gc, 
	       (Grid)(axisStart + (i * t_unit / Timescaling - startTime) 
				  * grid_time), 
		axisY,
	       (Grid)(axisStart + (i * t_unit / Timescaling - startTime) 
				  * grid_time), 
		canvasTop);

	XDrawLine (display, window, gc, 
	       (Grid)(axisStart + (i * t_unit / Timescaling - startTime) 
				  * grid_time), 
		axisY,
	       (Grid)(axisStart + (i * t_unit / Timescaling - startTime)
				  * grid_time), 
		axisY + canvasBottom / 6);
	sprintf (t_str2, tSprec_str, i * t_unit / t_outunit);
	XDrawString (display, window, gc, 
	       (Grid)(axisStart + (i * t_unit / Timescaling - startTime) 
				  * grid_time), 
		Min (canvasHeight - (2 * canvasBottom) / 9,
		     axisY + canvasBottom / 6 + 5 * fontHeight / 2),
	       t_str2, strlen (t_str2));
	i++;
    }

    i = startTime * tdivider * Timescaling / t_unit;
    if (i * t_unit / tdivider < startTime * Timescaling) i++;
    while (i * t_unit / tdivider 
	   < stopTime * Timescaling + Timescaling / grid_time) { 

	XDrawLine (display, window, gc, 
         (Grid)(axisStart + (i * t_unit / (Timescaling * tdivider) - startTime)
			      * grid_time), 
		  axisY,
         (Grid)(axisStart + (i * t_unit / (Timescaling * tdivider) - startTime) 
			      * grid_time), 
		  axisY + canvasBottom / 9);
	i++;
    }

    if (grid_time >= MINPIXGRID) {    /* display smallest grid */

	i = 0;
	while (i * grid_time <= axisLength) {

	    XDrawLine (display, window, gc, 
	     (Grid)(axisStart + i * grid_time), axisY,
	     (Grid)(axisStart + i * grid_time), axisY - canvasBottom / 9);
	    i++;
	}
    }

    /* For some reason (?) the first draw statement for the canvas
    /* has no effect when the signals are drawn immediately after 
    /* startup (by specifying the inputfile on the command line).
    /* Therefore, the first draw statement is repeated here:
    */

    XDrawLine (display, window, gc, axisStart, axisY,
				    axisStart + axisLength, axisY);

    XDrawString (display, window, gc, 
	    canvasLeft,
	    Min (canvasHeight - (2 * canvasBottom) / 9,
		 axisY + canvasBottom / 6 + 5 * fontHeight / 2),
	    t_str, strlen (t_str));


    /* drawing of names and voltage levels */


    grid_volt = (double) sigSpace * 0.75 / (curr_umax - curr_umin);

    oY = (curr_umin - 0) * grid_volt;   
    /* this value has to be added to the y value of a signal
       to fit within the space that is reserved for the signal */

    if (showVoltScale) {

        /* v_unit and v are in Volts ! */

	v_unit = convdec ((double)(curr_umax - curr_umin) * Voltscaling);
	if (v_unit * grid_volt / Voltscaling < MINPIXVOLTSTEP) 
	    v_unit = v_unit * 10;

	while (v_unit * grid_volt / Voltscaling >= MINPIXVOLTSTEP * 10) {
	    v_unit = v_unit / 10;
	}

        div2_5 = 0;
	if (v_unit * grid_volt / Voltscaling >= MINPIXVOLTSTEP * 4) {
	    v_unit = v_unit / 4;
	    div2_5 = 1;
	}
	else if (v_unit * grid_volt / Voltscaling >= MINPIXVOLTSTEP * 5) {
	    v_unit = v_unit / 5;

	    /* Since maximum voltage is usually 5V we prefer division by 4
	       above division by 5 */
	}
	else if (v_unit * grid_volt / Voltscaling >= MINPIXVOLTSTEP * 2) {
	    v_unit = v_unit / 2;
	}

	v_outunit = convdec ((Max (Abs (curr_umin), Abs (curr_umax))) 
			     * Voltscaling);

        /* (Voltscaling / grid_volt) == Volts per pixel */

	vprecision = 0;
	help = v_outunit / (Voltscaling / grid_volt);
	while (help > 1) {
	    help = help / 10;
	    vprecision++;
	}
	if (Spice)
	    vprecision = vprecision + 2;
	sprintf (vprec_str, "%%.%dlf", vprecision);

	vSprecision = 0;
	help = v_outunit / v_unit;
	while (help > 1) {
	    help = help / 10;
	    vSprecision++;
	}
	if (div2_5) vSprecision++;  /* ! */
	sprintf (vSprec_str, "%%.%dlf", vSprecision);

	sprintf (v_str, "%.0le", v_outunit);
	i = 0;
	while (v_str[i] != '\0') {     /* remove mantisse */
	    v_str[i] = v_str[i + 1];
	    i++;

	}
	XDrawString (display, window, gc, 
		axisStart + axisLength + fontWidth * 3 / 2, 
		(canvasTop + fontHeight)/ 2,
	        v_str, strlen (v_str));
    }

    if (showYValuesPos && showYValues)
	showYValues = 1;
    else
	showYValues = 0;

    sig = Top_signal;
    for (i = 1; i <= Curr_nr_signals; i++) {

        sig -> i = i;

	yb = canvasTop 
	     + (canvasHeight - canvasTop - canvasBottom) * i / Curr_nr_signals 
	     - (sigSpace / 8);
	
	if ((curr_umax - curr_umin) * grid_volt < MINPIXLEVELSPACE) {

	    /* do not draw levels */

	}
	else if (showVoltScale) {

            drawYScale (yb, 1);
	}
	else {

            /* draw only the minimum and maximum level for each signal */

	    drawDottedLine (display, window, gc, 
		   axisStart, (Grid)(yb + oY - grid_volt * curr_umin),
	           axisStart + axisLength, 
		   (Grid)(yb + oY - grid_volt * curr_umin));

	    drawDottedLine (display, window, gc, 
		   axisStart, (Grid)(yb + oY - grid_volt * curr_umax),
		   axisStart + axisLength, 
		   (Grid)(yb + oY - grid_volt * curr_umax));
	}

	XDrawString (display, window, gc, canvasLeft, yb, 
		     sig -> name, strlen (sig -> name));

        if (sig -> layover)
	    XDrawString (display, window, gc, 
			 canvasLeft, yb - 3 * fontHeight / 2, 
			 sig -> layover -> name, 
			 strlen (sig -> layover -> name));

	if (Cmd && sig -> endless) {
	    XDrawString (display, window, gc, 
			 axisStart + axisLength + fontWidth, yb,
			 "~", strlen ("~"));
	}

	sig = sig -> next;
    }

    if (Cmd) {
	sprintf (buf, "input signals");

	for (i = 0; i < strlen (buf); i++) {
	    XDrawString (display, window, gc, 
			 canvasWidth - 1 * (canvasRight + canvasVolts) / 3,
			 canvasHeight * (3 + i + 1) / (strlen (buf) + 6)
			   - fontHeight,
			 &buf[i], 1);
	}
    }
}

void drawYScale (yb, drawDL)
Grid yb;
int drawDL;
{
    int first;
    Grid h;
    double v;
    void drawDottedLine ();
    char v_str[20];


    v = ((int)(curr_umin * Voltscaling / v_unit)) * v_unit;

    /* to obtain a multiple value of v_unit ! */

    if (v < curr_umin * Voltscaling)
	v = v + v_unit;

    first = 1;
    while (v <= curr_umax * Voltscaling 
		+ 0.001 * (curr_umax - curr_umin) * Voltscaling) {

	if (drawDL)
	    drawDottedLine (display, window, gc, 
		   axisStart, 
		   (Grid)(yb + oY - grid_volt * v / Voltscaling),
		   axisStart + axisLength, 
		   (Grid)(yb + oY - grid_volt * v / Voltscaling));

	if (0.25 * sigSpace > grid_volt * v_unit / Voltscaling) {
	    h = fontHeight / 2;   /* center text */
	}
	else if (first) {
	    h = 0;
	}
	else {
	    if ((curr_umax - v / Voltscaling) * grid_volt 
						     < fontHeight)
		h = fontHeight - (curr_umax - v / Voltscaling) 
				 * grid_volt;
	    else 
		h = fontHeight / 2;   /* center text */
	}
	first = 0;

	if (!showYValuesOn) {
	    sprintf (v_str, vSprec_str, v / v_outunit);
	    XDrawString (display, window, gc, 
		     axisStart + axisLength + fontWidth * 3 / 2, 
		     (Grid)(yb + oY - grid_volt * v / Voltscaling + h),
		     v_str, strlen (v_str));
	}

	v = v + v_unit;
    }
}

double  convdec (f)
double  f;
{
    int     i = 0;

    if (f == 0)
	return (f);

    if (f >= 1) {
	while (f > 10) {
	    f = f / 10;
	    i++;
	}
    }
    else {
	while (f < 1) {
	    f = f * 10;
	    i--;
	}
    }

    f = 1;
    if (i >= 0) {
	while (i > 0) {
	    f = f * 10;
	    i--;
	}
    }
    else {
	while (i < 0) {
	    f = f / 10;
	    i++;
	}
    }

    return (f);
}


void drawSignal (sig, index, type, flag, inc_only)
struct signal *sig;
int index;
char type;
int flag;
int inc_only;
{
    struct sig_value *sval;
    Grid xcurr;
    Grid xprev;
    Grid ycurr;
    Grid yprev;
    Grid yb;
    Grid xl;
    Grid xBBr, xBBl, yBBt, yBBb;
    XGCValues xgcval;
    void drawLineSignal ();

    if (flag) {
	drawLineSignal (0, 0, 0, 0, -1);  /* initialization for stipple line */
    }

    yb = canvasTop
       + (canvasHeight - canvasTop - canvasBottom) * index / Curr_nr_signals 
       - (sigSpace / 8);
    
    xl = canvasLeft + canvasNames;

    if (type == 'l')
	sval = sig -> begin_value_L;
    else if (type == 'u')
	sval = sig -> begin_value_U;
    else
	sval = sig -> begin_value;

    if (sval == NULL) { 
	if (type == 'l')
	    sig -> last_value_L = NULL;
	else if (type == 'u')
	    sig -> last_value_U = NULL;
	else
	    sig -> last_value = NULL;
	return;
    }

    if (!flag) {
	if (currLogic)
	    XSetForeground (display, gc, logicColor);
	else
	    XSetForeground (display, gc, analogColor);
    }

    if (inc_only) {
	if (type == 'l') {
	    if (sig -> last_value_L)
		sval = sig -> last_value_L;
	}
	else if (type == 'u') {
	    if (sig -> last_value_U)
		sval = sig -> last_value_U;
	}
	else {
	    if (sig -> last_value)
		sval = sig -> last_value;
	}
    }

    while (sval -> next && sval -> next -> time < startTime) {
	sval = sval -> next;
    }
    if (sval -> time < startTime && sval -> next -> time == startTime) {
	sval = sval -> next;
    }

    /* if inc_only = 0 or first time on canvas: 
       sval -> time <= startTime && sval -> next -> time >= startTime ! */

    if (sval -> time <= startTime && sval -> next
	&& sval -> next -> time >= startTime) {

	/* first time on canvas for this signal */

	if (type == 'l')
	    Comb_vals_L[index] = sval;
	else
	    Comb_vals_U[index] = sval;

	if (currLogic || sval -> next -> time == sval -> time)
	    yprev = yb + oY - grid_volt * sval -> value;
	else {
	    yprev = yb + oY 
		      - grid_volt 
			* (sval -> value +
			   (double) ((startTime - sval -> time) 
			   / (double)(sval -> next -> time - sval -> time))
		              * (sval -> next -> value - sval -> value));
	}
	xcurr = xl;
    }
    else {
	/* inc_only = 1 */
	yprev = yb + oY - grid_volt * sval -> value;
	xcurr = xl + (sval -> time - startTime) * grid_time;
    }
    sval = sval -> next;

    while (sval && sval -> time <= stopTime) {
	xprev = xcurr;
	xcurr = xl + (sval -> time - startTime) * grid_time;
	if (sig -> stringValue)
	    ycurr = sval -> value;
	else
	    ycurr = yb + oY - grid_volt * sval -> value;
	if (currLogic) {
	    if (sig -> stringValue) {
		XSetForeground (display, gc, logicColor);
		drawLineSignal (xprev, (Grid)(yb + oY), 
				xcurr, (Grid)(yb + oY), flag); 
		drawLineSignal (xprev, (Grid)(yb + oY - grid_volt * 2),
				xcurr, (Grid)(yb + oY - grid_volt * 2), flag);
		if (ycurr != yprev) {
		    drawLineSignal (xcurr, (Grid)(yb + oY), 
				xcurr, (Grid)(yb + oY - grid_volt * 2), flag);
		}
	    }
	    else if (sval -> prev -> value >= 0) {
		if (sval -> prev -> value == 1 && !flag)
		    XSetForeground (display, gc, logicxColor);
		drawLineSignal (xprev, yprev, xcurr, yprev, flag);
		XSetForeground (display, gc, logicColor);
		if (ycurr != yprev && sval -> value >= 0)
		    drawLineSignal (xcurr, yprev, xcurr, ycurr, flag);
	    }
            else {           /* Free state */
                xgcval.line_style = LineDoubleDash;
                XChangeGC (display, gc, GCLineStyle, &xgcval);
		drawLineSignal (xprev, (Grid)(yprev - 2 * grid_volt), 
                                xcurr, (Grid)(yprev - 2 * grid_volt), flag);
                xgcval.line_style = LineSolid;
                XChangeGC (display, gc, GCLineStyle, &xgcval);
            }
	}
	else {
	    drawLineSignal (xprev, yprev, xcurr, ycurr, flag);
	}
	yprev = ycurr;
	sval = sval -> next;
    }

    if (sval && sval -> prev && sval -> prev -> time < stopTime) {

	xprev = xcurr;
	xcurr = xl + (stopTime - startTime) * grid_time;
	if (currLogic) {
	    if (sig -> stringValue) {
		XSetForeground (display, gc, logicColor);
		drawLineSignal (xprev, (Grid)(yb + oY), 
				xcurr, (Grid)(yb + oY), flag); 
		drawLineSignal (xprev, (Grid)(yb + oY - grid_volt * 2),
				xcurr, (Grid)(yb + oY - grid_volt * 2), flag);
	    }
	    else if (sval -> prev -> value >= 0) {
		if (sval -> prev -> value == 1 && !flag)
		    XSetForeground (display, gc, logicxColor);
		drawLineSignal (xprev, yprev, xcurr, yprev, flag);
		if (!flag)
		    XSetForeground (display, gc, logicColor);
	    }
            else {           /* Free state */
                xgcval.line_style = LineDoubleDash;
                XChangeGC (display, gc, GCLineStyle, &xgcval);
		drawLineSignal (xprev, (Grid)(yprev - 2 * grid_volt), 
                                xcurr, (Grid)(yprev - 2 * grid_volt), flag);
                xgcval.line_style = LineSolid;
                XChangeGC (display, gc, GCLineStyle, &xgcval);
            }
	}
	else {
	    ycurr = yb + oY - grid_volt * (
	                sval -> prev -> value +
			(double)((stopTime - sval -> prev -> time) 
			 / (double)(sval -> time - sval -> prev -> time))
			* (sval -> value - sval -> prev -> value));
	    drawLineSignal (xprev, yprev, xcurr, ycurr, flag);
	}
    }

    XSetForeground (display, gc, normalColor);

    if (editing && storedSig == sig 
	&& ((storedT1 > startTime && storedT1 < stopTime)
	    || (storedT2 > startTime && storedT2 < stopTime)
	    || (storedT1 >= startTime && storedT2 <= stopTime))) {

	/* draw bounding box for stored (=yanked) signal part */

	yBBb = yb + oY - grid_volt * Global_umin + sigSpace * 0.1 + 1;
	yBBt = yb + oY - grid_volt * Global_umax - sigSpace * 0.1 - 1;
	xBBl = Max (xl + (storedT1 - startTime) * grid_time, xl) - 1;
	xBBr = Min (xl + (storedT2 - startTime) * grid_time, 
						    xl + axisLength) + 1;

	XDrawLine (display, window, gc, xBBl, yBBb, xBBr, yBBb);
	XDrawLine (display, window, gc, xBBl, yBBt, xBBr, yBBt);
	if (storedT1 >= startTime)
	    XDrawLine (display, window, gc, xBBl, yBBb, xBBl, yBBt);
	if (storedT2 <= stopTime)
	    XDrawLine (display, window, gc, xBBr, yBBb, xBBr, yBBt);

        if ((xBBr - 2 - Max (xl, xBBl + 2)) > fontWidth * 6 
	    && (yBBb - 2 - (yBBt + 2)) > fontHeight) 
	    XDrawString (display, window, gc, 
			 Max (xl, xBBl + 2), yBBb - 2, "buffer", 6);
    }

    if (type == 'l')
	sig -> last_value_L = sig -> end_value_L;
    else if (type == 'u')
	sig -> last_value_U = sig -> end_value_U;
    else
	sig -> last_value = sig -> end_value;
}

void drawLineSignal (x1, y1, x2, y2, flag)
Grid x1, y1, x2, y2;
int flag;
{
    static Grid xlatest;
    static Grid ylatest;
    Grid x, y;
    double ya, yb;
    double d1, d2, d3;
    Grid sep = 3;

    if (flag < 0) {
	xlatest = -100;
	ylatest = -100;
	return;
    }

    if (x2 < x1) {
	fprintf (stderr, "He x2 < x1\n");  
	die (1);                     /* algorithm does not handle x2 < x1 */
    }

    if (!currLogic) {
	/* perform clipping (in case of detail zoom in) */

	if (y1 < canvasTop + sigSpace / 8) {
	    if (y2 < canvasTop + sigSpace / 8) {
		return;
	    }
	    x1 = x1 + (x2 - x1) * (canvasTop + sigSpace / 8 - y1) / (y2 - y1);
	    y1 = canvasTop + sigSpace / 8;
	}
	else if (y1 > canvasHeight - canvasBottom - sigSpace / 8) {
	    if (y2 > canvasHeight - canvasBottom - sigSpace / 8) {
		return;
	    }
	    x1 = x1 + (x2 - x1) 
			 * (canvasHeight - canvasBottom - sigSpace / 8 - y1)
			 / (y2 - y1);
	    y1 = canvasHeight - canvasBottom - sigSpace / 8;
	}

	if (y2 < canvasTop + sigSpace / 8) {
	    x2 = x1 + (x2 - x1) * (canvasTop + sigSpace / 8 - y1) / (y2 - y1);
	    y2 = canvasTop + sigSpace / 8;
	}
	else if (y2 > canvasHeight - canvasBottom - sigSpace / 8) {
	    x2 = x1 + (x2 - x1) 
			 * (canvasHeight - canvasBottom - sigSpace / 8 - y1)
			 / (y2 - y1);
	    y2 = canvasHeight - canvasBottom - sigSpace / 8;
	}
    }

    if (flag > 0) {

	/* stipple by placing a dot at every position that is
	   'sep' away from a previous dot
	*/

	x = x1;
	y = y1;

        while (!(x == x2 && y == y2)) {

	    if ((x2 > x1 && x >= xlatest + sep)
		|| (x2 < x1 && x <= xlatest - sep)
		|| (y2 > y1 && y >= ylatest + sep)
		|| (y2 < y1 && y <= ylatest - sep)) {
		XDrawLine (display, window, gc, x, y, x, y);
		xlatest = x;
		ylatest = y;
	    }

            if (x2 > x1) {

		ya = (y2 - y1) * (x - x1) / (double)(x2 - x1) + y1;
		yb = (y2 - y1) * (x + 1 - x1) / (double)(x2 - x1) + y1;

		if (y2 > y1) {

                    d1 = Abs (y - ya);
                    d2 = Abs (y - yb);
                    d3 = Abs (y + 1 - yb);
                    if (d1 < d2 && d1 < d3) {
			y++;
		    }
		    else if (d2 < d3) {
			x++;
		    }
		    else {
			x++;
			y++;
		    }
		}
		else {

                    d1 = Abs (y - ya);
                    d2 = Abs (y - yb);
                    d3 = Abs (y - 1 - yb);
                    if (d1 < d2 && d1 < d3) {
			y--;
		    }
		    else if (d2 < d3) {
			x++;
		    }
		    else {
			x++;
			y--;
		    }
		}
	    }
	    else if (y2 > y1) {
		y++;
	    }
	    else {
		y--;
	    }
	}

	if (x1 != x2) {
	    while (x != x2) {

		y = (y2 - y1) * (x - x1) / (x2 - x1) + y1;

		if ((x2 > x1 && x >= xlatest + sep)
		    || (x2 < x1 && x <= xlatest - sep)
		    || (y2 > y1 && y >= ylatest + sep)
		    || (y2 < y1 && y <= ylatest - sep)) {
		    XDrawLine (display, window, gc, x, y, x, y);
		    xlatest = x;
		    ylatest = y;
		}
		
		if (x2 > x1)
		    x++;
		else
		    x--;
	    }
	}
	else {
	    while (y != y2) {

		x = (x2 - x1) * (y - y1) / (y2 - y1) + x1;

		if ((x2 > x1 && x >= xlatest + sep)
		    || (x2 < x1 && x <= xlatest - sep)
		    || (y2 > y1 && y >= ylatest + sep)
		    || (y2 < y1 && y <= ylatest - sep)) {
		    XDrawLine (display, window, gc, x, y, x, y);
		    xlatest = x;
		    ylatest = y;
		}
		
		if (y2 > y1)
		    y++;
		else
		    y--;
	    }
	}
    }
    else {
	XDrawLine (display, window, gc, x1, y1, x2, y2);
    }
}

void drawDottedLine (display, window, gc, x1, y1, x2, y2)
Display *display;
Window window;
GC gc;
Grid x1, y1, x2, y2;
{
    Grid x, y;
    Grid sep = 6;

    x = x1;
    y = y1;

    if (x1 != x2 && y1 != y2)
	fprintf (stderr, "Sorry only orthogonal dotted lines\n"), die (1);

    if (x1 == x2) {
	if (y2 > y1) {
	    y = y + sep;
	    while (y <= y2) {
		XDrawLine (display, window, gc, x, y, x, y);
		y = y + sep;
	    }
	}
	else {
	    y = y - sep;
	    while (y >= y2) {
		XDrawLine (display, window, gc, x, y, x, y);
		y = y - sep;
	    }
	}
    }
    else {
	if (x2 > x1) {
	    x = x + sep;
	    while (x <= x2) {
		XDrawLine (display, window, gc, x, y, x, y);
		x = x + sep;
	    }
	}
	else {
	    x = x - sep;
	    while (x >= x2) {
		XDrawLine (display, window, gc, x, y, x, y);
		x = x - sep;
	    }
	}
    }
}

int drawPointerInfo (initial, x, y, flag, showLogic, round, moving)
int initial;
Grid x;
Grid y;
int flag;
int showLogic;  /* if showLogic != 0 then show the corresponding logic state;
		/* if showLogic == -1 then display 'free state'  */
int round;      /* if not yet indicated by showLogic != 0 or !currLogic, 
		   turning on this variable indicates rounding */
int moving;
{
    char buf1[32];
    char buf2[32];
    char buf[80];
    char buf1a[32];
    char buf1b[32];
    char buf2a[32];
    char buf2b[32];
    char tmp[32];
    static int memory = 0;
    static double vmem;
    static double tmem;
    static char smem;
    double v;
    double t;
    int s;
    int l;
    void findXYValSig ();
    void findVoltSig ();
    long findTime ();
    int store;
    int dPI = 0;
    void windowMessage ();
    
    if (initial >= 0) {

	store = 0;
	if (flag) {
	    if (memory)
		memory = 0;
	    else {
		store = 1;
		memory = 1;
	    }
	}

	if (initial == 1)
	    sprintf (buf, "- - - - ");
	/*
	else if (y < canvasTop && !currLogic)
	    sprintf (buf, "\\/ \\/ \\/");
	else if (y > axisY && !currLogic)
	    sprintf (buf, "/\\ /\\ /\\");
	*/
	else if ((x - axisStart) / grid_time < 0)
	    sprintf (buf, " > > > >");
	else if (startTime + (x - axisStart) / grid_time > stopTime)
	    sprintf (buf, "< < < < ");
	else {

	    t = findTime (x, (!currLogic || showLogic != 0 || round != 0)) 
				     * Timescaling / t_outunit;

	    sprintf (buf1, tprec_str, t);

            if (store) {
		tmem = t;
	    }

	    if (memory) {
		sprintf (buf1a, tprec_str, tmem);
		sprintf (buf1b, tprec_str, t - tmem);
		if (t - tmem >= 0) {
		    sprintf (tmp, buf1b);
		    sprintf (buf1b, " %s", tmp);
		}
	    }

	    if (!showVoltScale) {

		if (currLogic && showYValuesPos) {
		    findXYValSig (x, y, 'u', &v, buf2);

		    if (memory)
			sprintf (buf, "x = %s  y =%s  ( -  %s  =  %s )", 
				 buf1, buf2, buf1a, buf1b);
		    else
			sprintf (buf, "x = %s  y =%s", buf1, buf2);
		}
		else {
		    if (memory)
			sprintf (buf, "x = %s  ( -  %s  =  %s )", 
				 buf1, buf1a, buf1b);
		    else
			sprintf (buf, "x = %s", buf1);
		}
	    }
	    else {

		findVoltSig (x, y, &v, buf2);

		if (store) {
		    vmem = v;
		}

                if (memory) {
		    sprintf (buf2a, vprec_str, vmem);
		    if (vmem >= 0) {
			sprintf (tmp, buf2a);
			sprintf (buf2a, " %s", tmp);
		    }
		    sprintf (buf2b, vprec_str, v - vmem);
		    if (v - vmem >= 0) {
			sprintf (tmp, buf2b);
			sprintf (buf2b, " %s", tmp);
		    }
		}

		if (memory) {
		    sprintf (buf, "x = %s  y = %s  ( -  %s  %s  =  %s  %s )", 
			     buf1, buf2, buf1a, buf2a, buf1b, buf2b);
		}
		else
		    sprintf (buf, "x = %s  y = %s", buf1, buf2);

		dPI = 1;   /* valid position to draw horizontal cursor edge */
	    }

            if (showLogic != 0) {

                if (!memory || store) {
		    if (showLogic == -1)
			s = -1;           /* free state is forced */
		    else
                        s = findState (y);
                    if (s == 2)
                        smem = 'I';
                    else if (s == 1)
                        smem = 'X';
                    else if (s == 0)
                        smem = 'O';
                    else if (s == -1)
                        smem = 'f';
                }

                l = strlen(buf);
                sprintf (&buf[l], "  %c", smem); 
            }
	}

	if (moving)
	    windowMessage (buf, x);
	else
	    windowMessage (buf, -1);
    }
    else {
	memory = 0;
        windowMessage (NULL, -1);
    }

    return (dPI);
}

void drawValueInfo (initial, x)
int initial; 
Grid x;
{
    int i;
    char pval[16];
    double v;
    long t;
    struct signal *sig;
    Grid yb;
    long findTime ();
    void findValSig ();
    void drawYScale ();

    if (initial == 1) {

	if (showVoltScale)
	    XClearArea (display, window, 
			axisStart + axisLength, canvasTop,
			canvasWidth - axisStart - axisLength, 
			canvasHeight - canvasBottom - canvasTop, 
			False);
		
	showYValuesOn = 1;

	return;
    }
    else if (initial == -1) {
	showYValuesOn = 0;
    }

    t = findTime (x, !currLogic);

    sig = Top_signal;
    for (i = 1; i <= Curr_nr_signals; i++) {

	yb = canvasTop
	     + (canvasHeight - canvasTop - canvasBottom) * i / Curr_nr_signals
	     - (sigSpace / 8);

        if (currLogic && !stringValuesPresent)
	    XClearArea (display, window, 
	      (Grid)(axisStart + axisLength + fontWidth - 1),
	      (Grid)(yb - sigSpace * 3 / 4 - 1),
	      (Grid)(2 * fontWidth + 2), 
	      (Grid)(sigSpace * 3 / 4 + 4), False);
	else
	    XClearArea (display, window, 
	      (Grid)(axisStart + axisLength + fontWidth * 1 / 4),
	      (Grid)(yb - sigSpace * 3 / 4 - 1),
	      (Grid)(canvasWidth - axisStart - axisLength - fontWidth * 1 / 4), 
	      (Grid)(sigSpace * 3 / 4 + 4), False);

	if (initial == -1) {
	    if (showVoltScale)
		drawYScale (yb, 0);
	}
	else {
	    if (currLogic || Spice) {
		findValSig (i, sig -> stringValue, t, 'u', &v, pval);

		XDrawString (display, window, gc,
			     axisStart + axisLength + fontWidth,
			     (Grid)(yb),
			     pval, strlen (pval));
	    }
	    else {
		findValSig (i, sig -> stringValue, t, 'l', &v, pval);

		XDrawString (display, window, gc,
			     axisStart + axisLength + fontWidth,
			     (Grid)(yb),
			     pval, strlen (pval));

		findValSig (i, sig -> stringValue, t, 'u', &v, pval);

		XDrawString (display, window, gc,
			     axisStart + axisLength + fontWidth,
			     (Grid)(yb - sigSpace * 3 / 4 + fontHeight),
			     pval, strlen (pval));
	    }
	}

	sig = sig -> next;
    }
}

void findXYValSig (x, y, type, fval, pval)
Grid x;
Grid y;
char type;
double *fval;
char *pval;
{
    long t;
    struct signal *sig;
    struct signal *findSignal ();

    t = findTime (x, !currLogic);

    sig = findSignal (y, 0);

    findValSig (sig -> i, sig -> stringValue, t, type, fval, pval);
}

void findValSig (i, stringValue, t, type, fval, pval)
int i;
int stringValue;
long t;
char type;
double *fval;
char *pval;
{
    register struct sig_value *sval;
    double v;
    char tmp[16];

    if (type == 'l')
	sval = Comb_vals_L[i];
    else
	sval = Comb_vals_U[i];

    while (sval -> next && sval -> time <= t) {
	sval = sval -> next;
    }
    /* sval -> time > t */
    while (sval -> prev && sval -> time > t) {
	sval = sval -> prev;
    }
    /* (sval -> time <= t && sval -> next -> time > t)
	|| (sval -> time <= t && sval -> next == NULL) 
	|| (sval -> time > t && sval -> prev == NULL) */

    if ((sval -> time > t && sval -> prev == NULL)
	|| (sval -> time < t && sval -> next == NULL)) {
	strcpy (pval, " U");
    }
    else {
	if (currLogic) {
	    if (stringValue)
		sprintf (pval, " %s", SV[sval -> value]);
	    else if (sval -> value == 2)
		strcpy (pval, " I");
	    else if (sval -> value == 1)
		strcpy (pval, " X");
	    else if (sval -> value == 0)
		strcpy (pval, " O");
	    else if (sval -> value == -1)
		strcpy (pval, " f");
	}
	else {
	    if (sval -> time < t) {
		v = (sval -> value
		      + ((t - sval -> time) 
			 / (double)(sval -> next -> time - sval -> time))
			* (sval -> next -> value - sval -> value))
		    * Voltscaling / v_outunit;
	    }
	    else
		v = sval -> value * Voltscaling / v_outunit;

	    sprintf (pval, vprec_str, v);
	    if (v >= 0) {
		sprintf (tmp, pval);
		sprintf (pval, " %s", tmp);
	    }

	    *fval = v;
	}
    }

    if (type == 'l')
	Comb_vals_L[i] = sval;
    else
	Comb_vals_U[i] = sval;
}

struct signal *findSignal (y, extend)
Grid y;
int extend;     /* signal below bottom signal can also be selected */
{
    struct signal *sig;
    int i;

    if (extend)
	y = y + sigSpace / 2;

    if (y >= canvasHeight - canvasBottom) {
	if (!extend) {
	    i = Curr_nr_signals - 1;  /* Bottom_signal */
	}
	else {
	    if (Bottom_signal == End_signal)
		return (NULL);
	    else
		return (Bottom_signal -> next);
	}
    }
    else {
	i = Curr_nr_signals * (y - canvasTop) 
	    / (canvasHeight - canvasTop - canvasBottom);
    }

    if (i < 0) i = 0;

    sig = Top_signal;
    while (i > 0 && sig != Bottom_signal) {
	sig = sig -> next;
	i--;
    }

    return (sig);
}

int findVolt (y)
Grid y;
{
    int i;
    Grid yb;
    int v;

    i = Curr_nr_signals * (y - canvasTop) 
        / (canvasHeight - canvasTop - canvasBottom);

    if (i < 0) 
        i = 0;
    else if (i >= Curr_nr_signals) 
        i = Curr_nr_signals - 1;

    yb = canvasTop 
         + (canvasHeight - canvasTop - canvasBottom) * (i + 1) 
	    / Curr_nr_signals 
         - (sigSpace / 8);

    v = (yb + oY - y) / grid_volt + 0.5;   /* add 0.5 for rounding */

    return (v);
}

void findVoltSig (x, y, pv, s)
Grid x;
Grid y;
double *pv;
char *s;
{
    int i;
    long t;
    long findTime ();
    void findValSig ();
    void findGrid ();

    i = Curr_nr_signals * (y - canvasTop) 
        / (canvasHeight - canvasTop - canvasBottom);

    if (i < 0) 
        i = 0;
    else if (i >= Curr_nr_signals) 
        i = Curr_nr_signals - 1;
    i++;

    t = findTime (x, !currLogic);

    findValSig (i, 0, t, 'u', pv, s);

    findGrid (i, t, 0, *pv, &drawP_x, &drawP_y);
}

int findState (y)
Grid y;
{
    int s;
    int v;
    int findVolt ();

    v = findVolt (y);

    if (v < Global_umin + (double)(Global_umax - Global_umin) / 3)
        s = Global_umin;
    else if (v > Global_umin + (double) 2 * (Global_umax - Global_umin) / 3)
        s = Global_umax;
    else
        s = Global_umin + (Global_umax - Global_umin) / 2;

    return (s);
}

long findTime (x, round)
Grid x;
int round;
{
    long t;
    double a;

    if (x < axisStart)
        x = axisStart;
    else if (x > axisStart + axisLength)
        x = axisStart + axisLength; 

    if (round)
	a = 0.5;           /* add 0.5 for rounding */
    else
	a = 0.0;

    t = (double) startTime + (x - axisStart) / grid_time + a;
 
    return (t);
}

void findGrid (sig_i, time, lval, fval, x, y)
int sig_i;
long time;
int lval;
double fval;
Grid *x;
Grid *y;
{
    Grid yb;
    Grid xl;

    yb = canvasTop 
	 + (canvasHeight - canvasTop - canvasBottom) * sig_i 
	   / Curr_nr_signals 
	 - (sigSpace / 8);

    xl = canvasLeft + canvasNames;

    *x = xl + (time - startTime) * grid_time;
    if (currLogic && lval == -1)
	lval = 1;                /* draw level free state at level x state */
    if (currLogic)
	*y = yb + oY - grid_volt * lval;
    else
	*y = yb + oY - grid_volt * fval * v_outunit / Voltscaling;
}

void findBBox (sig, t1, t2, x1, y1, x2, y2)
struct signal *sig;
long t1;
long t2;
Grid *x1;
Grid *y1;
Grid *x2;
Grid *y2;
{
    Grid yb;
    Grid xl;

    yb = canvasTop 
	 + (canvasHeight - canvasTop - canvasBottom) * (sig -> i) 
	   / Curr_nr_signals 
	 - (sigSpace / 8);

    xl = canvasLeft + canvasNames;

    *x1 = xl + (t1 - startTime) * grid_time - 1;
    *x2 = xl + (t2 - startTime) * grid_time + 1;

    *y1 = yb + oY - grid_volt * -0.15 + 1;
    *y2 = yb + oY - grid_volt * 2.15 - 1;
}

void markSignal (sig)
struct signal *sig;
{
    Grid yb;

    yb = canvasTop 
	 + (canvasHeight - canvasTop - canvasBottom) * (sig -> i) 
	   / Curr_nr_signals 
	 - (sigSpace / 8);
	
    XDrawString (display, window, gc, 
		 (canvasLeft / 2), yb, "*", 1);
}

void unMarkSignal (sig)
struct signal *sig;
{
    Grid yb;

    yb = canvasTop 
	 + (canvasHeight - canvasTop - canvasBottom) * (sig -> i) 
	   / Curr_nr_signals 
	 - (sigSpace / 8);
	
    XClearArea (display, window, (canvasLeft / 2), yb - fontHeight, 
		fontWidth, fontHeight, False);
}

void insSigOnCanvas (sig, sig2)
struct signal *sig;
struct signal *sig2;
{
    Curr_nr_signals++;        /* don't forget ! */
    Nr_signals++;

    /* sig is inserted above (previous to) sig2.
       if sig2 == NULL, sig is inserted as End_signal */

    if (sig2 == Begin_signal)
	Begin_signal = sig;
    if (sig2 == NULL)
	End_signal = sig;

    if (sig2 == Top_signal) {
	sig -> next = sig2;
	sig -> prev = sig2 -> prev;
	if (sig2 -> prev)
	    sig2 -> prev -> next = sig;
	sig2 -> prev = sig;
	Top_signal = sig;
    }
    else if (sig2 == NULL) {
	sig -> next = NULL;
	sig -> prev = Bottom_signal;
	Bottom_signal -> next = sig;
	Bottom_signal = sig;
    }
    else {
	if (sig2 -> prev == Bottom_signal)
	    Bottom_signal = sig;
	sig -> next = sig2;
	sig -> prev = sig2 -> prev;
	sig2 -> prev -> next = sig;
	sig2 -> prev = sig;
    }
}

void delSigFromCanvas (sig, onlyMoved)
struct signal *sig;
int onlyMoved;
{
    struct signal *follow;

    if (sig == Top_signal)
	Top_signal = sig -> next;
    if (sig == Bottom_signal)
	Bottom_signal = sig -> prev;

    if (sig -> next != NULL)
	sig -> next -> prev = sig -> prev;
    else
	End_signal = sig -> prev;
    if (sig -> prev != NULL)
	sig -> prev -> next = sig -> next;
    else
	Begin_signal = sig -> next;

    Curr_nr_signals--;
    Nr_signals--;

    if (!onlyMoved) {

	/* find possible new Endtime */

	Endtime = 0;
	for (follow = Begin_signal; follow != NULL; follow = follow -> next) {
	    if (currLogic) {
		if (follow -> end_value 
		&& follow -> end_value -> time > Endtime)
		     Endtime = follow -> end_value -> time;
	    }
	    else {
		if (follow -> end_value_U 
		&& follow -> end_value_U -> time > Endtime)
		     Endtime = follow -> end_value_U -> time;
	    }
	}
	if (editing)
	    SimEndtime = Endtime;
    }
}

void newSigOnCanvas (name)
char *name;
{
    struct signal *sig;

    NEW (sig, 1, struct signal);
    NEW (sig -> name, strlen (name) + 1, char);
    strcpy (sig -> name, name);
    sig -> begin_value = NULL;
    sig -> begin_value_L = NULL;
    sig -> begin_value_U = NULL;
    sig -> end_value = NULL;
    sig -> end_value_L = NULL;
    sig -> end_value_U = NULL;
    sig -> expr = NULL;
    sig -> no_edit = 0;
    sig -> endless = 0;
    sig -> stringValue = 0;

    if (Begin_signal == NULL) {
        Begin_signal = sig;
        End_signal = sig;
        Top_signal = sig;
        Bottom_signal = sig;
        sig -> next = NULL;
        sig -> prev = NULL;
        Curr_nr_signals = 1;
        Nr_signals = 1;
	curr_umin = Global_umin;
	curr_umax = Global_umax;
    }
    else {
        sig -> next = Bottom_signal -> next;
        sig -> prev = Bottom_signal;
        if (Bottom_signal -> next)
            Bottom_signal -> next -> prev = sig;
        Bottom_signal -> next = sig;
        if (End_signal == Bottom_signal)
            End_signal = sig;
        Bottom_signal = sig;
        Curr_nr_signals++;
        Nr_signals++;
    }
}

void changeTimescaling (newTimescaling)
double newTimescaling;
{
    struct signal *sig;
    struct sig_value *sval;
    double factor;

    factor = Timescaling / newTimescaling;

    sig = Begin_signal; 
    while (sig != NULL) {
        sval = sig -> begin_value;
        while (sval) {
            if (factor < 1)
                sval -> time = (sval -> time + 0.5) * factor;
            else
                sval -> time = sval -> time * factor;
            sval = sval -> next;
        }
        sig = sig -> next;
    }
    
    if (storedVals) {
	sval = storedVals;
	while (sval) {
            if (factor < 1)
                sval -> time = (sval -> time + 0.5) * factor;
            else
                sval -> time = sval -> time * factor;
	    sval = sval -> next;
	}
    }

    if (factor < 1) {
        startTime = (startTime + 0.5) * factor;
        stopTime = (stopTime + 0.5) * factor;
        Begintime = (Begintime + 0.5) * factor;
        Endtime = (Endtime + 0.5) * factor;
	SimEndtime = (SimEndtime + 0.5) * factor;
    }
    else {
        startTime = startTime * factor;
        stopTime = stopTime * factor;
        Begintime = Begintime * factor;
        Endtime = Endtime * factor;
	SimEndtime = SimEndtime * factor;
    }

    Timescaling = newTimescaling;
}

void changeSimEndtime (newSimEndtimeS)
double newSimEndtimeS;
{
    struct signal *sig;

    extern long newEndtime;
    extern long curr_time;
    extern int simperiod;

    void addSgnPart ();
    void adjustSgnPart ();

    newEndtime = newSimEndtimeS / Timescaling;
    simperiod = newEndtime;

    sig = Begin_signal; 
    while (sig != NULL) {

	if (sig -> no_edit || sig -> endless) {
	    delSigval (sig -> begin_value);
	    sig -> begin_value = NULL;
	    sig -> end_value = NULL;
	    curr_time = 0;
	    /* simperiod has been set above */
	    addSgnPart (sig, sig -> expr, 1);
	}

        adjustSgnPart (sig);

	sig = sig -> next;
    }

    Endtime = newEndtime;
    SimEndtime = Endtime;

    startTime = Begintime; 
    stopTime = Endtime;
}

struct signal *existSignal (name)
char *name;
{
    struct signal *sig;

    sig = Begin_signal;
    while (sig && strcmp (sig -> name, name) != 0) {
	sig = sig -> next;
    }

    return (sig);
}

void windowMessage (s, x)
char *s;
Grid x;
{
    Grid x_mess;
    int len;

    /* prints a message on the canvas */

    if (windowListFn[0] != '\0')
        clear ();
    else
        XClearArea (display, window, 0, 0, 
		    axisStart + axisLength, canvasTop / 2 + fontHeight, False);

    if (s) {
	len = strlen (s);
	if (x > 0) {
	    x_mess = x - (len * fontWidth) / 2;
	    if (x_mess > axisStart + axisLength - len * fontWidth)
	        x_mess = axisStart + axisLength - len * fontWidth;
	    if (x_mess < axisStart)
		x_mess = axisStart;
	}
	else
	    x_mess = axisStart;
	XDrawString (display, window, gc, 
		     x_mess, (canvasTop + fontHeight) / 2, s, len);
	strcpy (windowMesBuf, s);
	if (x > 0)
	    windowMesX = x_mess;
	else
	    windowMesX = -1;
    }
    else {
	windowMesBuf[0] = '\0';
    }
    windowListFn[0] = '\0';
}

void windowList (fn)
char *fn;
{
    char buf[256];
    char c;
    int i;
    Grid y;
    FILE *fp;

    sprintf (windowListFn, "%s", fn);

    fp = fopen (windowListFn, "r");

    clear ();

    if (fp) {

	y = (canvasTop + fontHeight) / 2;

	while ((c = getc (fp)) != EOF && y < canvasHeight) { 

	    ungetc (c, fp);

	    i = 0;
	    while ((c = getc (fp)) != '\n' && c != EOF && i < 256) {
		buf[i++] = c;
	    }
	    buf[i] = '\0';

	    XDrawString (display, window, gc, axisStart, y, buf, i);

	    y = y + 1.8 * fontHeight;
	}

	fclose (fp);
        windowMesBuf[0] = '\0';
    }
    else {
	sprintf (buf, "Cannot open %s", fn);
	windowMessage (buf, -1);
    }
}
