/* Hippo Graphic View	by Paul Kunz	June 1991
 * a subclass of GraphicView in /NextDeveloper/Examples/Draw
 * to add or over-ride so that it can handle hippo Graphic objects
 *
 * This category handles targets of menu items and keyboard envents 
 *
 * Copyright (C)  1993  The Board of Trustees of
 * The Leland Stanford Junior University.  All Rights Reserved.
 */

#import "Draw.subproj/draw.h"
#import "HGraphicView.h"

const char hgvMenu_m_rcsid[] = "$Id: hgvMenu.m,v 2.8.2.2 1994/02/08 20:30:24 rensing Exp $";

#import "HDrawApp.h"
#import "InspectBase.h"
#import "Overlay.h"
#import "PageMarker.h"
#import "Plot.h"
#import "SaveWindow.h"

@implementation HGraphicView(Menu)

/* This routine is needed for the "Add Page" menu item. */
- addPage:sender
{
	return [self addPages: 1];
}

- deletePage:sender
{
    Graphic	*g;
    NXRect	box;
    NXRect	curRect;
    int		i;

    [[[self window] delegate] getPageFrame:&box];
    [self getBBox:&curRect of:glist extended:NO];
    if (NXIntersectsRect(&curRect, &box)) {
        NXRunAlertPanel("Error",
	    "Last page is not empty",
	    "OK", NULL, NULL);
	return self;
    }
    box.size.width = 0.0;
    box.size.height = -box.size.height;
    [self sizeBy:box.size.width :box.size.height ];
    i = [glist count];
    while( i-- ) {
        g = [glist objectAt:i];
	if ( ![g isLocked] ) {
	    [g moveBy:(const NXPoint *)&box.size];
	}
    }
    [self getFrame:&box ];
    [self cache:&box ];
    [window flushWindow];
    return self;
}

- addSaveWindow:sender
{
     [[[SaveWindow new] init] addSelf: self];
     return self;
}
- alignAll:sender
{
 // This method is obsolete and kept in the 1.1 release for
 // backward compatability.
    return [self overlay:sender];
}
- alignSize:sender
{
 // backward compatible code.   Remove in next release
    return [self overlay:sender];
}
- alignXRange:sender
{
    id	inspector;
    Plot	*firstPlot;
    NXPoint	theRange;
    binding_t	xaxis = XAXIS;
    
    inspector = [hippoDraw currentInspector];
    if ( inspector == nil ) return self;
    
    firstPlot = [inspector firstPlot];
    if ( firstPlot == nil ) return self;
    
    [firstPlot getRangeForAxis:XAXIS low:&theRange.x high:&theRange.y];
    [self graphicsPerform:@selector(setRange:to:)
	    with:&xaxis with: (id)&theRange andDraw:YES ];
    [window flushWindow];
    return self;
}

- alignYRange:sender
{
    id inspector;
    Plot        *firstPlot;
    NXPoint	theRange;
    binding_t	yaxis = YAXIS;
    
    inspector = [hippoDraw currentInspector];
    if ( inspector == nil ) return self;

    firstPlot = [inspector firstPlot];
    if ( firstPlot == nil ) return self;

    [firstPlot getRangeForAxis:YAXIS low:&theRange.x high:&theRange.y];
    [self graphicsPerform:@selector(setRange:to:)
	             with:&yaxis with:(id)&theRange andDraw:YES ];
    [window flushWindow];
    return self;
}

- alignXNumBins:sender
{
    id	inspector;
    Plot	*firstPlot;
    binding_t	xaxis = XAXIS;
    int		numBins;
    
    inspector = [hippoDraw currentInspector];
    if ( inspector == nil ) return self;
    
    firstPlot = [inspector firstPlot];
    if ( firstPlot == nil ) return self;
    
    numBins = [firstPlot numBinsForAxis: XAXIS ];
    [self graphicsPerform:@selector(setNumBins:to:)
	    with:(id)&xaxis with:(id)&numBins andDraw:YES ];
    [[window flushWindow] makeKeyWindow];
    return self;
}
- alignYNumBins:sender
{
    id inspector;
    Plot        *firstPlot;
    display     disp;
    binding_t	yaxis = YAXIS;
    int	        numBins;
    graphtype_t gt;
    
    inspector = [hippoDraw currentInspector];
    if ( inspector == nil ) return self;

    firstPlot = [inspector firstPlot];
    if ( firstPlot == nil ) return self;

    disp = [firstPlot histDisplay];
    gt = h_getDispType( disp );
    if ( gt == HISTOGRAM ) return self;
    
    numBins = h_getBinNum( disp, YAXIS );
    [self graphicsPerform:@selector(setNumBins:to:)
	    with:(id)&yaxis with: (id)&numBins andDraw:YES ];
    [[window flushWindow] makeKeyWindow];
    return self;
}

- cut:sender
{
    if ( [self isAllowed] ) {
	 return [super cut:sender];
    }
    return self;
}

- delete:sender
{
    Plot	*g;
    int		i;
    if ( [self isAllowed] ) {
      /* Do this before handing delete to GraphicView because
       * GraphicView doesn't free the graphic objects.   If I fix
       * GraphicView to free objects, then ChangeManager get's messed
       * up because we're not dealing with changes in Plots correctly
       * - pfk Jul '92
       */
        i = [slist count];
	while (i--) {
	    g = [slist objectAt:i];
	    if ( [g isKindOf:[Plot class]] ) {
	        [g removeAllCuts];
	    }
	}
        return [super delete:sender];
    }
    return self;
}

