
#include "mview_spectrum.h"

#include "gx11/visual_context.h"
#include "gsys/cfc.h"
#include "mview_main.h"
#include "mview_help.h"
#include "mview_menu.h"
#include "mview_slice.h"
#include "mview_cursor.h"
#include "mview_display.h"
#include "mview_view.h"
#include "mview_widgets.h"
#include "mview_misc.h"
#include "mview_macros.h"

#include <math.h>
#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>

#include <Xm/Xm.h>
#include <Xm/MwmUtil.h>
#include <Xm/Text.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/DrawingA.h>
#include <Xm/CascadeB.h>
#include <Xm/MainW.h>
#include <Xm/XmStrDefs.h>

#define spectre CFC_EXPORT_NAME(spectre)

extern int cursor_mode;
extern int xoffset, yoffset;


#define STARTVAL 200000
static int current_speed = STARTVAL;

extern void spectre( int *count, float *ngon, float *s);

static Widget spectrumshell = NULL, up_spectrumshell = NULL, down_spectrumshell = NULL, parent1 = NULL, parent2 = NULL;
static Widget zvalues;
static Widget specform1;
static Widget specform2;
static Widget spectreDA;
static Widget spectre_w;
static Widget movieb;
static Widget plusb;
static Widget moinsb;
static Widget resetregionb;

static char dumstr[80];

Pixmap integpixmap;             /* Pixmap for integrated mean */
Pixmap subsetpixmap;            /* Pixmap containing one subset */

static struct itimerval rttimer, old_rttimer;

static XPoint_list top = NULL, queue;
static int nsum = 0, rec = 0;

static XPoint *prev_sp, *sp;
static XPoint *isp;

static XPoint tics[3];
static int drag = 0;

static float *m0;               /* integrated mean coordinate word */
static float clipm0[2];
static float *intspec;          /* integrated spectrum */
static float *s1;

static float minintspec, maxintspec;

static int movieactive = 0;
static int restart = 0;
static int warning = 0, warning2 = 0;

int firstsub = 1;
static int Z = 0, sub1, sub2;
static int prev_Z = 0, prev_sub1, prev_sub2;
int ticwidth;
extern Dimension disp_w, disp_h;

extern void set_scale( );
extern void set_tics( );
extern void increment_speed( );
extern void decrement_speed( );
extern void quit( );



/* Actions to be added to the Translation Manager */
static XtActionsRec actions_list[] = {
    {"set_tics", (XtActionProc) set_tics},
    {"set_scale", (XtActionProc) set_scale},
};

char spectrum_translations[] = "<EnterNotify>: spectrum_input( )\n\
                       <LeaveNotify>: spectrum_input( )\n\
                       <Motion>: spectrum_input( )\n\
                       <Btn1Up>: spectrum_input( )\n\
                       <Btn1Down>: spectrum_input( )\n\
                       <Btn2Up>: spectrum_input( )\n\
                       <Btn2Down>: spectrum_input( )\n\
                       <Btn3Up>: spectrum_input( )\n\
                       <Btn3Down>: spectrum_input( )\n";

static char set_tics_translations[] = "Button1<Motion>: set_tics( )\n\
                      <Btn1Down>: set_tics( )\n\
                      <Btn1Up>: set_tics( )\n";

static char spectre_w_translations[] = "<Btn1Down>: set_scale( )\n\
                      <Btn2Down>: set_scale( )\n";

void draw_area( )
{
    XPoint_list xpl;

    if (top == NULL)
        return;
    if (nsum > 1) {

        xpl = top;

        while (xpl->next != NULL) {
            XDrawLine( display, XtWindow( integmean), gcx, xpl->xp.x, xpl->xp.y, xpl->next->xp.x, xpl->next->xp.y);

            xpl = xpl->next;
        }
    }
}


static int prev_rx, prev_ry, prev_width, prev_height, edit = 0;

void get_2D_area( int box[6])
{
    char chainx[80], chainy[80], chainz[80], chainv[80];
    double uc[3];

    if (edit) {
        box[0] = prev_rx / localzoom + 1;       /* + 1 for x between 1 and npix[0] */
        box[1] = (npix[1] - 1 - (prev_ry + prev_height) / localzoom) + 1;
        box[2] = 1;
        box[3] = (prev_rx + prev_width) / localzoom + 1;
        box[4] = (npix[1] - 1 - prev_ry / localzoom) + 1;
        box[5] = 1;
    } else {
        box[0] = 1;
        box[1] = 1;
        box[2] = 1;
        box[3] = npix[0];
        box[4] = npix[1];
        box[5] = Nsubs;
    }

    phys_coord( &box[0], &box[1], &box[2], uc,
               chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

    phys_coord( &box[3], &box[4], &box[5], uc,
               chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));
}

void redraw_2D_box( Widget w)
{
    if (edit) {
        if ((w == subset) && (subpixmap[0] == 0))
            XDrawRectangle( display, XtWindow( subset), gcx,
                           xoffset + zoom * ((float)prev_rx / localzoom) / incr,
                           yoffset + zoom * ((float)prev_ry / localzoom) / incr,
                           zoom * ((float)prev_width / localzoom) / incr, zoom * ((float)prev_height / localzoom) / incr);
        else
            XDrawRectangle( display, XtWindow( w), gcx, prev_rx, prev_ry, prev_width, prev_height);
    }
}

void reset_2D_box( )
{                                      /* (For the display only) */
    if (edit) {
        if (subpixmap[0] == 0)
            XDrawRectangle( display, XtWindow( subset), gcx,
                           xoffset + zoom * ((float)prev_rx / localzoom) / incr,
                           yoffset + zoom * ((float)prev_ry / localzoom) / incr,
                           zoom * ((float)prev_width / localzoom) / incr, zoom * ((float)prev_height / localzoom) / incr);
        else
            XDrawRectangle( display, XtWindow( subset), gcx, prev_rx, prev_ry, prev_width, prev_height);

        XDrawRectangle( display, XtWindow( integmean), gcx, prev_rx, prev_ry, prev_width, prev_height);
        edit = 0;
    }
}


void redraw_in_integmean( )
{
    XCopyArea( display, integpixmap, XtWindow( integmean), gc, 0, 0, zsizex, zsizey, 0, 0);

    draw_area( );
    redraw_zcross( integmean);
    redraws_slice_in_integmean( );
    redraw_2D_box( integmean);
}

void Update_IntegMean( )
{
    AffImage( m0, integpixmap, zsizex, zsizey,
             1, npix[0], 1, npix[1], localzoom, localzoom, clipm0[0], clipm0[1], 1, 0, 0, 0, 0, zsizex, zsizey);
    redraw_in_integmean( );
}


