File: programming/cocoa/MacScare-Source.zip/MacScare-Source/GlkWindowView.m


//
//  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

This code uses the PclZip Zip File reading code, which is subject to the GNU LGPL. It also uses the GeSHi syntax highlighter, subject to the GPL. Ask if you want this for your own web site, it's free.