/* File: Magnify.m - Application class for 'Magnify'
 *
 * By: Christopher Lane
 * Symbolic Systems Resources Group
 * Knowledge Systems Laboratory
 * Stanford University
 *
 * Date: 9 January 1992
 *
 * Copyright: 1990, 1991 & 1992 by The Leland Stanford Junior University.
 * This program may be distributed without restriction for non-commercial use.
 */

#import <ctype.h>

#import "Magnify.h"

#define WINDOWTITLEFORMAT "%.2gx Magnification"
#define WINDOWTITLEPROTOTYPE "0.00x Magnification"

static NXDefaultsVector MagnifyDefaults = {
	{ SCALEDEFAULTSTRING, DEFAULTSCALESTRING },
	{ GRIDDEFAULTSTRING, DEFAULTGRIDSTRING },
	{ UPDATEDEFAULTSTRING, DEFAULTUPDATESTRING },
	{ CURSORDEFAULTSTRING, DEFAULTCURSORSTRING },
	{ NULL }
};

extern void timer(DPSTimedEntry, double, void *);

@implementation Magnify : Application

+ new
{
	self = [super new];

	(void) registerDefaults(MagnifyDefaults);
	
	timedEntry = NULL;

	return self;
}

- appDidInit:sender
{	
	MenuCell *cell;
	double update;
	const char *string;
	Menu *menu = [self mainMenu];
	Window *window = [view window];

	if ((string = getDefault(UPDATEDEFAULTSTRING)) == NULL || sscanf(string, DOUBLE, &update) != 1)
		update = DEFAULTUPDATE;
	
	[[[self showScale:[view scale] andSlider:YES] showGrid:[view grid] andSlider:YES] showUpdate:update andSlider:YES];
		
	[cursorButton setIntValue:(strncmp(getDefault(CURSORDEFAULTSTRING), YESSTRING, 1) == 0)];

	[view setNextResponder:[window firstResponder]];

	[[window makeFirstResponder:view] addToEventMask:NX_MOUSEMOVEDMASK];

	if ((cell = [menu findCellWithTag:FROZENMENUCELLTAG]) != nil) {
		[cell setUpdateAction:@selector(isFrozenUpdateAction:) forMenu:menu];
		[menu update];
		}
		
	[window makeKeyAndOrderFront:self];
	
	return self;
}

- hide:sender
{
	if (![view isFrozen]) [[view window] removeFromEventMask:NX_MOUSEMOVEDMASK];
	
	return [super hide:sender];
}

- unhide:sender
{
	if (![view isFrozen]) [[view window] addToEventMask:NX_MOUSEMOVEDMASK];
	
	return [super unhide:sender];
}

- free
{
	if (timedEntry != NULL) DPSRemoveTimedEntry(timedEntry);

	return [super free];
}

- changeScale:sender
{
	float scale, value = rint([sender floatValue]); /* 'intValue' truncates */

	scale = (value < -1.0) ? 1.0 / (- value) : 2.0 + value; /* non-linear slider */
	
	[[view setScale:(scale = floor(scale * 100.0) / 100.0)] createWindows]; /* round to nearest .01 */

	return [self showScale:scale andSlider:NO];
}

- showScale:(float) scale andSlider:(BOOL) flag
{
	char title[] = WINDOWTITLEPROTOTYPE;
	
	if(flag) {
		float value = rint((scale < 1) ? - (1 / scale) : scale - 2.0);
	
		if([scaleSlider floatValue] != value) [scaleSlider setFloatValue:value];
		}

	if([scaleField floatValue] != scale) [scaleField setFloatValue:scale];
	
	sprintf(title, WINDOWTITLEFORMAT, scale);
	
	[[view window] setTitle:title];

	return self;
}

- changeGrid:sender
{
	float grid = rint([sender floatValue]);
	
	[[view setGrid:grid] display];

	return [self showGrid:grid andSlider:NO];
}

- showGrid:(float) grid andSlider:(BOOL) flag
{
	if(grid > 0.0) {
		[gridField setFloatValue:grid];
		if(flag && [gridSlider floatValue] != grid) [gridSlider setFloatValue:grid];
		}
	else {
		[gridField setStringValue:OFFSTRING];
		if(flag && [gridSlider floatValue] != 0.0) [gridSlider setFloatValue:0.0];
		}

	return self;
}

- changeUpdate:sender
{
	return [self showUpdate:rint([sender floatValue] * 10.0) / 10.0 andSlider:NO]; /* round to nearest 0.1 */
}

- showUpdate:(double) update andSlider:(BOOL) flag
{
	if (timedEntry != NULL) DPSRemoveTimedEntry(timedEntry);

	if(update > 0.0) {
		timedEntry = DPSAddTimedEntry(update, (DPSTimedEntryProc) &timer, (void *) view, NX_BASETHRESHOLD);
		[updateField setFloatValue:update];
		if(flag && [updateSlider floatValue] != update) [updateSlider setFloatValue:update];
		}
	else {
		timedEntry = NULL;
		[updateField setStringValue:OFFSTRING];
		if(flag && [updateSlider floatValue] != 0.0) [updateSlider setFloatValue:0.0];
		}
		
	return self;
}

- (MagnifyView *) getView { return view; }
- setView:(MagnifyView *) anObject { view = anObject; return self; }

- setVersion:anObject
{
	[(version = anObject) setStringValue:VERSION];
	
	return self;
}

- (int) msgVersion:(const char **) aString ok:(int *) flag
{
	*flag = ((*aString = [version stringValue]) != NULL);

	return SEND_SUCCESS;
}

- (BOOL) isFrozenUpdateAction:(MenuCell *) anObject
{
	BOOL flag = [[NXApp getView] isFrozen];
	
	if ([anObject tag] == flag) return NO;
	
	[[anObject setTag:(int) flag] setTitle:(flag) ? UNFROZENMENUTITLE : FROZENMENUTITLE];
	[anObject setKeyEquivalent:tolower([anObject title][0])];
	
	return YES;
}

@end
