/* InspectAxes.m		by Paul Kunz	December 1991
 * Controls the Axes of a Plot object
 *
 * Copyright (C)  1991  The Board of Trustees of
 * The Leland Stanford Junior University.  All Rights Reserved.
 */
 
#import "InspectAxes.h"

const char InspectAxes_h_rcsid[] = INSPECTAXES_H_ID;
const char InspectAxes_m_rcsid[] = "$Id: InspectAxes.m,v 1.15 1992/04/05 18:19:44 pfkeb Rel $";

#import <appkit/Application.h>
#import <appkit/Button.h>
#import <appkit/ButtonCell.h>
#import <appkit/Form.h>
#import <appkit/Matrix.h>
#import <appkit/SavePanel.h>

#import "DrawDocument.h"
#import "FineSlider.h"
#import "HDraw.h"
#import "HGraphicView.h"
#import "Plot.h"
#import "NewInspector.h"

#import <c.h>
#import <string.h>
#import <float.h>
 /*
  * bug fix: FLT_MIN=1.17549435e-38 is actually 0
  */
#undef FLT_MIN
#define FLT_MIN 2e-38f

#define RB_HIGH 0
#define RB_LOW 1
#define RB_NUM 2
#define RB_OFF 3

#define MAXBINS 500

#define OFF 0
#define ON  1

#define SCALE_FACTOR 5.0

@implementation InspectAxes

- initInspFor:aDraw
{
    int		i, count;
	
    [super initInspFor:aDraw];
    
    [NXApp loadNibSection:"InspectAxes.nib" owner:self
           withNames:NO fromZone:[self zone]];
 /*
  * we've got to do the following nonsense because can't stretch out spacing
  * of slider from IB 
  */
    rbXSlider[0] = rbXSlider0;
    rbXSlider[1] = rbXSlider1;
    rbXSlider[2] = rbXSlider2;
    rbXSlider[3] = rbXSlider3;
    rbYSlider[0] = rbYSlider0;
    rbYSlider[1] = rbYSlider1;
    rbYSlider[2] = rbYSlider2;
    rbYSlider[3] = rbYSlider3;
  /*
   * set the scaleFactor for FineSlider
   */
    count = [rbXForm cellCount];
    for ( i = 0; i <= count; i++ ) {
        [rbXSlider[i] setScaleFactor:SCALE_FACTOR];
    }
    count = [rbYForm cellCount];
    for ( i = 0; i < count; i++ ) {
        [rbYSlider[i] setScaleFactor:SCALE_FACTOR];
    }
    numLimitCheck = [limitCheckButton state];
  /*
   * set up one of the display options in the display options box
   */

   [theInspector addView:[contentBox contentView]
                 withName:"Axes Selection" withSupervisor:self];

    currentDim = 1;
    return self;
}
- limitCheckType:sender
{
    numLimitCheck = [limitCheckButton state];
    return self;
}
- (int) limitCheck:(int) nbins against:(int)maxbins
{
    int		irc;
    static int prevnbins=0;
        
    if ( numLimitCheck == OFF )  return nbins;
    
    if ( nbins > maxbins && numLimitCheck == ON ) {
        if (nbins == prevnbins) { 
	    	nbins = maxbins;
		return nbins;     /* ignore double events */
    	}
	prevnbins = nbins;
	irc = NXRunAlertPanel( "Alert",
		    "Greater than %d bins may cause performace problems",
		    "Cancel", "Proceed", NULL, maxbins );
	if ( irc == NX_ALERTDEFAULT ) {
	    nbins = maxbins;
	} else {
	    numLimitCheck = OFF;
	    [ limitCheckButton setState: OFF ];
	}
    }
    return nbins;
}