void calc_integspec( float *intspec)
{
    int z;


    /* Calcul des points du trace */
    minintspec = min( 0., intspec[0]);
    maxintspec = intspec[0];
    for (z = 1; z < Nsubs; z++) {
        if (intspec[z] < minintspec)
            minintspec = intspec[z];
        if (intspec[z] > maxintspec)
            maxintspec = intspec[z];
    }

    if (minintspec == maxintspec)
        isp[0].y = specheight - 20;
    else {
        for (z = 0; z < Nsubs; z++) {
            isp[z].y = (int)(((float)(specheight - 40)) * (1. - (intspec[z] - minintspec) / (maxintspec - minintspec)) + 20.);
        }
    }
}

void create_spectrum( Widget w, int w_code, XmAnyCallbackStruct * cbs)
{
    static Dimension h;

    switch (w_code) {

    case k_integmean:
        integmean = w;
        XtVaSetValues( integmean, XmNwidth, zsizex, XmNheight, zsizey, NULL);


        break;
    case k_subset:
        subset = w;
        XtVaSetValues( subset, XmNwidth, zsizex, XmNheight, zsizey, NULL);


        break;

    case k_integspectrum:
        integspectre = w;
        XtVaSetValues( integspectre, XmNwidth, specwidth, XmNheight, zsizey, NULL);
        break;

    case k_spectrum:
        spectre_w = w;
        XtVaSetValues( spectre_w, XmNwidth, specwidth, XmNheight, zsizey, NULL);
        XtVaSetValues( spectre_w, XmNtranslations, XtParseTranslationTable( spectre_w_translations), NULL);
        break;

    case k_bwidth:
        XtVaSetValues( w, XmNwidth, zsizex, XmNheight, h, NULL);
        break;

    case 0:
        XtVaSetValues( w, XmNwidth, specwidth, XmNheight, h, NULL);
        break;

    case k_bstart:
        XtVaSetValues( w, XmNwidth, (zsizex + specwidth) - 60, XmNheight, h, NULL);
        break;

    case k_bcontrol:
        XtVaSetValues( w, XmNwidth, 30, XmNheight, h, NULL);
        break;

    case k_zvalues:
        zvalues = w;
        XtVaSetValues( w, XmNwidth, specwidth, NULL);
        XtVaGetValues( w, XmNheight, &h, NULL);


        break;
    }
}

void draw_spec( Widget w, XPoint * ps, float clipmin, float clipmax)
{
    int i;

    XSetForeground( display, gc, g_vc.black_pixel);

    XFillRectangle( display, XtWindow( w), gc, 20, 20, specwidth - 40 + 1, specheight - 40 + 1);

    XSetForeground( display, gc, g_vc.white_pixel);


    if (w == spectre_w)
        XDrawLines( display, XtWindow( w), gc, sp, 2 * Nsubs, CoordModeOrigin);
    else {
        for (i = 0; i < (Nsubs - 1); i++) {
            XDrawLine( display, XtWindow( w), gc, 20 + ticwidth * i, ps[i].y, 20 + ticwidth * i + ticwidth - 1, ps[i].y);
            XDrawLine( display, XtWindow( w), gc,
                      20 + ticwidth * i + ticwidth - 1, ps[i].y, 20 + ticwidth * i + ticwidth - 1, ps[i + 1].y);
        }
        XDrawLine( display, XtWindow( w), gc,
                  20 + ticwidth * (Nsubs - 1), ps[Nsubs - 1].y, 20 + ticwidth * (Nsubs - 1) + ticwidth - 1, ps[Nsubs - 1].y);
    }
    if (clipmin == clipmax)
        XDrawLine( display, XtWindow( w), gc, 20, specheight - 20, specwidth - 20, specheight - 20);
    else
        XDrawLine( display, XtWindow( w), gc,
                  20,
                  (int)(((float)(specheight - 40)) * (1. - (-clipmin) /
                                                      (clipmax - clipmin)) + 20.),
                  specwidth - 20, (int)(((float)(specheight - 40)) * (1. - (-clipmin) / (clipmax - clipmin)) + 20.));


    if (w == spectre_w) {
        for (i = 0; i < 2 * Nsubs; i++)
            prev_sp[i].y = sp[i].y;
    }
}

void change_tic( int z)
{
    if (Nsubs >= 2)
        tics[0].x = 20 + (specwidth - 40 - ticwidth) * ((float)z / (Nsubs - 1));
    else
        tics[0].x = 20;
}

void expose_spectrum( Widget w, XtPointer w_code, XmAnyCallbackStruct * cbs)
{
    switch ((int)(long)w_code) {

    case k_integmean:
        if (cbs != NULL && cbs->event->xexpose.count == 0)
            redraw_in_integmean( );
        break;

    case k_integspectrum:
        draw_spec( w, isp, minintspec, maxintspec);

        ERRASETIC(20, specheight - 5, specwidth - 20, 5);
        DRAWTIC(tics[0].x, specheight - 5, ticwidth, 5);
        ERRASETIC(20, specheight - 19, specwidth - 20, 10);
        DRAWTIC(tics[1].x, specheight - 19, ticwidth, 10);
        DRAWTIC(tics[2].x, specheight - 19, ticwidth, 10);
        break;

    case k_subset:
        if (cbs != NULL && cbs->event->xexpose.count == 0) {

            XCopyArea( cbs->event->xexpose.display, subsetpixmap, XtWindow( w), gc, 0, 0, zsizex, zsizey, 0, 0);
            redraws_slice_in_subset( );
            redraw_zcross( w);
            redraw_2D_box( w);
        }
        break;

    case k_spectrum:
        draw_spec( w, sp, clip[0], clip[1]);
        break;

    }
}

void change_pixmap( int z)
{
    static int k = 0;

    if ((z >= Nsubs) || (z < 0)) {
        sprintf( dumstr, "%s %d\n", "z = ", z);
        printf( dumstr);
    }

    Z = z;                             /* In case of calling from slice mode */
    if (subpixmap[z] != 0)
        XCopyArea( display, subpixmap[z], subsetpixmap, gc, 0, 0, zsizex, zsizey, 0, 0);
    else
        XCopyArea( display, pixmap, subsetpixmap, gc, POSX(0, z), POSY(voffset, z), sizex, sizey, xoffset, yoffset);

    XCopyArea( display, subsetpixmap, XtWindow( subset), gc, 0, 0, zsizex, zsizey, 0, 0);

    redraws_slice_in_subset( );
    redraw_zcross( subset);
    redraw_2D_box( subset);

    ERRASETIC(20, specheight - 5, specwidth - 20, 5);
    DRAWTIC(tics[0].x, specheight - 5, ticwidth, 5);
    sprintf( dumstr, "Z=%d Z1=%d Z2=%d", Z + firstsub, sub1 + firstsub, sub2 + firstsub);
    XmTextSetString( zvalues, dumstr);
    if (warning) {
        XSetForeground( display, gc, g_vc.colmap[k]);
        XDrawString( display, XtWindow( subset), gc, 10, 30, "Not so fast...", 14);

        k = (k < MAXCOL - 1) ? k + 1 : 0;
    }
    if (warning2) {
        XSetForeground( display, gc, g_vc.colmap[k]);
        XDrawString( display, XtWindow( subset), gc, 10, 30, "Not so slow...", 14);
        k = (k < MAXCOL - 1) ? k + 1 : 0;
    }
    XFlush( display);
}

