// // GlkWindowView.m // CocoaGlk // // Created by Andrew Hunter on Wed Jun 11 2003. // Copyright (c) 2003 Andrew Hunter. All rights reserved. // #import "GlkWindowView.h" #import "GlkTextBufferView.h" #import "GlkTextGridView.h" #import "GlkGraphicsView.h" @implementation GlkWindowView - (id) initWithGlkWindow: (GlkWindow*) win { self = [super initWithFrame: NSMakeRect(0,0,0,0)]; if (self) { glkWin = win; [self setPostsFrameChangedNotifications: YES]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(frameChanged:) name: NSViewFrameDidChangeNotification object: self]; madeSubviews = NO; } return self; } - (void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver: self]; [super dealloc]; } -(BOOL) validateMenuItem: (id<NSMenuItem>)mi { if( [mi action] == @selector(toggleSpeechSynthesis:) ) { [mi setState: [glkWin speechSynthesisOn]]; return YES; } else return NO; } -(void) toggleSpeechSynthesis: (id)sender { [glkWin toggleSpeechSynthesis: sender]; } - (void) performArrangement { [self setPostsFrameChangedNotifications: NO]; NSRect bounds = [self bounds]; if (!madeSubviews) { // Clear out any old subviews [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)]; splitter = nil; } switch ([glkWin type]) { case wintype_Pair: { // Get the preferred sizes of the subviews leftSize = [[[glkWin left] view] preferredSize]; glui32 position = [glkWin position]; BOOL isFixed = [glkWin fixed]; BOOL isProportional = [glkWin proportional]; BOOL isVertical = (position==winmethod_Above||position==winmethod_Below)?YES:NO; float ourLen = isVertical?bounds.size.height:bounds.size.width; if (!isFixed && !isProportional) { // Is a resizable window - create the splitter if (!madeSubviews) { splitter = [[NSSplitView allocWithZone: [self zone]] initWithFrame: bounds]; [splitter setDelegate: self]; [splitter setVertical: !isVertical]; if (position == winmethod_Above || position == winmethod_Left) { [splitter addSubview: [[glkWin left] view]]; [splitter addSubview: [[glkWin right] view]]; } else { [splitter addSubview: [[glkWin right] view]]; [splitter addSubview: [[glkWin left] view]]; } [splitter setIsPaneSplitter: YES]; [self addSubview: splitter]; //[splitter release]; } [splitter setFrame: bounds]; ourLen -= [splitter dividerThickness]; } else { ourLen -= 2; if (!madeSubviews) { [self addSubview: [[glkWin left] view]]; [self addSubview: [[glkWin right] view]]; } } // Work out the actual sizes of the views to use if (!isFixed) { double lProp = leftSize / 100.0; leftSize = floor(lProp * ourLen + 0.5); rightSize = ourLen - leftSize; //rightSize = (1-lProp) * ourLen; } else { leftSize = floor(leftSize + 0.5); rightSize = ourLen - leftSize; if (rightSize < 4) { rightSize = 4; leftSize = ourLen-4; } } // Size the subviews NSRect leftRect, rightRect; leftRect = rightRect = bounds; if (position == winmethod_Above || position == winmethod_Below) { leftRect.size.height = leftSize; rightRect.size.height = rightSize; if (position == winmethod_Below) { rightRect.origin.y += leftSize+2; offset = leftSize; } else { leftRect.origin.y += rightSize+2; offset = rightSize; } } if (position == winmethod_Left || position == winmethod_Right) { leftRect.size.width = leftSize; rightRect.size.width = rightSize; if (position == winmethod_Left) { rightRect.origin.x += leftSize+2; offset = leftSize; } else { leftRect.origin.x += rightSize+2; offset = rightSize; } } if (!isFixed && !isProportional) { [[[glkWin left] view] setFrameSize: leftRect.size]; [[[glkWin right] view] setFrameSize: rightRect.size]; } else { [[[glkWin left] view] setFrame: leftRect]; [[[glkWin right] view] setFrame: rightRect]; } [[[glkWin left] view] updateSize]; [[[glkWin right] view] updateSize]; [[[glkWin left] view] performArrangement]; [[[glkWin right] view] performArrangement]; break; } case wintype_TextBuffer: if (!madeSubviews) { subview = [[GlkTextBufferView allocWithZone: [self zone]] initWithFrame: bounds window: glkWin]; [self addSubview: subview]; [subview release]; } [subview setFrame: bounds]; [(GlkTextBufferView*)subview performResize]; break; case wintype_TextGrid: if (!madeSubviews) { subview = [[GlkTextGridView allocWithZone: [self zone]] initWithFrame: bounds window: glkWin]; [self addSubview: subview]; [subview release]; } [subview setFrame: bounds]; break; case wintype_Graphics: if (!madeSubviews) { subview = [[GlkGraphicsView allocWithZone: [self zone]] initWithFrame: bounds window: glkWin]; [self addSubview: subview]; [subview release]; } [subview setFrame: bounds]; break; default: break; } [self windowRequestStatusChanged]; [self setPostsFrameChangedNotifications: YES]; madeSubviews = YES; } - (void) drawRect: (NSRect) r { if ([glkWin fixed] || [glkWin proportional]) { NSRect cRect1, cRect2; NSRect bounds = [self bounds]; if ([glkWin position] == winmethod_Above || [glkWin position] == winmethod_Below) { cRect1 = NSMakeRect(bounds.origin.x, bounds.origin.y + offset + 1, bounds.size.width, 1); cRect2 = cRect1; cRect2.origin.y -= 1; } else { cRect1 = NSMakeRect(bounds.origin.x + offset + 1, bounds.origin.y, 1, bounds.size.height); cRect2 = cRect1; cRect2.origin.x -= 1; } [[NSColor controlShadowColor] set]; NSRectFill(cRect1); [[NSColor controlHighlightColor] set]; NSRectFill(cRect2); } [super drawRect: r]; } - (double) preferredSize { if ([glkWin parent] != nil && [[glkWin parent] fixed]) { double sz = [glkWin sizeValue]; switch ([glkWin type]) { case wintype_Graphics: return sz; break; default: { NSDictionary* attr = [glkWin attributesForStyle: style_Normal]; NSSize fntSz = [@"0" sizeWithAttributes: attr]; double fntSz2 = ([[glkWin parent] position]==winmethod_Above||[[glkWin parent] position]==winmethod_Below)?fntSz.height:fntSz.width; return fntSz2 * sz; } } } else { return [glkWin sizeValue]; } } - (void) forceViewReorder { madeSubviews = NO; if ([glkWin type] == wintype_Pair) { [[[glkWin left] view] forceViewReorder]; [[[glkWin right] view] forceViewReorder]; } [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)]; } - (void) windowRequestStatusChanged { switch ([glkWin type]) { case wintype_TextBuffer: if (subview != nil) { [(GlkTextBufferView*)subview windowRequestStatusChanged]; } break; case wintype_TextGrid: if (subview != nil && ([glkWin requestedLineEvents] || [glkWin requestedCharEvents])) { [[[glkWin session] window] makeFirstResponder: subview]; } break; default: // Do nothing break; } } - (void) windowContentChanged { switch ([glkWin type]) { case wintype_TextBuffer: if (subview != nil) { [(GlkTextBufferView*)subview windowContentChanged]; } break; case wintype_TextGrid: case wintype_Graphics: if (subview) { [subview setNeedsDisplay: YES]; } break; default: // Do nothing break; } } - (void) focus { if (subview != nil && ([glkWin requestedLineEvents] || [glkWin requestedCharEvents])) { [[[glkWin session] window] makeFirstResponder: subview]; } } - (void)keyDown:(NSEvent *)theEvent { if (![glkWin handleKeyDown: theEvent]) { [super keyDown: theEvent]; } } - (NSLayoutManager*) layoutManager { // Need to know this to perform image layout if ([glkWin type] == wintype_TextBuffer) { return [(GlkTextBufferView*)subview layoutManager]; } else { return nil; } } // Event handling - (void) frameChanged: (NSNotification*) aNot { [self performArrangement]; } - (void) updateSize { NSRect bounds = [self bounds]; if ([glkWin type] == wintype_Graphics) { [glkWin sizeIsNow: GlkMakeSize(bounds.size.width, bounds.size.height)]; } else { NSDictionary* attr = [glkWin attributesForStyle: style_Normal]; NSSize fntSz = [@"0" sizeWithAttributes: attr]; GlkSize sz = GlkMakeSize(bounds.size.width / fntSz.width, bounds.size.height / fntSz.height); [glkWin sizeIsNow: sz]; } } @end |