- rebinForm:sender
{
    NXPoint             p;
    float               thigh, tlow, toff, range;
    int                 sel, tnbins;
    BOOL             	re_displayX = NO;
    BOOL             	re_displayY = NO;
    BOOL                logAxis, checkBins;
    display             adisplay = [firstPlot histDisplay];

    sel = [rbXForm selectedIndex];

    logAxis = h_getLogAxis(adisplay, XAXIS);
    checkBins = graphtype == HISTOGRAM || graphtype == LEGOPLOT
	 || graphtype == COLORPLOT;

    if (checkBins) {
	tnbins = [rbXForm intValueAt:RB_NUM];
	tnbins = MAX(tnbins, 2);
	tnbins = [self limitCheck:tnbins against:MAXBINS];
    } else
	tnbins = 50;

    thigh = [rbXForm floatValueAt:RB_HIGH];
    tlow = [rbXForm floatValueAt:RB_LOW];

    if (logAxis && tlow <= 0.0)
	tlow = 2 * FLT_MIN;

    if (tlow >= thigh) {
	if (checkBins)
	    thigh = tlow + xw;
	else
	    thigh = tlow * (1.0 + 2.0 * FLT_EPSILON);
    }
    range = thigh - tlow;
    xw = range / tnbins;

    if ((xh != thigh) || (sel == RB_HIGH)) {
	re_displayX = YES;
	xh = thigh;
	[rbXForm setFloatValue:xh at:RB_HIGH];
	[rbXSlider[RB_HIGH] setMinValue:(double)(tlow + xw)];
	[rbXSlider[RB_HIGH] setMaxValue:(double)(thigh + range)];
	[rbXSlider[RB_HIGH] setFloatValue:xh];
    }
    if ((xl != tlow) || (sel == RB_LOW)) {
	re_displayX = YES;
	xl = tlow;
	[rbXForm setFloatValue:xl at:RB_LOW];
	if (logAxis) {
	    if (tlow <= range) {
		[rbXSlider[RB_LOW] setMinValue:(double)tlow / 10.0];
		[rbXSlider[RB_LOW] setMaxValue:(double)tlow * 10.0];
	    } else {
		[rbXSlider[RB_LOW] setMinValue:(double)(tlow - range)];
		[rbXSlider[RB_LOW] setMaxValue:(double)(thigh - xw)];
	    }

	} else {
	    [rbXSlider[RB_LOW] setMinValue:(double)(tlow - range)];
	    [rbXSlider[RB_LOW] setMaxValue:(double)(thigh - xw)];
	}
	[rbXSlider[RB_LOW] setFloatValue:xl];
    }
    if ((tnbins != nx) || (sel == RB_NUM)) {
	if (checkBins) {
	    re_displayX = YES;
	    nx = tnbins;
	    [rbXForm setIntValue:nx at:RB_NUM];
	    [rbXSlider[RB_NUM] setMinValue:2.];
	    [rbXSlider[RB_NUM] setMaxValue:(double)(2 * nx)];
	    [rbXSlider[RB_NUM] setIntValue:nx];
	}
    }
    toff = [rbXForm floatValueAt:RB_OFF];
    if (toff != xoff) {
	re_displayX = YES;
	toff = MIN(toff, 1.0);
	toff = MAX(toff, -1.0);
	xh -= xoff * xw;
	xl -= xoff * xw;
	xoff = toff;
	xh += xoff * xw;
	xl += xoff * xw;
	[rbXForm setFloatValue:xoff at:RB_OFF];
	[rbXSlider[RB_OFF] setFloatValue:xoff];
	[rbXForm setFloatValue:xh at:RB_HIGH];
	[rbXForm setFloatValue:xl at:RB_LOW];
	[rbXSlider[RB_HIGH] setFloatValue:xh];
	[rbXSlider[RB_LOW] setFloatValue:xl];
    }
    if ( re_displayX == YES ) {
	[graphicView graphicsPerform:@selector(setNumBinsForAxisX:)
				with:(id)&nx andDraw:NO];
	p.x = xl;
	p.y = xh;
	[graphicView graphicsPerform:@selector(setRangeForAxisX:)
				with:(id)&p andDraw:YES];
	[autoScaleXbutton setState:NO];
	if (currentDim == 1 && [autoScaleYbutton state] == YES) {
	    [self rebinAutoYRange];
	}
    }
    sel = [rbYForm selectedIndex];

    checkBins = graphtype == LEGOPLOT || graphtype == COLORPLOT;
    logAxis = h_getLogAxis(adisplay, YAXIS);

    if (checkBins) {
	tnbins = [rbYForm intValueAt:RB_NUM];
	tnbins = MAX(tnbins, 2);
	tnbins = [self limitCheck:tnbins against:MAXBINS];
    } else {
	tnbins = 50;
    }

    thigh = [rbYForm floatValueAt:RB_HIGH];
    tlow = [rbYForm floatValueAt:RB_LOW];

    if (logAxis && tlow <= 0.0)
	tlow = 2 * FLT_MIN;

    if (tlow >= thigh) {
	if (checkBins)
	    thigh = tlow + yw;
	else
	    thigh = tlow * (1.0 + 2.0 * FLT_EPSILON);
    }
    range = thigh - tlow;
    yw = range / tnbins;

    if ((yh != thigh) || (sel == RB_HIGH)) {
	re_displayY = YES;
	if ( yh != thigh ) {
	    [autoScaleYbutton setState:NO];
	}
	yh = thigh;
	[rbYForm setFloatValue:yh at:RB_HIGH];
	[rbYSlider[RB_HIGH] setMinValue:(double)(tlow + yw)];
	[rbYSlider[RB_HIGH] setMaxValue:(double)(yh + range)];
	[rbYSlider[RB_HIGH] setFloatValue:yh];
    }
    if ((yl != tlow) || (sel == RB_LOW)) {
	re_displayY = YES;
	if ( yl != tlow ) {
	    [autoScaleYbutton setState:NO];
	}
	yl = tlow;
	[rbYForm setFloatValue:yl at:RB_LOW];
	if (logAxis) {
	    if (tlow <= range) {
		[rbYSlider[RB_LOW]
		 setMinValue:(double)tlow / 10.0];
		[rbYSlider[RB_LOW]
		 setMaxValue:(double)tlow * 10.0];
	    } else {
		[rbYSlider[RB_LOW] setMinValue:(double)(tlow - range)];
		[rbYSlider[RB_LOW] setMaxValue:(double)(thigh - yw)];
	    }
	} else {
	    [rbXSlider[RB_LOW] setMinValue:(double)(tlow - range)];
	    [rbXSlider[RB_LOW] setMaxValue:(double)(thigh - yw)];
	}
	[rbYSlider[RB_LOW] setFloatValue:yl];
    }
    if ((ny != tnbins) || (sel == RB_NUM)) {
	if (checkBins) {
	    re_displayY = YES;
	    if ( ny != tnbins ) {
		[autoScaleYbutton setState:NO];
	    }
	    ny = tnbins;
	    [rbYForm setIntValue:ny at:RB_NUM];
	    [rbYSlider[RB_NUM] setMinValue:2.];
	    [rbYSlider[RB_NUM] setMaxValue:(double)(2 * ny)];
	    [rbYSlider[RB_NUM] setIntValue:ny];
	}
    }
    toff = [rbYForm floatValueAt:RB_OFF];
    if (toff != yoff) {
	re_displayY = YES;
	toff = MIN(toff, 1.0);
	toff = MAX(toff, -1.0);
	yh -= yoff * yw;
	yl -= yoff * yw;
	if ( yoff != toff ) {
	    [autoScaleYbutton setState:NO];
	}
	yoff = toff;
	yh += yoff * yw;
	yl += yoff * yw;
	[rbYForm setFloatValue:yoff at:RB_OFF];
	[rbYSlider[RB_OFF] setFloatValue:yoff];
	[rbYForm setFloatValue:yh at:RB_HIGH];
	[rbYForm setFloatValue:yl at:RB_LOW];
	[rbYSlider[RB_HIGH] setFloatValue:yh];
	[rbYSlider[RB_LOW] setFloatValue:yl];
    }
    if ( re_displayY == YES ) {
	[graphicView graphicsPerform:@selector(setNumBinsForAxisY:)
				with:(id)&ny andDraw:NO];
	p.x = yl;
	p.y = yh;
	[graphicView graphicsPerform:@selector(setRangeForAxisY:)
				with:(id)&p andDraw:YES];
    }
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}
- rebin:sender
{
     NXPoint p;
     float x, y, toff, txl, txh, tyl, tyh, delta, deltaoff;
     float xplo, xphi, yplo, yphi;
     int                 	i;
     int                 	slider_index;
     BOOL             	re_displayX = NO;
     BOOL             	re_displayY = NO;
     BOOL logAxis, checkBins;
     display adisplay = [firstPlot histDisplay];
     BOOL zpmode;
     
     /*
      * following are used to skip processing of multiple 
      * interrupts with values unchanged
      */
     static int		prevXIndex = -1, prevYIndex = -1;
     static float	prevXValue = 999.999, prevYValue = 999.999;
     
     slider_index = -1;
     for (i = 0; i < 4; i++) {
	  if (sender == rbYSlider[i]) {
	       slider_index = i;
	       break;
	  }
     }

     y = [sender floatValue];
     h_getRange(adisplay, YAXIS, &yplo, &yphi );
     zpmode = [zpYbutton state];
     if  ( (i < 4) && ((slider_index != prevYIndex) || (y != prevYValue))) {

	  prevYIndex = slider_index;
	  prevYValue = y;

	  checkBins = graphtype == LEGOPLOT || graphtype == COLORPLOT;
	  logAxis = h_getLogAxis(adisplay, YAXIS);
	  
	  switch (slider_index) {
	  case RB_HIGH:
	       if (logAxis && y<=0.0) y = 2*FLT_MIN;
	       if (checkBins)
	       {
		    tyh = MAX(y, yl + 2 * yw);
		    delta = tyh - yh;
		    if (ABS(delta) > yw)
		    {
			 i = (delta > 0) ? delta / yw : delta / yw + 1;
			 ny = ny + i;
			 if ( zpmode ) ny = ny + i;
			 ny = [self limitCheck:ny against: MAXBINS ];
			 yh = yh + i * yw;
			 if ( zpmode ) yl = yl - i*yw;
			 yh = MAX(yh, yl + yw);
			 re_displayY = YES;
		    }
	       }
	       else 
	       {
		    yh = MAX(y,yl*(1.0+2.0*FLT_EPSILON));
		    if (zpmode) yl = yplo - (yh - yphi);
		    re_displayY = YES;
	       }
	       if (re_displayY)
	       {
		    [rbYForm setFloatValue:yh at:RB_HIGH];
		    if (checkBins) {
			 [rbYForm setIntValue:ny at:RB_NUM];
			 [rbYSlider[RB_NUM] setIntValue:ny];
		    }
	       }
	       break;
	  case RB_LOW:
	       if (logAxis && y<=0.0) y = 2*FLT_MIN;
	       if (checkBins)
	       {
		    tyl = MIN(y, yh - 2 * yw);
		    delta = yl - tyl;
		    if (ABS(delta) > yw) {
			 i = delta / yw;
			 if ( !zpmode ) {
			     ny = ny + i;
			     ny = [self limitCheck:ny against: MAXBINS ];
			 }
			 yl = yl - i * yw;
			 if (zpmode) yh = yh - i*yw;
			 yl = MIN(yl, yh - yw);
			 re_displayY = YES;
		    }
	       }
	       else
	       {
		    yl = MIN(y,yh*(1.0-2.0*FLT_EPSILON));
		    if ( zpmode ) yh = yphi + ( yl - yplo );
		    re_displayY = YES;
	       }
	       if (re_displayY)
	       {
		    [rbYForm setFloatValue:yl at:RB_LOW];
		    if (checkBins) {
			 [rbYForm setIntValue:ny at:RB_NUM];
			 [rbYSlider[RB_NUM] setIntValue:ny];
		    }
	       }
	       break;
	  case RB_NUM:
	       if (checkBins)
	       {
		    ny = [rbYSlider[RB_NUM] intValue];
		    ny = [self limitCheck:ny against: MAXBINS ];
		    [rbYForm setIntValue:ny at:RB_NUM];
		    re_displayY = YES;
	       }
	       break;
	  case RB_OFF:
	       toff = y;		/* slider value */
	       deltaoff = toff - yoff; /* diff from previous value of slider */
	       yl = yl + yw * deltaoff; /* adjust low by difference */
	       yh = yh + yw * deltaoff; /* adjust high by same difference */
	       yoff = toff;	       /* set previous value = current value */
	       [rbYForm setFloatValue:yh at:RB_HIGH];
	       [rbYSlider[RB_HIGH] setFloatValue:yh];
	       [rbYForm setFloatValue:yl at:RB_LOW];
	       [rbYSlider[RB_LOW] setFloatValue:yl];
	       [rbYForm setFloatValue:yoff at:RB_OFF];
	       re_displayY = YES;
	       break;
	  }	/* end switch ySlider */
	  if (re_displayY == YES) {
	       [graphicView
	   graphicsPerform:@selector(setNumBinsForAxisY:)
		with :(id)&ny andDraw:NO];
	       p.x = yl;
	       p.y = yh;
	       [graphicView graphicsPerform:@selector(setRangeForAxisY:)
		with :(id)&p andDraw:YES];
	       if (zpmode) {
	           if ( slider_index == 0 ) {
		       [rbYForm setFloatValue:yl at:1];
		       [rbYSlider[1] setFloatValue:yl];
		   } else if ( slider_index == 1 ) {
		       [rbYForm setFloatValue:yh at:0];
		       [rbYSlider[0] setFloatValue:yh];
		   }
	       }
	       [ autoScaleYbutton setState:NO];
	       yw = (yh - yl) / (ny);
	  }
     }

     slider_index = -1;
     for (i = 0; i < 4; i++) {
	  if (sender == rbXSlider[i]) {
	       slider_index = i;
	       break;
	  }
     }

     x = [sender floatValue];
     h_getRange(adisplay, XAXIS, &xplo, &xphi );
     zpmode = [zpXbutton state];
     if  (( i < 4) && ((slider_index != prevXIndex) || (x != prevXValue))) {
	  prevXIndex = slider_index;
	  prevXValue = x;

	  logAxis = h_getLogAxis(adisplay, XAXIS);
	  checkBins = graphtype == HISTOGRAM || graphtype == LEGOPLOT
	       || graphtype == COLORPLOT;
	  
	  switch (slider_index) {
	  case RB_HIGH:
	       if (logAxis && x<=0.0) x = 2*FLT_MIN;
	       if (checkBins)
	       {
		    txh = MAX(x, xl + 2 * xw);
		    delta = txh - xh;
		    if (ABS(delta) > xw) {
			 i = (delta > 0) ? delta / xw : delta / xw + 1;
			 nx = nx + i;
			 if (zpmode) nx = nx + i;
			 nx = [self limitCheck:nx against: MAXBINS ];
			 xh = xh + i * xw;
			 if (zpmode) xl = xl - i*xw;
			 xh = MAX(xh, xl + xw);
			 re_displayX = YES;
		    }
	       }
	       else
	       {
		    xh = MAX(x,xl*(1.0+2.0*FLT_EPSILON));
		    re_displayX = YES;
		    if (zpmode ) {
			xl = xplo - (xh - xphi);
		    }
	       }
	       if (re_displayX)
	       {
		    [rbXForm setFloatValue:xh at:RB_HIGH];
		    [rbXForm setIntValue:nx at:RB_NUM];
		    [rbXSlider[RB_NUM] setIntValue:nx];
	       }
	       break;
	  case RB_LOW:
	       if (logAxis && x<=0.0) x = 2*FLT_MIN;
	       if (checkBins)
	       {
		    txl = MIN(x, xh - 2 * xw);
		    delta = xl - txl;
		    if (ABS(delta) > xw) {
			 i = delta / xw;
			 if (!zpmode) {
			     nx = nx + i;
			     nx = [self limitCheck:nx against: MAXBINS ];
			 }
			 xl = xl - i * xw;
			 if (zpmode) xh = xh - i * xw;
			 xl = MIN(xl, xh - xw);
			 re_displayX = YES;
		    }
	       }
	       else
	       {
		    xl = MIN(x,xh*(1.0-2.0*FLT_EPSILON));
		    if ( zpmode ) xh = xphi + ( xl - xplo );
		    re_displayX = YES;
	       }
	       if (re_displayX)
	       {
		    [rbXForm setFloatValue:xl at:RB_LOW];
		    [rbXForm setIntValue:nx at:RB_NUM];
		    [rbXSlider[RB_NUM] setIntValue:nx];
	       }
	       break;
	  case RB_NUM:
	       if (checkBins)
	       {
		    nx = [rbXSlider[RB_NUM] intValue];
		    nx = [self limitCheck:nx against: MAXBINS ];
		    [rbXForm setIntValue:nx at:RB_NUM];
		    re_displayX = YES;
	       }
	       break;
	  case RB_OFF:
	       toff = x;		/* slider value */
	       deltaoff = toff - xoff; /* diff from previous value of slider */
	       xl = xl + xw * deltaoff;/* adjust low by difference */
	       xh = xh + xw * deltaoff;/* adjust high by same difference */
	       xoff = toff;	      /* set previous value = current value */
	       [rbXForm setFloatValue:xh at:RB_HIGH];
	       [rbXSlider[RB_HIGH] setFloatValue:xh];
	       [rbXForm setFloatValue:xl at:RB_LOW];
	       [rbXSlider[RB_LOW] setFloatValue:xl];
	       [rbXForm setFloatValue:xoff at:RB_OFF];
	       re_displayX = YES;
	       break;
	  }	/* end switch xSlider */
	  if (re_displayX == YES)
	  {
	       [graphicView graphicsPerform:@selector(setNumBinsForAxisX:)
		with :(id)&nx andDraw:NO];
	       p.x = xl;
	       p.y = xh;
	       [graphicView graphicsPerform:@selector(setRangeForAxisX:)
		with :(id)&p andDraw:YES];
	       if (zpmode) {
	           if ( slider_index == 0 ) {
		       [rbXForm setFloatValue:xl at:1];
		       [rbXSlider[1] setFloatValue:xl];
		   } else if ( slider_index == 1 ) {
		       [rbXForm setFloatValue:xh at:0];
		       [rbXSlider[0] setFloatValue:xh];
		   }
	       }
	       [ autoScaleXbutton setState: NO];
	       xw = (xh - xl) / (nx);
	       if ( currentDim == 1 &&
		   [autoScaleYbutton state] == YES ) {
		    [self rebinAutoYRange ];
	       }
	  }
     }
     if ((re_displayX == YES) || (re_displayY == YES)) {
	  [[[graphicView window] flushWindow] makeKeyWindow];
     }
     return self;
}