void change_Z()
{
    int pos[2];

    get_crosspos( pos);

    param( incr * GETX(pos[0]) / zoom, (npix[1] - 1 - incr * GETY(pos[1]) / zoom), Z, 1);
}

void kill_movie( )
{
    if (movieactive) {
        rttimer.it_value.tv_usec = 0;
        setitimer( ITIMER_REAL, &rttimer, &old_rttimer);
        movieactive = 0;
        restart = 0;

        long_timer( );
    }
}

void select_next_subset( int dum)
{
    sigset_t aa, bb;

    sigaddset( &aa, SIGALRM);

    sigprocmask( SIG_BLOCK, &aa, &bb);

    Z = (Z == Nsubs - 1) ? 0 : Z + 1;
    if (Nsubs >= 2)
        tics[0].x = 20 + (specwidth - 40 - ticwidth) * ((float)Z / (Nsubs - 1));
    else
        tics[0].x = 20;

    draw_cross( radec,
               POSX((int)((float)zoom * ((float)show_zposx / localzoom) / incr), Z),
               POSY((int)((float)zoom * ((float)show_zposy / localzoom) / incr), Z));

    change_pixmap( Z);
    change_Z();

    sigprocmask( SIG_UNBLOCK, &aa, &bb);
    signal( SIGALRM, select_next_subset);
}

void movie( )
{


    if (movieactive) {
        kill_movie( );
        return;
    }

    movieactive = 1;
    rttimer.it_value.tv_sec = 0;
    rttimer.it_value.tv_usec = current_speed;
    rttimer.it_interval.tv_sec = 0;
    rttimer.it_interval.tv_usec = current_speed;

    signal( SIGALRM, select_next_subset);

    setitimer( ITIMER_REAL, &rttimer, &old_rttimer);
}

void increase_speed( Widget w, XtPointer w_code, XmAnyCallbackStruct * cbs)
{
    if (!movieactive)
        return;

    if (current_speed >= 100000) {
        warning2 = 0;
        current_speed -= 50000;
    } else
        warning = 1;

    rttimer.it_interval.tv_usec = current_speed;
    setitimer( ITIMER_REAL, &rttimer, &old_rttimer);

}

void decrease_speed( Widget w, XtPointer w_code, XmAnyCallbackStruct * cbs)
{
    if (!movieactive)
        return;

    if (current_speed < 400000) {
        current_speed += 50000;
        warning = 0;
    } else
        warning2 = 1;

    rttimer.it_interval.tv_usec = current_speed;
    setitimer( ITIMER_REAL, &rttimer, &old_rttimer);
}

void dismiss_spectrum( Widget w, XtPointer w_code, XmAnyCallbackStruct * cbs)
{
    if (spectrumshell != NULL)
        XtUnmapWidget( spectrumshell);
    else {
        XtUnmapWidget( up_spectrumshell);
        XtUnmapWidget( down_spectrumshell);
    }
    kill_movie( );
}

void movie_CB(Widget w, XtPointer w_code, XmAnyCallbackStruct * cbs)
{
    movie( );
}

void all_integration( Widget w, XtPointer w_code, XmAnyCallbackStruct * cbs)
{
    XPoint_list xpl;

    calc_integspec( intspec);
    draw_spec( integspectre, isp, minintspec, maxintspec);

    if (top) {
        while (top != NULL) {
            xpl = top;
            top = top->next;
            free( xpl);
        }
        nsum = 0;
        rec = 0;
        top = NULL;
    }

/*
  draw_pol( );
*/
    redraw_in_integmean( );
}

void calc_integmean( int z1, int z2)
{
    int k, x, y, z;

    /* Calcul de la moyenne integree */
    for (k = 0; k < isize; k++)
        m0[k] = 0.;
    k = 0;
    for (y = 0; y < npix[1]; y++) {
        for (x = 0; x < npix[0]; x++) {
            for (z = z1; z <= z2; z++)
                if ((float)fabs( (double)*(F_ADDR(x, y, z)) - Blank) > Tolerance)
                    m0[k] = m0[k] + *(F_ADDR(x, y, z));
            k++;
        }
    }

    clipm0[0] = m0[0];
    clipm0[1] = m0[0];
    for (k = 1; k < isize; k++) {
        if (m0[k] < clipm0[0])
            clipm0[0] = m0[k];
        if (m0[k] > clipm0[1])
            clipm0[1] = m0[k];
    }
    AffImage( m0, integpixmap, zsizex, zsizey,
             1, npix[0], 1, npix[1], localzoom, localzoom, clipm0[0], clipm0[1], 1, 0, 0, 0, 0, zsizex, zsizey);
}

void configure( Widget w, XtPointer data, XEvent * event, char *odd)
{
    if ((event->type == VisibilityNotify) || (event->type == FocusOut)) {
        if (movieactive) {
            kill_movie( );
            restart = 1;

            /* Send a ConfigureNotify event to restart the movie */
            /* when leaving the window without moving it */
            if (spectrumshell == NULL) {
                XMapRaised( display, XtWindow( up_spectrumshell));
                XMapRaised( display, XtWindow( down_spectrumshell));
            } else
                XMapRaised( display, XtWindow( spectrumshell));
        }
    }
    if (event->type == ConfigureNotify)
        if ((restart) && (!movieactive))
            movie( );
}


