568 lines
14 KiB
Objective-C
568 lines
14 KiB
Objective-C
|
|
#import "SchemeDelegate.h"
|
|
|
|
VScheme *vm = nil;
|
|
|
|
|
|
@implementation SchemeDelegate : NSObject
|
|
|
|
- (void)applicationWillFinishLaunching:(NSNotification *)not
|
|
{
|
|
// CREATE_AUTORELEASE_POOL(pool);
|
|
NSMenu *menu, *info, *file, *scheme, *external, *env,
|
|
*edit, *print, *services, *windows;
|
|
|
|
// Create the app menu
|
|
menu = [NSMenu new];
|
|
|
|
[menu addItemWithTitle: @"Info"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"File"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"Edit"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"Windows"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"Scheme"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"Environment"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"Services"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
|
|
[menu addItemWithTitle: @"Hide"
|
|
action: @selector(hide:)
|
|
keyEquivalent: @"h"];
|
|
|
|
[menu addItemWithTitle: @"Quit"
|
|
action: @selector(terminate:)
|
|
keyEquivalent: @"q"];
|
|
|
|
// Create the scheme submenu
|
|
scheme = [NSMenu new];
|
|
[menu setSubmenu: scheme
|
|
forItem: [menu itemWithTitle: @"Scheme"]];
|
|
|
|
[scheme addItemWithTitle: @"Reset"
|
|
action: @selector(reset:)
|
|
keyEquivalent: @"+"];
|
|
|
|
[scheme addItemWithTitle: @"Evaluate"
|
|
action: @selector(evaluate:)
|
|
keyEquivalent: @"#"];
|
|
|
|
[scheme addItemWithTitle: @"Evaluate external"
|
|
action:NULL
|
|
keyEquivalent: @""];
|
|
|
|
external = [NSMenu new];
|
|
[scheme setSubmenu: external
|
|
forItem: [scheme itemWithTitle: @"Evaluate external"]];
|
|
[external addItemWithTitle: @"Add external"
|
|
action: @selector(addExternal:)
|
|
keyEquivalent: @""];
|
|
|
|
|
|
// Create the environment submenu
|
|
env = [NSMenu new];
|
|
[menu setSubmenu: env
|
|
forItem: [menu itemWithTitle: @"Environment"]];
|
|
|
|
[env addItemWithTitle: @"Up"
|
|
action: @selector(up:)
|
|
keyEquivalent: @""];
|
|
|
|
[env addItemWithTitle: @"Down"
|
|
action: @selector(down:)
|
|
keyEquivalent: @""];
|
|
|
|
// Create the info submenu
|
|
info = [NSMenu new];
|
|
[menu setSubmenu: info
|
|
forItem: [menu itemWithTitle: @"Info"]];
|
|
|
|
[info addItemWithTitle: @"Info Panel..."
|
|
action: @selector(orderFrontStandardInfoPanel:)
|
|
keyEquivalent: @""];
|
|
|
|
/*
|
|
[info addItemWithTitle: @"Preferences..."
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
*/
|
|
[info addItemWithTitle: @"Help"
|
|
action: @selector (orderFrontHelpPanel:)
|
|
keyEquivalent: @"?"];
|
|
// RELEASE(info);
|
|
|
|
// Create the file submenu
|
|
file = [NSMenu new];
|
|
[menu setSubmenu: file
|
|
forItem: [menu itemWithTitle: @"File"]];
|
|
|
|
[file addItemWithTitle: @"Open Document"
|
|
action: @selector(openDocument:)
|
|
keyEquivalent: @"o"];
|
|
|
|
[file addItemWithTitle: @"New Document"
|
|
action: @selector(newDocument:)
|
|
keyEquivalent: @"n"];
|
|
|
|
[file addItemWithTitle: @"Save"
|
|
action: @selector(saveDocument:)
|
|
keyEquivalent: @"s"];
|
|
|
|
[file addItemWithTitle: @"Save To..."
|
|
action: @selector(saveDocumentTo:)
|
|
keyEquivalent: @"t"];
|
|
|
|
[file addItemWithTitle: @"Save As..."
|
|
action: @selector(saveDocumentAs:)
|
|
keyEquivalent: @"S"];
|
|
|
|
[file addItemWithTitle: @"Save All"
|
|
action: @selector(saveDocumentAll:)
|
|
keyEquivalent: @""];
|
|
|
|
[file addItemWithTitle: @"Revert to Saved"
|
|
action: @selector(revertDocumentToSaved:)
|
|
keyEquivalent: @"u"];
|
|
|
|
[file addItemWithTitle: @"Close"
|
|
action: @selector(close)
|
|
keyEquivalent: @""];
|
|
|
|
[file addItemWithTitle: @"Insert File..."
|
|
action: @selector(insertFile:)
|
|
keyEquivalent: @""];
|
|
|
|
// RELEASE(file);
|
|
|
|
// Create the edit submenu
|
|
edit = [NSMenu new];
|
|
[menu setSubmenu: edit
|
|
forItem: [menu itemWithTitle: @"Edit"]];
|
|
|
|
[edit addItemWithTitle: @"Cut"
|
|
action: @selector(cut:)
|
|
keyEquivalent: @"x"];
|
|
|
|
[edit addItemWithTitle: @"Copy"
|
|
action: @selector(copy:)
|
|
keyEquivalent: @"c"];
|
|
|
|
[edit addItemWithTitle: @"Paste"
|
|
action: @selector(paste:)
|
|
keyEquivalent: @"v"];
|
|
|
|
[edit addItemWithTitle: @"Delete"
|
|
action: @selector(delete:)
|
|
keyEquivalent: @""];
|
|
/*
|
|
[edit addItemWithTitle: @"Undelete"
|
|
action: NULL
|
|
keyEquivalent: @""];
|
|
*/
|
|
[edit addItemWithTitle: @"Select All"
|
|
action: @selector(selectAll:)
|
|
keyEquivalent: @"a"];
|
|
// RELEASE(edit);
|
|
|
|
// Create the windows submenu
|
|
windows = [NSMenu new];
|
|
[menu setSubmenu: windows
|
|
forItem: [menu itemWithTitle: @"Windows"]];
|
|
|
|
[windows addItemWithTitle: @"Arrange"
|
|
action: @selector(arrangeInFront:)
|
|
keyEquivalent: @""];
|
|
|
|
[windows addItemWithTitle: @"Miniaturize"
|
|
action: @selector(performMiniaturize:)
|
|
keyEquivalent: @"m"];
|
|
|
|
[windows addItemWithTitle: @"Close"
|
|
action: @selector(performClose:)
|
|
keyEquivalent: @"w"];
|
|
|
|
[windows addItemWithTitle: @"Close image windows"
|
|
action: @selector(closeImageWindows:)
|
|
keyEquivalent: @"W"];
|
|
|
|
[windows addItemWithTitle: @"Close environment windows"
|
|
action: @selector(closeEnvWindows:)
|
|
keyEquivalent: @""];
|
|
|
|
[NSApp setWindowsMenu: windows];
|
|
// RELEASE(windows);
|
|
|
|
// Create the service submenu
|
|
services = [NSMenu new];
|
|
[menu setSubmenu: services
|
|
forItem: [menu itemWithTitle: @"Services"]];
|
|
|
|
[NSApp setServicesMenu: services];
|
|
// RELEASE(services);
|
|
|
|
[NSApp setMainMenu: menu];
|
|
// RELEASE(menu);
|
|
|
|
imageWindows = [NSMutableArray arrayWithCapacity:1];
|
|
[imageWindows retain];
|
|
|
|
envWindows = [NSMutableArray arrayWithCapacity:1];
|
|
[envWindows retain];
|
|
|
|
// RELEASE(pool);
|
|
}
|
|
|
|
- (void)applicationDidFinishLaunching: (NSNotification *)not;
|
|
{
|
|
vm = [[VScheme alloc] init];
|
|
[vm setDelegate:self];
|
|
|
|
[self makeStatisticsPanel];
|
|
[self makeInterruptPanel];
|
|
[self makeInterpreterWindow];
|
|
|
|
// Make the DocumentController the delegate of the application,
|
|
// as this is the only way I know to bring it into the responder chain
|
|
[NSApp setDelegate:[NSDocumentController sharedDocumentController]];
|
|
}
|
|
|
|
NSWindow *interpreterWindow = nil;
|
|
|
|
|
|
- makeInterpreterWindow
|
|
{
|
|
NSWindow *window;
|
|
NSScrollView *scrollView;
|
|
SCMInteractive *textView;
|
|
NSRect scrollViewRect = {{0, 0}, {470, 400}};
|
|
NSRect winRect = {{250, 100}, {470, 400}};
|
|
NSRect textRect;
|
|
unsigned int style = NSTitledWindowMask |
|
|
NSMiniaturizableWindowMask | NSResizableWindowMask;
|
|
|
|
// This is expected to be retained, as it would normaly come from a
|
|
// nib file, where the owner would retain it.
|
|
window = [[NSWindow alloc] initWithContentRect: winRect
|
|
styleMask: style
|
|
backing: NSBackingStoreRetained
|
|
defer: NO];
|
|
[window setMinSize:NSMakeSize(300, 300)];
|
|
|
|
scrollView = [[NSScrollView alloc] initWithFrame: scrollViewRect];
|
|
[scrollView setHasHorizontalScroller: NO];
|
|
[scrollView setHasVerticalScroller: YES];
|
|
[scrollView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
|
|
[[scrollView contentView] setAutoresizingMask: NSViewHeightSizable
|
|
| NSViewWidthSizable];
|
|
[[scrollView contentView] setAutoresizesSubviews:YES];
|
|
|
|
// Build up the text network
|
|
textRect = [[scrollView contentView] frame];
|
|
textView = [[SCMInteractive alloc] initWithFrame: textRect];
|
|
|
|
[textView setBackgroundColor: [NSColor whiteColor]];
|
|
|
|
[textView setString:GSCHEME];
|
|
[textView appendString:@"> "];
|
|
[textView setFont:[NSFont userFixedPitchFontOfSize:12]];
|
|
|
|
[textView setDelegate:vm];
|
|
[textView setHorizontallyResizable: NO];
|
|
[textView setVerticallyResizable: YES];
|
|
[textView setMinSize: NSMakeSize(0, 0)];
|
|
[textView setMaxSize: NSMakeSize(1E7, 1E7)];
|
|
[textView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
|
|
[[textView textContainer]
|
|
setContainerSize:NSMakeSize(textRect.size.width, 1e7)];
|
|
|
|
|
|
[[textView textContainer] setWidthTracksTextView: YES];
|
|
// Store the text view in an ivar
|
|
intTextView = textView;
|
|
|
|
[scrollView setDocumentView: textView];
|
|
// RELEASE(textView);
|
|
[window setContentView: scrollView];
|
|
// RELEASE(scrollView);
|
|
|
|
// Make the Document the delegate of the window
|
|
[window setDelegate: self];
|
|
|
|
[window setTitle:@"GScheme"];
|
|
[window display];
|
|
[window makeKeyAndOrderFront:nil];
|
|
// Make the text view the first responder
|
|
[textView placeCursorAtEnd];
|
|
[window makeFirstResponder:textView];
|
|
|
|
interpreterWindow = window;
|
|
|
|
return self;
|
|
}
|
|
|
|
- makeStatisticsPanel
|
|
{
|
|
NSPanel *panel;
|
|
NSScrollView *scrollView;
|
|
SCMInteractive *textView;
|
|
NSRect scrollViewRect = {{0, 0}, {470, 400}};
|
|
NSRect winRect = {{450, 75}, {470, 400}};
|
|
NSRect textRect;
|
|
unsigned int style = NSTitledWindowMask |
|
|
NSMiniaturizableWindowMask | NSResizableWindowMask;
|
|
|
|
// This is expected to be retained, as it would normaly come from a
|
|
// nib file, where the owner would retain it.
|
|
panel = [[NSPanel alloc] initWithContentRect: winRect
|
|
styleMask: style
|
|
backing: NSBackingStoreRetained
|
|
defer: NO];
|
|
[panel setMinSize:NSMakeSize(300, 300)];
|
|
|
|
scrollView = [[NSScrollView alloc] initWithFrame: scrollViewRect];
|
|
[scrollView setHasHorizontalScroller: NO];
|
|
[scrollView setHasVerticalScroller: YES];
|
|
[scrollView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
|
|
[[scrollView contentView] setAutoresizingMask: NSViewHeightSizable
|
|
| NSViewWidthSizable];
|
|
[[scrollView contentView] setAutoresizesSubviews:YES];
|
|
|
|
// Build up the text network
|
|
textRect = [[scrollView contentView] frame];
|
|
textView = [[NSTextView alloc] initWithFrame: textRect];
|
|
|
|
[textView setBackgroundColor: [NSColor whiteColor]];
|
|
|
|
[textView setString:GSCHEME];
|
|
[textView setEditable:NO];
|
|
[textView setFont:[NSFont userFixedPitchFontOfSize:12]];
|
|
|
|
[textView setDelegate:vm];
|
|
[textView setHorizontallyResizable: NO];
|
|
[textView setVerticallyResizable: YES];
|
|
[textView setMinSize: NSMakeSize(0, 0)];
|
|
[textView setMaxSize: NSMakeSize(1E7, 1E7)];
|
|
[textView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable];
|
|
[[textView textContainer]
|
|
setContainerSize:NSMakeSize(textRect.size.width, 1e7)];
|
|
|
|
|
|
[[textView textContainer] setWidthTracksTextView: YES];
|
|
// Store the text view in an ivar
|
|
statTextView = textView;
|
|
|
|
[scrollView setDocumentView: textView];
|
|
// RELEASE(textView);
|
|
[panel setContentView: scrollView];
|
|
// RELEASE(scrollView);
|
|
|
|
// Make the Document the delegate of the panel
|
|
[panel setDelegate: self];
|
|
[panel setWorksWhenModal:NO];
|
|
|
|
// Make the text view the first responder
|
|
// [panel makeFirstResponder:textView];
|
|
[panel setTitle:@"GScheme Statistics"];
|
|
[panel display];
|
|
[panel orderFront:nil];
|
|
|
|
return self;
|
|
}
|
|
|
|
#define IPCWIDTH 100
|
|
#define IPCHEIGHT 30
|
|
|
|
|
|
- makeInterruptPanel
|
|
{
|
|
interruptPanel =
|
|
[[NSPanel alloc]
|
|
initWithContentRect:NSMakeRect(0, 0, IPCWIDTH, IPCHEIGHT)
|
|
styleMask:NSBorderlessWindowMask
|
|
backing:NSBackingStoreBuffered
|
|
defer:NO];
|
|
[interruptPanel setReleasedWhenClosed:NO];
|
|
|
|
NSButton *stopper;
|
|
stopper = [NSButton new];
|
|
[stopper setTitle:@"Stop"];
|
|
[stopper setTarget:vm];
|
|
[stopper setAction:@selector(interrupt:)];
|
|
|
|
[interruptPanel setContentView:stopper];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSPanel *)interruptPanel
|
|
{
|
|
return interruptPanel;
|
|
}
|
|
|
|
|
|
- input:(NSString *)data
|
|
{
|
|
[intTextView appendString:data];
|
|
return self;
|
|
}
|
|
|
|
- output:(NSString *)data
|
|
{
|
|
[intTextView appendString:data];
|
|
[intTextView placeCursorAtEnd];
|
|
return self;
|
|
}
|
|
|
|
- result:(id)item
|
|
{
|
|
[intTextView appendString:@"\n"];
|
|
[intTextView appendString:[VScheme valToString:item]];
|
|
[intTextView appendString:@"\n> "];
|
|
[intTextView placeCursorAtEnd];
|
|
return self;
|
|
}
|
|
|
|
- statistics:(NSString *)stats
|
|
{
|
|
NSString *sofar = [statTextView string];
|
|
[statTextView
|
|
replaceCharactersInRange:NSMakeRange([sofar length], 0)
|
|
withString:stats];
|
|
|
|
[statTextView placeCursorAtEnd];
|
|
|
|
return self;
|
|
}
|
|
|
|
- reset:(id)sender
|
|
{
|
|
[vm reset:self];
|
|
|
|
[intTextView setString:GSCHEME];
|
|
[intTextView appendString:@"> "];
|
|
[intTextView placeCursorAtEnd];
|
|
[[intTextView window] makeFirstResponder:intTextView];
|
|
|
|
[statTextView setString:GSCHEME];
|
|
}
|
|
|
|
- addExternal:(id)sender
|
|
{
|
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
|
|
|
[openPanel setTitle:@"Add external"];
|
|
[openPanel setAllowsMultipleSelection:NO];
|
|
[openPanel setPrompt:@"File:"];
|
|
[openPanel setCanChooseDirectories:NO];
|
|
|
|
if([openPanel
|
|
runModalForTypes:
|
|
[NSArray arrayWithObject:@"scm"]]==NSOKButton){
|
|
[[sender menu] addItemWithTitle:[openPanel filename]
|
|
action:@selector(evaluateExternal:)
|
|
keyEquivalent: @""];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
extern VScheme *vm;
|
|
extern NSWindow *interpreterWindow;
|
|
|
|
extern int errno;
|
|
|
|
- evaluateExternal:(id)sender
|
|
{
|
|
SCMInteractive *intView =
|
|
[[interpreterWindow contentView] documentView];
|
|
NSString *suffix = [intView getSuffix];
|
|
|
|
if([suffix length]>0){
|
|
[intView appendString:@"\n> "];
|
|
}
|
|
|
|
NSString *progstr;
|
|
if((progstr =
|
|
[NSString stringWithContentsOfFile:[sender title]])==nil){
|
|
NSString *msg = @"Load failed";
|
|
if(errno){
|
|
char *estr = strerror(errno);
|
|
msg = [msg stringByAppendingFormat:@": %s", estr];
|
|
}
|
|
|
|
NSRunAlertPanel(@"Error", msg, @"Ok", nil, nil);
|
|
return self;
|
|
}
|
|
|
|
BOOL res = [vm processString:progstr mode:MODE_EVALUATE];
|
|
if(res==NO){
|
|
NSRunAlertPanel(@"Error", [vm errmsg],
|
|
@"Ok", nil, nil);
|
|
}
|
|
else{
|
|
[interpreterWindow makeKeyAndOrderFront:self];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
- imageWindow:(NSWindow *)window
|
|
{
|
|
[imageWindows addObject:window];
|
|
[window setDelegate:self];
|
|
return self;
|
|
}
|
|
|
|
- envWindow:(NSWindow *)window
|
|
{
|
|
[envWindows addObject:window];
|
|
[window setDelegate:self];
|
|
return self;
|
|
}
|
|
|
|
- (void)windowWillClose:(NSNotification *)aNotification
|
|
{
|
|
NSWindow *win = [aNotification object];
|
|
|
|
if([imageWindows containsObject:win]==YES){
|
|
[imageWindows removeObject:win];
|
|
}
|
|
else if([envWindows containsObject:win]==YES){
|
|
[envWindows removeObject:win];
|
|
}
|
|
}
|
|
|
|
- closeImageWindows:(id)sender
|
|
{
|
|
NSArray *cwins = [NSArray arrayWithArray:imageWindows];
|
|
[cwins makeObjectsPerformSelector:@selector(close)];
|
|
return self;
|
|
}
|
|
|
|
- closeEnvWindows:(id)sender
|
|
{
|
|
NSArray *cwins = [NSArray arrayWithArray:envWindows];
|
|
[cwins makeObjectsPerformSelector:@selector(close)];
|
|
return self;
|
|
}
|
|
|
|
@end
|