- rebinAutoYRange
{
	NXPoint	p;
    	float	yrange;
    
    	ny = [firstPlot numBinsForAxis:YAXIS];
    	[ firstPlot getRangeForAxisY: &p ];
    	yl = p.x;
    	yh = p.y;
    	yrange = yh - yl;
    	yw = (yh - yl) / (ny);
	[rbYForm setFloatValue:yh at:RB_HIGH];
   	[rbYSlider[RB_HIGH] setMinValue:(double) (yl + yw)];
    	[rbYSlider[RB_HIGH] setMaxValue:(double) (yh + yrange)];
    	[rbYSlider[RB_HIGH] setFloatValue:yh];

	[rbYForm setFloatValue:yl at:RB_LOW];
    	[rbYSlider[RB_LOW]  setMinValue:(double) (yl - yrange)];
   	[rbYSlider[RB_LOW]  setMaxValue:(double) (yh - yw)];
    	[rbYSlider[RB_LOW]  setFloatValue:yl];
    
    	return self;
    
}		
 /* called when the AutoScale or logScale button is clicked */
- tupleSetScaleType:sender
{
	SEL		theMethod = 0;
	int		theState;
	
	theState = [sender state];
	
	switch ([sender tag])
	{
		case 0: /* AutoScale X-axis */
			theMethod = @selector(setAutoScaleX:);
			break;
			
		case 1: /* AutoScale Y-axis */
			theMethod = @selector(setAutoScaleY:);
			break;
			
		case 2: /* Log Scale X-axis */
			theMethod = @selector(setLogScaleX:);
			break;
			
		case 3: /* LogScale Y-axis */
			theMethod = @selector(setLogScaleY:);
			break;
	}
	
	[graphicView graphicsPerform:theMethod
		with :(id)&theState andDraw:YES];

	[self setSliders]; /* reset axis slider & form */
	[[graphicView window] flushWindow];
    
	return self;
}
    
 /* Methods supporting updating the Inspector View */