void spectrum( )
{
    static int firstpass = 1;

    Widget menubar, smenubar;

    int n = 0;
    Arg args[32];

    XtVaSetValues( radec, XmNtranslations, XtParseTranslationTable( spectrum_translations), NULL);
    cursor_mode = SPECTRUM;

    if (Nsubs < 2)
        return;

    if (firstpass) {
        double uc[3];

        int i, k, x, y, z;
        char chainx[80], chainy[80], chainz[80], chainv[80];
        m0 = (float *)malloc( npix[0] * npix[1] * sizeof( float));


        sp = (XPoint *) XtMalloc( 2 * Nsubs * sizeof( XPoint));
        prev_sp = (XPoint *) XtMalloc( 2 * Nsubs * sizeof( XPoint));

        isp = (XPoint *) XtMalloc( Nsubs * sizeof( XPoint));
        intspec = (float *)malloc( Nsubs * sizeof( float));
        s1 = (float *)malloc( Nsubs * sizeof( float));

        integpixmap = XCreatePixmap( display, g_vc.root_window, zsizex, zsizey, g_vc.depth);
        subsetpixmap = XCreatePixmap( display, g_vc.root_window, zsizex, zsizey, g_vc.depth);
        XSetForeground( display, gc, g_vc.black_pixel);
        XFillRectangle( display, subsetpixmap, gc, 0, 0, zsizex, zsizey);

        if (subpixmap[0] != 0)
            XCopyArea( display, subpixmap[0], subsetpixmap, gc, 0, 0, zsizex, zsizey, 0, 0);
        else
            XCopyArea( display, pixmap, subsetpixmap, gc, 0, 0, sizex, sizey, xoffset, yoffset);

        x = 1;
        y = 1;

        phys_coord( &x, &y, &firstsub, uc,
                   chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

        /* Calcul du spectre integre */
        for (z = 0; z < Nsubs; z++) {
            intspec[z] = 0.;
            for (y = 0; y < npix[1]; y++) {
                for (x = 0; x < npix[0]; x++) {
                    if (fabs( *(F_ADDR(x, y, z)) - Blank) > Tolerance)
                        intspec[z] = intspec[z] + *(F_ADDR(x, y, z));
                }
            }
        }

        calc_integspec( intspec);

        sub1 = 0;
        sub2 = Nsubs - 1;

        prev_sub1 = 0;
        prev_sub2 = Nsubs - 1;

        calc_integmean( sub1, sub2);

        if (Nsubs >= 2)
            ticwidth = (specwidth - 40) / Nsubs;
        else
            ticwidth = 8;

        k = 0;
        sp[k].x = 20;
        prev_sp[k].x = sp[k].x;
        k++;
        for (i = 0; i < (Nsubs - 1); i++) {
            sp[k].x = 20 + ticwidth * i + ticwidth - 1;
            prev_sp[k].x = sp[k].x;
            k++;
            sp[k].x = 20 + ticwidth * i + ticwidth - 1;
            prev_sp[k].x = sp[k].x;
            k++;
        }
        sp[k].x = 20 + ticwidth * (Nsubs - 1) + ticwidth - 1;
        prev_sp[k].x = sp[k].x;
        k++;

        for (i = 0; i < 2 * Nsubs - 1; i++)
            prev_sp[k].y = 0;


        tics[0].x = 20;
        tics[0].y = specheight - 5;
        tics[1].x = 20;
        tics[1].y = specheight - 20;
        tics[2].x = specwidth - 20 - ticwidth;
        tics[2].y = specheight - 20 - ticwidth;

        if (2 * zsizey + 200 < disp_h) {

            spectrumshell = XtVaAppCreateShell( "Integrated mean / spectrum",
                                               "spectrumshell",
                                               topLevelShellWidgetClass,
                                               XtDisplay( toplevel),
                                               XmNmappedWhenManaged, True,
                                               XmNmwmDecorations, MWM_DECOR_TITLE | MWM_DECOR_BORDER | MWM_DECOR_MINIMIZE, NULL);
            parent1 = parent2 = XtVaCreateManagedWidget( "spectrum_w", xmFormWidgetClass, spectrumshell, NULL);
        } else {
            up_spectrumshell =
             XtVaAppCreateShell( "Integrated mean",
                                "up_spectrumshell",
                                topLevelShellWidgetClass,
                                XtDisplay( toplevel),
                                XmNmappedWhenManaged, True,
                                XmNmwmDecorations, MWM_DECOR_TITLE | MWM_DECOR_BORDER | MWM_DECOR_MINIMIZE, NULL);
            parent1 = XtVaCreateManagedWidget( "up_spectrum_w", xmFormWidgetClass, up_spectrumshell, NULL);
            down_spectrumshell =
             XtVaAppCreateShell( "Spectrum",
                                "down_spectrumshell",
                                topLevelShellWidgetClass,
                                XtDisplay( toplevel),
                                XmNmappedWhenManaged, True,
                                XmNmwmDecorations, MWM_DECOR_TITLE | MWM_DECOR_BORDER | MWM_DECOR_MINIMIZE, NULL);
            parent2 = XtVaCreateManagedWidget( "down_spectrum_w", xmFormWidgetClass, down_spectrumshell, NULL);
        }
        specform1 = XtVaCreateManagedWidget( "specform1",
                                            xmFormWidgetClass,
                                            parent1,
                                            XmNbackground, blackpix,
                                            XmNtopAttachment, XmATTACH_FORM,
                                            XmNleftAttachment, XmATTACH_FORM,
                                            XmNrightAttachment, XmATTACH_FORM, XmNheight, 32, NULL);
        spixelvalue = XtVaCreateManagedWidget( "spixelvalue",
                                              xmTextWidgetClass,
                                              specform1,
                                              XmNleftAttachment, XmATTACH_FORM,
                                              XmNtraversalOn, FALSE,
                                              XmNbackground, blackpix,
                                              XmNforeground, whitepix, XmNcursorPositionVisible, FALSE, XmNeditable, FALSE, NULL);
        create( spixelvalue, k_spixelvalue, NULL);

        sgridcoord = XtVaCreateManagedWidget( "sgridcoord",
                                             xmTextWidgetClass,
                                             specform1,
                                             XmNleftAttachment, XmATTACH_WIDGET,
                                             XmNleftWidget, spixelvalue,
                                             XmNrightAttachment, XmATTACH_FORM,
                                             XmNbackground, blackpix,
                                             XmNforeground, whitepix,
                                             XmNtraversalOn, FALSE, XmNcursorPositionVisible, FALSE, XmNeditable, FALSE, NULL);
        create( sgridcoord, k_sgridcoord, NULL);

        specform2 = XtVaCreateManagedWidget( "specform2",
                                            xmFormWidgetClass,
                                            parent1,
                                            XmNbackground, blackpix,
                                            XmNtopAttachment, XmATTACH_WIDGET,
                                            XmNtopWidget, specform1,
                                            XmNleftAttachment, XmATTACH_FORM,
                                            XmNrightAttachment, XmATTACH_FORM, XmNheight, 32, NULL);
        saxis1 = XtVaCreateManagedWidget( "saxis1",
                                         xmTextWidgetClass,
                                         specform2,
                                         XmNleftAttachment, XmATTACH_FORM,
                                         XmNtraversalOn, FALSE,
                                         XmNbackground, blackpix,
                                         XmNforeground, whitepix, XmNcursorPositionVisible, FALSE, XmNeditable, FALSE, NULL);
        create( saxis1, k_saxis1, NULL);

        saxis2 = XtVaCreateManagedWidget( "saxis2",
                                         xmTextWidgetClass,
                                         specform2,
                                         XmNleftAttachment, XmATTACH_WIDGET,
                                         XmNleftWidget, saxis1,
                                         XmNbackground, blackpix,
                                         XmNforeground, whitepix,
                                         XmNtraversalOn, FALSE, XmNcursorPositionVisible, FALSE, XmNeditable, FALSE, NULL);
        create( saxis2, k_saxis2, NULL);

        saxis3 = XtVaCreateManagedWidget( "saxis3",
                                         xmTextWidgetClass,
                                         specform2,
                                         XmNleftAttachment, XmATTACH_WIDGET,
                                         XmNleftWidget, saxis2,
                                         XmNrightAttachment, XmATTACH_FORM,
                                         XmNbackground, blackpix,
                                         XmNforeground, whitepix,
                                         XmNtraversalOn, FALSE, XmNcursorPositionVisible, FALSE, XmNeditable, FALSE, NULL);
        create( saxis3, k_saxis3, NULL);
        n = 0;
        XtSetArg( args[n], XmNtopAttachment, XmATTACH_WIDGET);
        n++;
        XtSetArg( args[n], XmNtopWidget, specform2);
        n++;
        XtSetArg( args[n], XmNmarginWidth, 0);
        n++;
        XtSetArg( args[n], XmNmarginHeight, 0);
        n++;
        XtSetArg( args[n], XmNshadowThickness, 0);
        n++;
        XtSetArg( args[n], XmNshadowType, XmSHADOW_OUT);
        n++;
        XtSetArg( args[n], XmNleftAttachment, XmATTACH_FORM);
        n++;
        XtSetArg( args[n], XmNrightAttachment, XmATTACH_FORM);
        n++;
        XtSetArg( args[n], XmNmenuHelpWidget, helpbutton);
        n++;
        menubar = smenubar = XmCreateMenuBar( parent1, "smenubar", args, n);
        create_standard_menu( menubar);
        XtManageChild( menubar);

        integmean = XtVaCreateManagedWidget( "INTEGMEAN",
                                            xmDrawingAreaWidgetClass,
                                            parent1,
                                            XmNleftAttachment, XmATTACH_FORM,
                                            XmNtopAttachment, XmATTACH_WIDGET,
                                            XmNtopWidget, smenubar, XmNbackground, blackpix, NULL);
        create_spectrum( integmean, k_integmean, NULL);
        XtAddCallback( integmean, XmNexposeCallback, (XtCallbackProc) expose_spectrum, (XtPointer) k_integmean);

        integspectre = XtVaCreateManagedWidget( "INTEGSPECTRE",
                                               xmDrawingAreaWidgetClass,
                                               parent1,
                                               XmNtopAttachment, XmATTACH_WIDGET,
                                               XmNtopWidget, smenubar,
                                               XmNleftAttachment, XmATTACH_WIDGET,
                                               XmNleftWidget, integmean, XmNbackground, blackpix, NULL);
        create_spectrum( integspectre, k_integspectrum, NULL);
        XtAddCallback( integspectre, XmNexposeCallback, (XtCallbackProc) expose_spectrum, (XtPointer) k_integspectrum);
        zvalues = XtVaCreateManagedWidget( "ZVALUES",
                                          xmTextWidgetClass,
                                          parent1,
                                          XmNbackground, blackpix,
                                          XmNforeground, whitepix,
                                          XmNcursorPositionVisible, FALSE,
                                          XmNeditable, FALSE,
                                          XmNtopAttachment, XmATTACH_WIDGET,
                                          XmNtopWidget, integspectre, XmNrightAttachment, XmATTACH_FORM, NULL);
        create_spectrum( zvalues, k_zvalues, NULL);

        resetregionb = XtVaCreateManagedWidget( "Reset region",
                                               xmPushButtonWidgetClass,
                                               parent1,
                                               XmNleftAttachment, XmATTACH_FORM,
                                               XmNtopAttachment, XmATTACH_WIDGET,
                                               XmNtopWidget, integmean,
                                               XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, zvalues, NULL);

        create_spectrum( resetregionb, k_bwidth, NULL);
        XtAddCallback( resetregionb, XmNactivateCallback, (XtCallbackProc) all_integration, NULL);

        subset = XtVaCreateManagedWidget( "SUBSET",
                                         xmDrawingAreaWidgetClass,
                                         parent2, XmNleftAttachment, XmATTACH_FORM, XmNbackground, blackpix, NULL);
        if (spectrumshell != NULL) {
            XtVaSetValues( subset, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, resetregionb, NULL);
        } else {
            XtVaSetValues( subset, XmNtopAttachment, XmATTACH_FORM, NULL);
        }
        create_spectrum( subset, k_subset, NULL);
        XtAddCallback( subset, XmNexposeCallback, (XtCallbackProc) expose_spectrum, (XtPointer) k_subset);

        spectreDA = XtVaCreateManagedWidget( "spectreDA",
                                            xmDrawingAreaWidgetClass,
                                            parent2,
                                            XmNleftAttachment, XmATTACH_WIDGET,
                                            XmNleftWidget, subset, XmNbackground, blackpix, NULL);
        if (spectrumshell != NULL) {
            XtVaSetValues( spectreDA, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zvalues, NULL);
        } else {
            XtVaSetValues( spectreDA, XmNtopAttachment, XmATTACH_FORM, NULL);
        }
        create_spectrum( spectreDA, k_spectrum, NULL);
        XtAddCallback( spectreDA, XmNexposeCallback, (XtCallbackProc) expose_spectrum, (XtPointer) k_spectrum);
        movieb = XtVaCreateManagedWidget( "Automatic movie",
                                         xmPushButtonWidgetClass,
                                         parent2,
                                         XmNtopAttachment, XmATTACH_WIDGET,
                                         XmNtopWidget, subset, XmNleftAttachment, XmATTACH_FORM, NULL);
        create_spectrum( movieb, k_bstart, NULL);
        XtAddCallback( movieb, XmNactivateCallback, (XtCallbackProc) movie_CB, NULL);
        plusb = XtVaCreateManagedWidget( "+",
                                        xmPushButtonWidgetClass,
                                        parent2,
                                        XmNtopAttachment, XmATTACH_WIDGET,
                                        XmNtopWidget, spectreDA, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, movieb, NULL);
        create_spectrum( plusb, k_bcontrol, NULL);
        XtAddCallback( plusb, XmNarmCallback, (XtCallbackProc) increase_speed, NULL);
        moinsb = XtVaCreateManagedWidget( "-",
                                         xmPushButtonWidgetClass,
                                         parent2,
                                         XmNtopAttachment, XmATTACH_WIDGET,
                                         XmNtopWidget, spectreDA,
                                         XmNleftAttachment, XmATTACH_WIDGET,
                                         XmNleftWidget, plusb, XmNrightAttachment, XmATTACH_FORM, NULL);
        create_spectrum( moinsb, k_bcontrol, NULL);
        XtAddCallback( moinsb, XmNarmCallback, (XtCallbackProc) decrease_speed, NULL);

        /* initialisation des points du spectre 
           for (z = 0; z < Nsubs; z++) {
           ps[z].y = (specheight - 40)*(1 + clip[0]/(clip[1] - clip[0])) + 20;
           } */
        for (z = 0; z < 2 * Nsubs; z++) {
            sp[z].y = (specheight - 40) * (1 + clip[0] / (clip[1] - clip[0])) + 20;
            prev_sp[z].y = sp[z].y;
        }

        /*
         ** Add actions to the Translation manager 
         */

        XtAppAddActions( app, actions_list, XtNumber( actions_list));

        if (spectrumshell != NULL) {
            XtRealizeWidget( spectrumshell);
            XtAddEventHandler( spectrumshell, StructureNotifyMask | FocusChangeMask | VisibilityChangeMask, False, configure, NULL);

            set_colormap( spectrumshell);

        } else {
            XtRealizeWidget( up_spectrumshell);
            XtRealizeWidget( down_spectrumshell);
            XtAddEventHandler( up_spectrumshell,
                              StructureNotifyMask | FocusChangeMask | VisibilityChangeMask, False, configure, NULL);
            XtAddEventHandler( down_spectrumshell,
                              StructureNotifyMask | FocusChangeMask | VisibilityChangeMask, False, configure, NULL);
            set_colormap( up_spectrumshell);
            set_colormap( down_spectrumshell);
        }

        sprintf( dumstr, "Z=%d Z1=%d Z2=%d", Z + firstsub, sub1 + firstsub, sub2 + firstsub);
        XmTextSetString( zvalues, dumstr);


        XtVaSetValues( integspectre, XmNtranslations, XtParseTranslationTable( set_tics_translations), NULL);

        firstpass = 0;
    }



    XtVaSetValues( subset, XmNtranslations, XtParseTranslationTable( spectrum_translations), NULL);

    XtVaSetValues( integmean, XmNtranslations, XtParseTranslationTable( spectrum_translations), NULL);
}

extern XImage *hugeimage;
extern char *lotofpixels;
extern Widget zoomshell, zoom_w;
extern Dimension zoom_width, zoom_height;

static float scale = 1.;

void spec_modify( int x, int y)
{
    int z, xr, yr, zr;
    float f;

    xr = GETX(x);
    yr = GETY(y);
    zr = GETZ(x, y);

    if (!INMOSAIC(x, y) || (zr >= Nsubs))
        return;

    param( incr * xr / zoom, (npix[1] - 1 - incr * yr / zoom), zr, 1);

    if (Nsubs >= 2) {
        for (z = 0; z < Nsubs; z++) {
            /* Between () to be correctly evaluated */
            f = *(F_ADDR(incr * xr / zoom, (npix[1] - 1 - incr * yr / zoom), z));

            if (f == Blank)
                f = clip[0];
            f = min( clip[1], max( clip[0], scale * f));
            sp[2 * z].y = (specheight - 40) * (1 - (f - clip[0]) / (clip[1] - clip[0])) + 20;
            sp[2 * z + 1].y = sp[2 * z].y;
        }

        draw_spec( spectre_w, sp, clip[0], clip[1]);
    }
}



void new_spec( Widget w, int x, int y)
{
    int z, xr, yr, zr;
    static int prev_zr = -1;
    float f;
    int zx, zy;

    if (w == radec) {
        xr = GETX(x);
        yr = GETY(y);
        zr = GETZ(x, y);

        if (!INMOSAIC(x, y) || (zr >= Nsubs))
            return;

        zx = x;
        zy = y;

        draw_cross( w, x, y);

        if (Nsubs >= 2) {
            draw_cross( subset, (int)(((float)(incr * xr) / zoom) * localzoom), (int)(((float)(incr * yr) / zoom) * localzoom));

            if (zr != prev_zr) {
                prev_zr = zr;
                Z = zr;
                if (Nsubs >= 2)
                    tics[0].x = 20 + (specwidth - 40 - ticwidth) * ((float)Z / (Nsubs - 1));
                else
                    tics[0].x = 20;
                change_pixmap( Z);
            }
        }

        param( incr * xr / zoom, (npix[1] - 1 - incr * yr / zoom), zr, 1);

        if (Nsubs >= 2) {
            for (z = 0; z < Nsubs; z++) {
                /* Between () to be correctly evaluated */
                f = *(F_ADDR(incr * xr / zoom, (npix[1] - 1 - incr * yr / zoom), z));

                if (f == Blank)
                    f = clip[0];

                f = min( clip[1], max( clip[0], scale * f));

                sp[2 * z].y = (specheight - 40) * (1 - (f - clip[0]) / (clip[1] - clip[0])) + 20;
                sp[2 * z + 1].y = sp[2 * z].y;
            }
        }
    }

    else {
        if ((w == subset) && (subpixmap[0] == 0)) {
            if ((x < xoffset) || (x >= xoffset + sizex) || (y < yoffset) || (y >= yoffset + sizey))
                return;
            else {
                zx = POSX(x - xoffset, Z);
                zy = POSY(y - yoffset, Z);

                draw_cross( radec, zx, zy);

                xr = ((float)(incr * (x - xoffset)) / zoom) * localzoom;
                yr = ((float)(incr * (y - yoffset)) / zoom) * localzoom;
                draw_cross( subset, xr, yr);     /* integmean not subset ... */
                param( incr * (x - xoffset) / zoom, (npix[1] - 1 - incr * (y - yoffset) / zoom), Z, 1);
                for (z = 0; z < Nsubs; z++) {
                    /* Between () to be correctly evaluated */
                    f = *(F_ADDR(incr * (x - xoffset) / zoom, (npix[1] - 1 - incr * (y - yoffset) / zoom), z));
                    if (f == Blank)
                        f = clip[0];
                    f = min( clip[1], max( clip[0], scale * f));
                    sp[2 * z].y = (specheight - 40) * (1 - (f - clip[0]) / (clip[1] - clip[0])) + 20;
                    sp[2 * z + 1].y = sp[2 * z].y;
                }
            }
        } else {
            xr = x / localzoom;
            yr = npix[1] - 1 - y / localzoom;

            draw_cross( w, x, y);

            zx = POSX((int)((float)zoom * ((float)x / localzoom) / incr), Z);
            zy = POSY((int)((float)zoom * ((float)y / localzoom) / incr), Z);

            draw_cross( radec, zx, zy);


            param( xr, yr, Z, 1);
            for (z = 0; z < Nsubs; z++) {
                f = *(F_ADDR(xr, yr, z));
                if (f == Blank)
                    f = clip[0];
                f = min( clip[1], max( clip[0], scale * f));
                sp[2 * z].y = (specheight - 40) * (1 - (f - clip[0]) / (clip[1] - clip[0])) + 20;
                sp[2 * z + 1].y = sp[2 * z].y;
            }
        }
    }

    if (Nsubs >= 2)
        draw_spec( spectre_w, sp, clip[0], clip[1]);

    if ((lotofpixels != NULL) && (zoomshell == NULL))   /* && 
                                                           (zx>=32/factor) && ((zy+voffset)>=(32/factor)) &&
                                                           (zx<pixmapdim[0]-32/factor) && 
                                                           ((zy+voffset)<(rows*sizey-32/factor))) */
        XPutImage( display, XtWindow( small_w), gc, hugeimage, factor * zx - 32, factor * (zy + voffset) - 32, 0, 0, 64, 64);

    if ((lotofpixels != NULL) && (zoomshell != NULL)) { /* && 
                                                           (zx>=zoom_width/(2*factor)) && 
                                                           ((zy+voffset)>=zoom_height/(2*factor)) &&
                                                           (zx<pixmapdim[0]-zoom_width/(2*factor)) && 
                                                           ((zy+voffset)<(rows*sizey-zoom_height/(2*factor)))) */
        XPutImage( display, XtWindow( zoom_w), gc, hugeimage,
                  factor * zx - zoom_width / 2, factor * (zy + voffset) - zoom_height / 2, 0, 0, zoom_width, zoom_height);
        DRAWCROSS(zoom_w, zoom_width / 2, zoom_height / 2);
    }
}

void spectrum_input( Widget w, XEvent * event)
{
    int j, x, y;
    static int press1 = 0, press2 = 0, mot = 0, in = 1;
    float *ngon;
    XPoint_list xpl;

    int d, D, n, N;
    static int xr, yr;          /* reference coordinates (BUTTON PRESS event) */
    static int prev_x, prev_y;  /* previous pointer relative position */
    static int xs[4], ys[4];    /* box corners */
    int rx, ry, width, height;

    switch (event->type) {
    case EnterNotify:
        in = 1;
        break;

    case ButtonPress:
        x = event->xbutton.x;
        y = event->xbutton.y;

        switch (event->xbutton.button) {
        case Button1:
            x = event->xbutton.x;
            y = event->xbutton.y;
            mot = 0;
            press1 = 1;
            kill_movie( );
            new_spec( w, x, y);

            break;

        case Button2:
            if (cursor_mode == SUBAREA) {
                if ((subpixmap[0] == 0) && (w == subset)) {
                    XBell( display, 0);
                    return;
                }
                press2 = 1;
                kill_movie( );
                new_spec( w, x, y);

                xr = x;
                yr = y;

                if (!edit) {
                    /* initialize previous position */
                    prev_x = x;
                    prev_y = y;
                    prev_rx = x;
                    prev_ry = y;
                    prev_width = 0;
                    prev_height = 0;
                }

                else {
                    /* find new corner */
                    D = 1E+05;
                    for (n = 0; n < 4; n++) {
                        d = sqrt( (float)((ys[n] - yr) * (ys[n] - yr)
                                         + (xs[n] - xr) * (xs[n] - xr)));
                        if (d < D) {
                            D = d;
                            N = n;
                        }
                    }

                    switch (N) {
                    case 0:
                        xr = xs[2];
                        yr = ys[2];
                        break;
                    case 1:
                        xr = xs[3];
                        yr = ys[3];
                        break;
                    case 2:
                        xr = xs[0];
                        yr = ys[0];
                        break;
                    case 3:
                        xr = xs[1];
                        yr = ys[1];
                        break;
                    }
                    /* re-initialize previous position */
                    prev_x = xs[N];
                    prev_y = ys[N];
                }
            }
            break;
        }
        break;

    case MotionNotify:
        x = event->xmotion.x;
        y = event->xmotion.y;

        if (!in)
            return;


        if ((press2 == 1) && (cursor_mode == SUBAREA)) {
            new_spec( w, x, y);

            rx = min( xr, x);
            ry = min( yr, y);

            width = abs( x - xr);
            height = abs( y - yr);

            if (subpixmap[0] == 0) {
                XDrawRectangle( display, XtWindow( subset), gcx,
                               xoffset + zoom * ((float)prev_rx / localzoom) / incr,
                               yoffset + zoom * ((float)prev_ry / localzoom) / incr,
                               zoom * ((float)prev_width / localzoom) / incr, zoom * ((float)prev_height / localzoom) / incr);
                XDrawRectangle( display, XtWindow( subset), gcx,
                               xoffset + zoom * ((float)rx / localzoom) / incr,
                               yoffset + zoom * ((float)ry / localzoom) / incr,
                               zoom * ((float)width / localzoom) / incr, zoom * ((float)height / localzoom) / incr);
            } else {
                XDrawRectangle( display, XtWindow( subset), gcx, prev_rx, prev_ry, prev_width, prev_height);
                XDrawRectangle( display, XtWindow( subset), gcx, rx, ry, width, height);
            }
            XDrawRectangle( display, XtWindow( integmean), gcx, prev_rx, prev_ry, prev_width, prev_height);
            XDrawRectangle( display, XtWindow( integmean), gcx, rx, ry, width, height);

            prev_x = x;
            prev_y = y;
            prev_rx = rx;
            prev_ry = ry;
            prev_width = width;
            prev_height = height;
            return;
        }

        if (press1) {
            mot = 1;
            new_spec( w, x, y);
        }
        break;

    case ButtonRelease:

        x = event->xbutton.x;
        y = event->xbutton.y;

        switch (event->xbutton.button) {

        case Button1:
            press1 = 0;
            if ((cursor_mode != SPECTRUM) || (strcmp( XtName( w), "INTEGMEAN") != 0))
                return;
            if (!mot) {
                if (rec) {
                    while (top != NULL) {
                        xpl = top;
                        top = top->next;
                        free( xpl);
                    }
                    nsum = 0;
                    rec = 0;
                }
                xpl = (XPoint_list) malloc( sizeof( struct XPoint_item_list));
                xpl->xp.x = x;
                xpl->xp.y = y;
                xpl->next = top;
                top = xpl;
                nsum++;
                if (nsum == 1)
                    queue = xpl;
                redraw_in_integmean( );
            }
            break;

        case Button2:

            x = event->xbutton.x;
            y = event->xbutton.y;

            if ((cursor_mode == SUBAREA) && (press2 == 1)) {
                xs[0] = xr;
                ys[0] = yr;
                xs[1] = prev_x;
                ys[1] = yr;
                xs[2] = prev_x;
                ys[2] = prev_y;
                xs[3] = xr;
                ys[3] = prev_y;
                edit = 1;
                press2 = 0;
            }

            if ((cursor_mode == SPECTRUM) && (strcmp( XtName( w), "INTEGMEAN") == 0)) {
                if ((nsum == 0) || (rec == 1))
                    return;

                xpl = top;
                top = top->next;
                free( xpl);
                nsum--;
                redraw_in_integmean( );
            }
            break;

        case Button3:
            if ((cursor_mode != SPECTRUM) || (strcmp( XtName( w), "INTEGMEAN") != 0))
                return;
            if ((rec == 1) || (nsum <= 2))
                return;

            xpl = (XPoint_list) malloc( sizeof( struct XPoint_item_list));
            xpl->xp.x = queue->xp.x;
            xpl->xp.y = queue->xp.y;
            xpl->next = top;
            top = xpl;

            redraw_in_integmean( );

            ngon = (float *)malloc( 2 * nsum * sizeof( float));

            xpl = top;
            j = 0;
            while (xpl->next != NULL) {
                ngon[2 * j] = (float)(xpl->xp.x / localzoom + 1);
                ngon[2 * j + 1] = (float)(npix[1] - 1 - xpl->xp.y / localzoom + 1);
                xpl = xpl->next;
                j++;

            }
            rec = 1;

            spectre( &nsum, ngon, s1);

            calc_integspec( s1);
            draw_spec( integspectre, isp, minintspec, maxintspec);
            break;

        }
        break;

    case LeaveNotify:
        in = 0;
        break;
    }
}

void new_tics( int x, int y)
{
    int d, D, n;
    int s1, s2;
    static int N;

    if (!drag) {
        D = 1E+05;
        for (n = 0; n < 3; n++) {
            d = sqrt( (float)(tics[n].x - x) * (tics[n].x - x) + (float)(tics[n].y - y) * (tics[n].y - y));

            if (d < D) {
                D = d;
                N = n;
            }
        }
        drag = 1;

    }

    switch (N) {
    case 0:
        Z = (x - 20) / ticwidth;
        Z = min( max( 0, Z), Nsubs - 1);
        tics[0].x = 20 + ticwidth * Z;

        if (prev_Z != Z) {
            prev_Z = Z;
            change_pixmap( Z);
            change_Z();
            draw_cross( radec,
                       POSX((int)((float)zoom * ((float)show_zposx / localzoom) / incr), Z),
                       POSY((int)((float)zoom * ((float)show_zposy / localzoom) / incr), Z));

        }
        return;

    case 1:
        s1 = (x - 20) / ticwidth;
        s1 = min( max( 0, s1), Nsubs - 1);
        s2 = sub2;
        sub1 = min( s1, s2);
        sub2 = max( s1, s2);
        sprintf( dumstr, "%s%d %s%d %s%d", "Z=", (Z + firstsub), "Z1=", (sub1 + firstsub), "Z2=", (sub2 + firstsub));
        XmTextSetString( zvalues, dumstr);
        tics[1].x = 20 + ticwidth * sub1;
        tics[2].x = 20 + ticwidth * sub2;

        ERRASETIC(20, specheight - 19, specwidth - 20, 10);
        DRAWTIC(tics[1].x, specheight - 19, ticwidth, 10);
        DRAWTIC(tics[2].x, specheight - 19, ticwidth, 10);

        return;

    case 2:
        s2 = (x - 20) / ticwidth;
        s2 = min( max( 0, s2), Nsubs - 1);
        s1 = sub1;
        sub1 = min( s1, s2);
        sub2 = max( s1, s2);
        sprintf( dumstr, "%s%d %s%d %s%d", "Z=", (Z + firstsub), "Z1=", (sub1 + firstsub), "Z2=", (sub2 + firstsub));
        XmTextSetString( zvalues, dumstr);
        tics[1].x = 20 + ticwidth * sub1;
        tics[2].x = 20 + ticwidth * sub2;

        ERRASETIC(20, specheight - 19, specwidth - 20, 10);
        DRAWTIC(tics[1].x, specheight - 19, ticwidth, 10);
        DRAWTIC(tics[2].x, specheight - 19, ticwidth, 10);
        return;
    }
}

void set_scale( Widget w, XEvent * event, String * params, Cardinal num_params)
{
    int pos[2];
    char dum[80];

    switch (event->type) {
    case ButtonPress:
        switch (event->xbutton.button) {
        case Button1:
            scale = scale * 2.;
            break;
        case Button2:
            scale = scale / 2.;
            break;
        }
        break;
    }

    get_crosspos( pos);
    spec_modify( pos[0], pos[1]);

    sprintf( dum, "Scale : x%4.2f", scale);

    XSetForeground( display, gc, g_vc.black_pixel);
    XFillRectangle( display, XtWindow( w), gc, 0, 0, specwidth, 15);
    XSetForeground( display, gc, g_vc.white_pixel);

    XDrawString( display, XtWindow( w), gc, 10, 10, dum, strlen( dum));


}


void force_tics( )
{
    drag = 0;

    if ((prev_sub1 != sub1) || (prev_sub2 != sub2)) {
        prev_sub1 = sub1;
        prev_sub2 = sub2;
    }
    calc_integmean( sub1, sub2);
    redraw_in_integmean( );
}

void set_tics( Widget w, XEvent * event, String * params, Cardinal num_params)
{
    int x, y;

    switch (event->type) {
    case ButtonPress:
        switch (event->xbutton.button) {
        case Button1:
            x = event->xbutton.x;
            y = event->xbutton.y;
            kill_movie( );
            new_tics( x, y);
            break;
        }
        break;


    case MotionNotify:
        x = event->xmotion.x;
        y = event->xmotion.y;

        new_tics( x, y);
        break;

    case ButtonRelease:
        /* calc new integrated spectrum always, even if subsets have not changed */
        drag = 0;

        if ((prev_sub1 != sub1) || (prev_sub2 != sub2)) {
            prev_sub1 = sub1;
            prev_sub2 = sub2;
        }
        calc_integmean( sub1, sub2);
        redraw_in_integmean( );
        break;
    }
}

int GET_CURZ()
{
    return (Z);
}

XPoint_list get_pol_coord( )
{
    return (top);
}

int get_nsum( )
{
    if (rec)
        return (nsum);
    else
        return (0);
}

void get_relative_sub( int sub[2])
{
    sub[0] = sub1;
    sub[1] = sub2;
}

void get_planes( int sub[3], float velo[2])
{
    double uc[3];
    char chainx[80], chainy[80], chainz[80], chainv[80];
    int x = 1, y = 1;

    sub[0] = Z + 1;
    sub[1] = sub1 + 1;
    sub[2] = sub2 + 1;

    phys_coord( &x, &y, &sub[1], uc, chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

    velo[0] = (float)atof( chainz);

    phys_coord( &x, &y, &sub[2], uc, chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

    velo[1] = (float)atof( chainz);
}

