/* InspectPlot.h		by Paul Kunz	June 1991
 * Controls various options for displaying the plot.
 *
 * Copyright (C)  1991  The Board of Trustees of
 * The Leland Stanford Junior University.  All Rights Reserved.
 */

#import "HGraphicView.h"
#import "InspectPlot.h"

const char InspectPlot_h_rcsid[] = INSPECTPLOT_H_ID;
const char InspectPlot_m_rcsid[] = "$Id: InspectPlot.m,v 2.30.2.1 1993/12/15 22:44:48 mfg Exp $";

#import "NewInspector.h"
#import "Plot.h"
#import "FineSlider.h"
#import "h3D.h"

/*
 * Tags on the Graph Type radio Buttons defined in IB 
 * must be same as graphtype_t enumerated type in hippo.h 
 * Here we define the rows index of grey and color bins buttons
 * which both have tag of COLORPLOT
 */

/* Tags on the draw options switches defined in IB */
#define BOX_TAG 0
#define PTS_TAG 1
#define JOIN_TAG 2
#define ERR_TAG 3
#define TLT_TAG 4
#define AXES_TAG 5
#define SOLID_TAG 0
#define DASH_TAG 1
#define DOT_TAG 2
#define DOTDASH_TAG 3

#define PI 3.1415926536
#define RAD_TO_DEG 180.0/PI

@implementation InspectPlot
static int	nSymbols = 12;
static char	*symbolTitle[] = {
			"Triangle 1",
			"Triangle 2",
			"Triangle 3",
			"Triangle 4",
			"Square 1",
			"Square 2",
			"Diamond 1",
			"Diamond 2",
			"Circle 1",
			"Circle 2",
			"Times",
			"Plus"
		};
        

- initInspFor:aDraw
{
    NXBundle	*bundle;
    char	buffer[MAXPATHLEN+1];
    PopUpList  	*popUpList;
    int		i;
        
    [super initInspFor:aDraw];
    
    bundle = [NXBundle bundleForClass:[self class]];
    if ( [bundle getPath:buffer forResource:"InspectPlot" ofType:"nib"] ) {
    	[NXApp loadNibFile:buffer owner:self
                 withNames:NO  fromZone:[self zone]];
    }
    [theInspector addView:[contentBox contentView]
                 withName:"Plot Options" withSupervisor:self];

    popUpList = [popUpButtonLine target];
    [popUpList setTarget:self];
    [popUpList setAction:@selector(lineOption:)];

    popUpList = [popUpButtonSymbol target];
    [popUpList setTarget:self];
    [popUpList setAction:@selector(plotSymbol:)];
    for (i=0; i<nSymbols; i++) {
	[popUpList addItem:symbolTitle[i]];
    }
    return self;
}
- drawOption:sender
{
    drawtype_t          drawtype;
    int			titlesFlag, axesFlag;

    drawtype = NONE;
    if ([[drawOptMatrix findCellWithTag:BOX_TAG] state] == 1) 
        drawtype |= BOX;
    if ([[drawOptMatrix findCellWithTag:PTS_TAG] state] == 1)
        drawtype |= POINT;
    if ([[drawOptMatrix findCellWithTag:JOIN_TAG] state] == 1)
	drawtype |= LINE;
    if ([[drawOptMatrix findCellWithTag:ERR_TAG] state] == 1)
	drawtype |= ERRBAR;

    [graphicView graphicsPerform:@selector(setDrawType:)
                           with :(id)&drawtype andDraw:NO];
    
    titlesFlag = [[drawOptMatrix findCellWithTag:TLT_TAG] state ];
    [graphicView graphicsPerform:@selector(setTitlesFlag:)
                           with :(id)&titlesFlag andDraw:NO];
    
    axesFlag = [[drawOptMatrix findCellWithTag:AXES_TAG] state ];
    [graphicView graphicsPerform:@selector(setAxesFlag:)
                           with :(id)&axesFlag andDraw:YES];
    
    [[graphicView window] flushWindow];
    return self;
}

- lineOption:sender
{
    linestyle_t         linestyle;

    linestyle = [sender selectedRow];

    [graphicView graphicsPerform:@selector(setLineStyle:)
                           with :(id)&linestyle andDraw:YES];
    
    [[graphicView window] flushWindow];
    return self;
}

- plotSymbol:sender
{
    plotsymbol_t         plotsymbol;

    plotsymbol = [sender selectedRow];
    
    [graphicView graphicsPerform:@selector(setPlotSym:)
                           with :(id)&plotsymbol andDraw:YES];
    
    [[graphicView window] flushWindow];
    return self;
}

- plotSymSize:sender
{
    float        plotsymsize;

    plotsymsize = [sender floatValue];     
    
    [graphicView graphicsPerform:@selector(setSymSize:)
                           with :(id)&plotsymsize andDraw:YES];
    
    [[graphicView window] flushWindow];
    return self;
}