- duplicate: sender
 /*
  * Duplicate is equivalent to copy + paste, except that the new objects are
  * placed on the page using the plot placement method. If more than one
  * object is selected, the relative positions are maintained.
  */
{
     List *pblist;
     Pasteboard *pboard;

     /* copy selection to the pasteboard */
     [self copy:sender];

     /*
      * paste in and move 
      */
     pboard = [Pasteboard new];
     /* the following call sets the selection list as well */
     pblist = [self pasteFromPasteboard:pboard andLink:DontLink at:NULL];

     if (pblist) {
	  NXPoint location, offset;
	  NXRect bbox;
	  
	  [self getBBox:&bbox of:pblist extended:NO];/*don't include handles*/
	  [self calcPlacement: &(bbox.size) result: &location ];

          /* calcPlacement can change bbox if pages are added. */
	  [self getBBox:&bbox of:pblist extended:NO];    
	  offset.x = location.x - bbox.origin.x;
	  offset.y = location.y - bbox.origin.y;
	  [pblist makeObjectsPerform:@selector(moveBy:) with:(id)&offset];

	  [pblist free];
     }
     [self recacheSelection];
     
     return self;
}

- overlay:sender
 /*
  * Creates a new Group object with the current slist as its member list.
  * See the Group class for more info.
  */
{
    id		g, insp, firstPlot;
    NXRect	eb;
    int		i;

    insp = [hippoDraw currentInspector];
    if ( insp == nil ) return self;
    firstPlot = [insp firstPlot];
    
 /* If firstPlot is nil, which can happen if user just did a unoverlay,
  * then pick a plot in the list to be the firstPlot.
  */
    if ( firstPlot == nil ) {
        i = [slist count];
	while( i-- ) {
	    g = [slist objectAt:i];
	    if ( [g isKindOf:[Plot class]] ) {
	        firstPlot = g;
		break;
	    }
	}
    }
    
    i = [slist count];
    if (i > 1) {
	while (i--) [glist removeObject:[slist objectAt:i]];
	g = [[Overlay allocFromZone:[self zone]] initList:slist
						 with:firstPlot];
	[glist insertObject:g at:0];
	slist = [[List allocFromZone:[self zone]] init];
	[slist addObject:g];
	gvFlags.groupInSlist = YES;
	[self cache:[g getInitialBounds:&eb]];
	if (sender != self) [window flushWindow];
    }
    [ window flushWindow];
    return self;
}

- unoverlay:sender
 /*
  * Goes through the slist and ungroups any Group objects in it.
  * Does not descend any further than that (i.e. all the Group objects
  * in the slist are ungrouped, but any Group objects in those ungrouped
  * objects are NOT ungrouped).
  */
{
    id	g, tlist;
    int i, j, k;
    NXRect sbounds, tbounds;
    BOOL found = NO;

    [self getBBox:&sbounds of:slist];
    i = [slist count];
    while (i--) {
	g = [slist objectAt:i];
	if ([g isKindOf:[Overlay class]]) {
	    k = [glist indexOf:g];
	    [glist removeObjectAt:k];
	    found = YES;
	    tlist = [[List allocFromZone:[self zone]] initCount:0];
	    [[g transferSubGraphicsTo:tlist at:0] free];
	    [self getBBox:&tbounds of:tlist];
	    NXUnionRect( &tbounds, &sbounds );
	    j = [tlist count];
	    while ( j-- ) {
	        g = [tlist objectAt:j];
		[glist insertObject:g at:k];
	    }
	    [tlist free];
	}
    }

    if (found) {
	[self cache:&sbounds];
	if (sender != self) [window flushWindow];
	[self getSelection];
    }

    return self;
}

- prefPanel:sender
{
    NXBundle	*bundle;
    char	buffer[MAXPATHLEN+1];
    const char	*defaultValue;
    
    if( ! prefPanel ){
	bundle = [NXBundle bundleForClass:[self class]];
	if ( [bundle getPath:buffer 
	         forResource:"HGraphicView" ofType:"nib"] ) {
	    [NXApp loadNibFile:buffer owner:self
			withNames:NO  fromZone:[self zone]];
	}
    }
    defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotCols" );
    [prefForm setStringValue:defaultValue at:0];
    defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotRows" );
    [prefForm setStringValue:defaultValue at:1];
    [prefPanel makeKeyAndOrderFront:sender];
    return self;    
}

- prefButton:sender
{
    char	string[80];
    unsigned int	cols, rows;

    [prefPanel orderOut:self];
    if ( [sender selectedCol] == 1 ) {
        cols = [prefForm intValueAt:0];
	rows = [prefForm intValueAt:1];
	sprintf( string, "%u", cols );
	NXWriteDefault("HippoDraw", "NumPlotCols", string );
	sprintf( string, "%u", rows );
	NXWriteDefault("HippoDraw", "NumPlotRows", string );
	[self deselectAll:self];
	[window flushWindow];
    }
    NXUpdateDefaults();
    return self;
}

@end