- updateView
{
    if ( !firstPlot ) {
        return self;
    }
    [ self setOptions];
    [ self setSliders];
    return self;
}
- setOptions
{
    display             adisplay = [firstPlot histDisplay];

    graphtype = h_getDispType(adisplay);
    if (graphtype == HISTOGRAM)
	 currentDim = 1;
    else
	 currentDim = 2;

    if ( (graphtype == HISTOGRAM) || ( graphtype == COLORPLOT ) ) {
	[logScaleXbutton setEnabled:NO];
    } else {
	[logScaleXbutton setEnabled:YES];
    }
    if ( graphtype == COLORPLOT ) {
        [logScaleYbutton setEnabled:NO];
    } else {
        [logScaleYbutton setEnabled:YES];
    }
    [autoScaleXbutton setState:h_getAutoScale(adisplay, XAXIS)];
    [autoScaleYbutton setState:h_getAutoScale(adisplay, YAXIS)];
    [logScaleXbutton  setState:h_getLogAxis(adisplay, XAXIS)];
    [logScaleYbutton  setState:h_getLogAxis(adisplay, YAXIS)];

    return self;
}
- setSliders
{
     float               xrange, yrange;
     BOOL logAxis, checkBins;
     display adisplay = [firstPlot histDisplay];
     
     /*
      * Y Axis
      */
     checkBins = graphtype == LEGOPLOT || graphtype == COLORPLOT;
     logAxis = h_getLogAxis(adisplay, YAXIS);
     
     if (checkBins)
     {
	  ny = [firstPlot numBinsForAxis:YAXIS];
	  [rbYForm setIntValue:ny at: RB_NUM];
	  [rbYSlider[RB_NUM] setMinValue:2.];
	  [rbYSlider[RB_NUM] setMaxValue:(double)(2 * ny)];
	  [rbYSlider[RB_NUM] setIntValue:ny];
	  [rbYSlider[RB_NUM] setEnabled:YES];
	  [[rbYForm cellAt:RB_NUM :0] setEnabled:YES];
     }
     else
     {
	  [rbYForm setStringValue:"" at:RB_NUM];
	  [rbYSlider[RB_NUM] setEnabled:NO];
	  [[rbYForm cellAt:RB_NUM :0] setEnabled:NO];
	  ny = 50;
     }
     
     [firstPlot getRangeForAxis:YAXIS low: &yl high: &yh ];
     yrange = yh - yl;
     yw = (yh - yl) / (ny);
     [rbYForm setFloatValue:yh at:RB_HIGH];

     [rbYSlider[RB_HIGH] setMinValue:(double) (yl + yw)];
     [rbYSlider[RB_HIGH] setMaxValue:(double) (yh + yrange)];
     [rbYSlider[RB_HIGH] setFloatValue:yh];
     
     [rbYForm setFloatValue:yl at:RB_LOW];
     if (logAxis)
     {
	  if (yl <= yrange)
	  {
	       [rbYSlider[RB_LOW] setMinValue:(double) yl/10.0];
	       [rbYSlider[RB_LOW]  setMaxValue:(double) yl*10.0];
	  }
	  else
	  {
	       [rbYSlider[RB_LOW] setMinValue:(double) (yl - yrange)];
	       [rbYSlider[RB_LOW]  setMaxValue:(double) (yh - yw)];
	  }
     }
     else
     {
	  [rbYSlider[RB_LOW]  setMinValue:(double) (yl - yrange)];
	  [rbYSlider[RB_LOW]  setMaxValue:(double) (yh - yw)];
     }
     [rbYSlider[RB_LOW]  setFloatValue:yl];
     
     if (checkBins)
     {
	  [rbYForm setFloatValue:0. at:RB_OFF ];
	  [rbYSlider[RB_OFF] setMinValue:-1.];
	  [rbYSlider[RB_OFF] setMaxValue: 1.];
	  [rbYSlider[RB_OFF] setFloatValue: 0.];
	  [rbYSlider[RB_OFF] setEnabled:YES];
	  [[rbYForm cellAt:RB_OFF :0] setEnabled:YES];
     }
     else
     {
	  [rbYForm setStringValue:"" at:RB_OFF];
	  [rbYSlider[RB_OFF] setEnabled:NO];
	  [[rbYForm cellAt:RB_OFF :0] setEnabled:NO];
     }
     yoff = 0.0;
	  
     /*
      * X axis
      */
     logAxis = h_getLogAxis(adisplay, XAXIS);
     checkBins = graphtype == LEGOPLOT || graphtype == HISTOGRAM
	  || graphtype == COLORPLOT;

     if (checkBins)
     {
	  nx = [firstPlot numBinsForAxis:XAXIS];
	  [rbXForm setIntValue:nx at: RB_NUM];
	  [rbXSlider[RB_NUM] setMinValue:2.];
	  [rbXSlider[RB_NUM] setMaxValue:(double)(2 * nx)];
	  [rbXSlider[RB_NUM] setIntValue:nx];
	  [rbXSlider[RB_NUM] setEnabled:YES];
	  [[rbXForm cellAt:RB_NUM :0] setEnabled:YES];
     }
     else
     {
	  [rbXForm setStringValue:"" at:RB_NUM];
	  [rbXSlider[RB_NUM] setEnabled:NO];
	  [[rbXForm cellAt:RB_NUM :0] setEnabled:NO];
	  nx = 50;
     }
	  
     [firstPlot getRangeForAxis:XAXIS low: &xl high: &xh ];
     xrange = xh - xl;
     xw = (xh - xl) / (nx);
     [rbXForm setFloatValue:xh at:RB_HIGH];
     [rbXSlider[RB_HIGH] setMinValue:(double) (xl + xw)];
     [rbXSlider[RB_HIGH] setMaxValue:(double) (xh + xrange)];
     [rbXSlider[RB_HIGH] setFloatValue:xh];
     
     [rbXForm setFloatValue:xl at:RB_LOW];
     if (logAxis)
     {
	  if (xl <= xrange)
	  {
	       [rbXSlider[RB_LOW] setMinValue:(double) xl/10.0];
	       [rbXSlider[RB_LOW]  setMaxValue:(double) xl*10.0];
	  }
	  else
	  {
	       [rbXSlider[RB_LOW]  setMaxValue:(double) (xh - xw)];
	       [rbXSlider[RB_LOW] setMinValue:(double) (xl - xrange)];
	  }
     }
     else
     {
	  [rbXSlider[RB_LOW]  setMinValue:(double) (xl - xrange)];
	  [rbXSlider[RB_LOW]  setMaxValue:(double) (xh - xw)];
     }
     [rbXSlider[RB_LOW]  setMaxValue:(double) (xh - xw)];
     [rbXSlider[RB_LOW]  setFloatValue:xl];
     
     if (checkBins)
     {
	  [rbXForm setFloatValue:0. at:RB_OFF ];
	  [rbXSlider[RB_OFF] setMinValue:-1.];
	  [rbXSlider[RB_OFF] setMaxValue: 1.];
	  [rbXSlider[RB_OFF] setFloatValue: 0.];
	  [rbXSlider[RB_OFF] setEnabled:YES];
	  [[rbXForm cellAt:RB_OFF :0] setEnabled:YES];
     }
     else
     {
	  [rbXForm setStringValue:"" at:RB_OFF];
	  [rbXSlider[RB_OFF] setEnabled:NO];
	  [[rbXForm cellAt:RB_OFF :0] setEnabled:NO];
     }
     xoff = 0.0;

     return self;
}

@end