- titleForm:sender
{
    const char		*string;
    
    string = [titleForm stringValueAt:0];
    [graphicView graphicsPerform:@selector(setTitle:)
	                    with:(id)string andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- resetTitle:sender
{
    const char	*string;
    
    if ( !selectedPlot ) {
        return self;
    }

    string = "%t";
    [graphicView graphicsPerform:@selector(setTitle:)
	with:(id)string andDraw:YES];
    [titleForm setStringValue:string at:0];
    [[graphicView window] flushWindow];
    return self;
}


- newGray:sender
{
    id                  thisSlider;
    struct {
    	int                 faceNo;
    	float               value;
    } grayValue;    
    thisSlider = [sender selectedCell];
    grayValue.faceNo = [thisSlider tag];
    grayValue.value = [thisSlider floatValue];
    [graphicView graphicsPerform:@selector(newGray3D:)
                           with :(id)&grayValue andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- newTheta:sender
{
    float angle;    

    angle = [sender floatValue];
    [thetaText setFloatValue:RAD_TO_DEG * angle];
    [graphicView graphicsPerform:@selector(newTheta3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newPhi:sender
{
    float angle;    

    angle = [sender floatValue];
    [phiText setFloatValue:RAD_TO_DEG * angle];
    [graphicView graphicsPerform:@selector(newPhi3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newDist:sender
{
    float distance;

    distance = [sender floatValue];
    if (distance < 1.8) {
	[self showError:"Distance must be greater than 1.8"];
	return self;
    }
    [distanceSlider setFloatValue:-1./ distance];
    [distText setFloatValue:distance];
    [graphicView graphicsPerform:@selector(newDist3D:)
                           with :(float *)&distance andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newInvDist:sender
{
    float               invDist, distance;
    
    invDist = -[sender floatValue];
    if (invDist == 0.)
	distance = HUGE;
    else
	distance = 1./ invDist;
    [distText setFloatValue:distance];
    [graphicView graphicsPerform:@selector(newDist3D:)
                           with :(float *)&distance andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newTheta_degrees:sender
{
    float angle;    

    angle = [sender floatValue] / RAD_TO_DEG;
    [thetaSlider setFloatValue:angle];
    [thetaText setFloatValue:angle];
    [graphicView graphicsPerform:@selector(newTheta3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- newPhi_degrees:sender
{
    float angle;    

    angle = [sender floatValue] / RAD_TO_DEG;
    [phiSlider setFloatValue:angle];
    [phiText setFloatValue:angle];
    [graphicView graphicsPerform:@selector(newPhi3D:)
                           with :(float *)&angle andDraw:YES];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}

- toggleCube:sender
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector(toggleCube3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- toggleWireFrame:sender;
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector(toggleWireFrame3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- toggleFill:sender
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector( toggleFill3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- toggleMesh:sender
{
    BOOL state;
    
    state = (BOOL)[sender state];
    [graphicView graphicsPerform:@selector(toggleMesh3D:)
                           with :(BOOL *)&state andDraw:YES];
    [[graphicView window] flushWindow];
    return self;
}

- showError:(char *)errorMessage
{
    NXRunAlertPanel("Error", errorMessage, "OK", NULL, NULL);
    return self;
}

- mouseMoved:(const NXPoint *)offset in:sender withKey:(int)flag
{
        threeD_t	       *threeD;  	  
	float			theta,phi;
    	display			disp;
		
	disp = ([sender histDisplay]);
	threeD = disp->threeDWorkArea;
	
	if (flag & NX_COMMANDMASK) {	/*command key was held down */
		theta = disp->theta + ((offset->x)*3.14/180);
		if (theta > 3.14) theta = theta - 6.28; /* pi * 2 */
		if (theta < -3.14) theta = 6.28 + theta;
	
		[sender newTheta3D:&theta];
	
		phi = -disp->phi + ((offset->y)*3.14/180);
		if (phi > 1.57) phi = -3.14 + phi;
		if (phi < -1.57) phi = 3.14 + phi;
		[sender newPhi3D:&phi];
	}
	if (flag & NX_CONTROLMASK) {
		float	diff,dist;
		diff = [distanceSlider mmaxValue] - [distanceSlider mminValue];
		dist = disp->dist + ((offset->y)*diff/100);
		if (dist > -1./[distanceSlider mmaxValue]) dist = -1./[distanceSlider mmaxValue];
		if (dist < -1./[distanceSlider mminValue]) dist = -1./[distanceSlider mminValue];
		[sender newDist3D:&dist];
	}
	return self;
}

/* Methods to support updating the inspector's View */
- updateView
{
    display             disp;
    drawtype_t          drawtype;
    graphtype_t         graphtype;
    int                      pos;
    threeD_t	       *threeD;  

    static char *lineTitle[] = {"Solid","Dash","Dot","DotDash"};
        
    if ( !selectedPlot ) {
        return self;
    }
    disp = [selectedPlot histDisplay];
    graphtype = h_getDispType( disp );

    if (graphtype == HISTOGRAM || graphtype == XYPLOT ||
	graphtype == STRIPCHART) 
    {
	[selectedPlot getDrawType:(drawtype_t *) & drawtype];
	pos = drawtype & BOX;
	if (pos > 0)
	    pos = 1;
	[[drawOptMatrix findCellWithTag:BOX_TAG] setState:pos];
	[[drawOptMatrix findCellWithTag:BOX_TAG] setEnabled:YES];
	
	pos = drawtype & POINT;
	if (pos > 0)
	    pos = 1;
	[[drawOptMatrix findCellWithTag:PTS_TAG] setState:pos];
	[[drawOptMatrix findCellWithTag:PTS_TAG] setEnabled:YES];
	
	pos = drawtype & LINE;
	if (pos > 0)
	    pos = 1;
	[[drawOptMatrix findCellWithTag:JOIN_TAG] setState:pos];
	[[drawOptMatrix findCellWithTag:JOIN_TAG] setEnabled:YES];
	
	pos = drawtype & ERRBAR;
	if (pos > 0)
	    pos = 1;
	[[drawOptMatrix findCellWithTag:ERR_TAG] setState:pos];
	[[drawOptMatrix findCellWithTag:ERR_TAG] setEnabled:YES];

	[popUpButtonLine setEnabled:YES];
	[popUpButtonLine setTitle:lineTitle[(int)h_getLineStyle(disp)]];
    } else {
	[[drawOptMatrix findCellWithTag:BOX_TAG] setEnabled:NO];
	[[drawOptMatrix findCellWithTag:PTS_TAG] setEnabled:NO];
	[[drawOptMatrix findCellWithTag:JOIN_TAG] setEnabled:NO];
	[[drawOptMatrix findCellWithTag:ERR_TAG] setEnabled:NO];
	[popUpButtonLine setEnabled:NO];
    }

    if (graphtype == COLORPLOT || graphtype == LEGOPLOT)
    {
	[popUpButtonSymbol setEnabled:NO];
        [plotSymSizeNumber setStringValue: ""];
    }
    else
    {
	[popUpButtonSymbol setEnabled:YES];
	[popUpButtonSymbol setTitle:symbolTitle[(int)h_getPlotSym(disp)]];
        [plotSymSizeNumber setFloatValue: h_getSymSize(disp)];
    }

    [[drawOptMatrix findCellWithTag:TLT_TAG] 
         setState:h_getDrawTitles(disp)];
    [[drawOptMatrix findCellWithTag:AXES_TAG] 
         setState:h_getDrawAxes(disp)];
	 
    [drawOptMatrix display];
    
    [titleForm setStringValue:h_getTitle(disp) at:0];
    
    /*
     * 3D stuff:-
     */
    if (firstPlot) {
	if ( graphtype == LEGOPLOT || graphtype == THREEDSCATTER ) {
	    [distanceSlider       setEnabled:YES];
	    [phiSlider            setEnabled:YES];
	    [thetaSlider          setEnabled:YES];
	    [distText             setEnabled:YES];
	    [phiText              setEnabled:YES];
	    [thetaText            setEnabled:YES];
	    [cubeSwitch           setEnabled:YES];
	    [grayMatrix           setEnabled:YES];
	    if (disp->threeDWorkArea == NULL) return self;
	    threeD = disp->threeDWorkArea;
	    [thetaSlider setFloatValue:disp->theta];
	    [thetaText setFloatValue:RAD_TO_DEG*disp->theta];
	    [phiSlider setFloatValue:-disp->phi];
	    [phiText setFloatValue:-RAD_TO_DEG*disp->phi];
	    [distanceSlider setFloatValue:-1/disp->dist];
	    [distText setFloatValue:disp->dist];
    
	    [cubeSwitch setState:(int)disp->doCube];
	    [wireFrameSwitch setState:(int)disp->doWireFrame];
	    [fillSwitch setState:(int)disp->doFill];
	    [meshSwitch setState:(int)disp->doMesh];
    
	    if (graphtype == LEGOPLOT) {
		[wireFrameSwitch setEnabled:YES];
		[fillSwitch setEnabled:YES];
		[meshSwitch setEnabled:YES];
	    } 
	    else if (graphtype == THREEDSCATTER) {
		[wireFrameSwitch setEnabled:NO];
		[fillSwitch setEnabled:NO];
		[meshSwitch setEnabled:NO];
	    } 
        } else {
	    [distanceSlider       setEnabled:NO];
	    [phiSlider            setEnabled:NO];
	    [thetaSlider          setEnabled:NO];
	    [distText             setEnabled:NO];
	    [phiText              setEnabled:NO];
	    [thetaText            setEnabled:NO];
	    [cubeSwitch           setEnabled:NO];
	    [wireFrameSwitch      setEnabled:NO];
	    [fillSwitch           setEnabled:NO];
	    [meshSwitch           setEnabled:NO];
	    [grayMatrix           setEnabled:NO];
	}
    }

    return self;
}
@end
