/** NSTabView The tabular view class Copyright (C) 1999,2000 Free Software Foundation, Inc. Author: Michael Hanni Date: 1999 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "AppKit/NSColor.h" #include "AppKit/NSFont.h" #include "AppKit/NSGraphics.h" #include "AppKit/NSImage.h" #include "AppKit/NSForm.h" #include "AppKit/NSMatrix.h" #include "AppKit/NSWindow.h" #include "AppKit/NSTabView.h" #include "AppKit/NSTabViewItem.h" #include "AppKit/PSOperators.h" @implementation NSTabView - (id) initWithFrame: (NSRect)rect { [super initWithFrame: rect]; // setup variables ASSIGN (_items, [NSMutableArray array]); ASSIGN (_font, [NSFont systemFontOfSize: 0]); _selected = nil; return self; } - (void) dealloc { RELEASE(_items); RELEASE(_font); [super dealloc]; } // tab management. - (void) addTabViewItem: (NSTabViewItem*)tabViewItem { [self insertTabViewItem: tabViewItem atIndex: [_items count]]; } - (void) insertTabViewItem: (NSTabViewItem*)tabViewItem atIndex: (int)index { [tabViewItem _setTabView: self]; [_items insertObject: tabViewItem atIndex: index]; if ([_delegate respondsToSelector: @selector(tabViewDidChangeNumberOfTabViewItems:)]) { [_delegate tabViewDidChangeNumberOfTabViewItems: self]; } } - (void) removeTabViewItem: (NSTabViewItem*)tabViewItem { unsigned i = [_items indexOfObject: tabViewItem]; if (i == NSNotFound) return; if ([tabViewItem isEqual: _selected]) { _selected = nil; } [_items removeObjectAtIndex: i]; if ([_delegate respondsToSelector: @selector(tabViewDidChangeNumberOfTabViewItems:)]) { [_delegate tabViewDidChangeNumberOfTabViewItems: self]; } } - (int) indexOfTabViewItem: (NSTabViewItem*)tabViewItem { return [_items indexOfObject: tabViewItem]; } - (int) indexOfTabViewItemWithIdentifier: (id)identifier { unsigned howMany = [_items count]; unsigned i; for (i = 0; i < howMany; i++) { id anItem = [_items objectAtIndex: i]; if ([[anItem identifier] isEqual: identifier]) return i; } return NSNotFound; } - (int) numberOfTabViewItems { return [_items count]; } - (NSTabViewItem*) tabViewItemAtIndex: (int)index { return [_items objectAtIndex: index]; } - (NSArray*) tabViewItems { return (NSArray*)_items; } - (void) selectFirstTabViewItem: (id)sender { [self selectTabViewItemAtIndex: 0]; } - (void) selectLastTabViewItem: (id)sender { [self selectTabViewItem: [_items lastObject]]; } - (void) selectNextTabViewItem: (id)sender { if ((unsigned)(_selected_item + 1) < [_items count]) [self selectTabViewItemAtIndex: _selected_item+1]; } - (void) selectPreviousTabViewItem: (id)sender { if (_selected_item > 0) [self selectTabViewItemAtIndex: _selected_item-1]; } - (NSTabViewItem*) selectedTabViewItem { if (_selected_item == NSNotFound || [_items count] == 0) return nil; return [_items objectAtIndex: _selected_item]; } - (void) selectTabViewItem: (NSTabViewItem*)tabViewItem { BOOL canSelect = YES; if ([_delegate respondsToSelector: @selector(tabView: shouldSelectTabViewItem:)]) { canSelect = [_delegate tabView: self shouldSelectTabViewItem: tabViewItem]; } if (canSelect) { NSView *selectedView; if (_selected != nil) { [_selected _setTabState: NSBackgroundTab]; /* NB: If [_selected view] is nil this does nothing, which is fine. */ [[_selected view] removeFromSuperview]; } _selected = tabViewItem; if ([_delegate respondsToSelector: @selector(tabView: willSelectTabViewItem:)]) { [_delegate tabView: self willSelectTabViewItem: _selected]; } _selected_item = [_items indexOfObject: _selected]; [_selected _setTabState: NSSelectedTab]; selectedView = [_selected view]; if (selectedView != nil) { [self addSubview: selectedView]; [selectedView setFrame: [self contentRect]]; [_window makeFirstResponder: [_selected initialFirstResponder]]; } /* FIXME - only mark the contentRect as needing redisplay! */ [self setNeedsDisplay: YES]; if ([_delegate respondsToSelector: @selector(tabView: didSelectTabViewItem:)]) { [_delegate tabView: self didSelectTabViewItem: _selected]; } } } - (void) selectTabViewItemAtIndex: (int)index { if (index < 0) [self selectTabViewItem: nil]; else [self selectTabViewItem: [_items objectAtIndex: index]]; } - (void) selectTabViewItemWithIdentifier:(id)identifier { int index = [self indexOfTabViewItemWithIdentifier: identifier]; [self selectTabViewItemAtIndex: index]; } - (void) takeSelectedTabViewItemFromSender: (id)sender { int index = -1; if ([sender respondsToSelector: @selector(indexOfSelectedItem)] == YES) { index = [sender indexOfSelectedItem]; } else if ([sender isKindOfClass: [NSMatrix class]] == YES) { int cols = [sender numberOfColumns]; int row = [sender selectedRow]; int col = [sender selectedColumn]; if (row >= 0 && col >= 0) { index = row * cols + col; } } [self selectTabViewItemAtIndex: index]; } - (void) setFont: (NSFont*)font { ASSIGN(_font, font); } - (NSFont*) font { return _font; } - (void) setTabViewType: (NSTabViewType)tabViewType { _type = tabViewType; } - (NSTabViewType) tabViewType { return _type; } - (void) setDrawsBackground: (BOOL)flag { _draws_background = flag; } - (BOOL) drawsBackground { return _draws_background; } - (void) setAllowsTruncatedLabels: (BOOL)allowTruncatedLabels { _truncated_label = allowTruncatedLabels; } - (BOOL) allowsTruncatedLabels { return _truncated_label; } - (void) setDelegate: (id)anObject { _delegate = anObject; } - (id) delegate { return _delegate; } // content and size - (NSSize) minimumSize { return NSZeroSize; } - (NSRect) contentRect { NSRect cRect = _bounds; if (_type == NSTopTabsBezelBorder) { cRect.origin.y += 1; cRect.origin.x += 0.5; cRect.size.width -= 2; cRect.size.height -= 18.5; } if (_type == NSNoTabsBezelBorder) { cRect.origin.y += 1; cRect.origin.x += 0.5; cRect.size.width -= 2; cRect.size.height -= 2; } if (_type == NSBottomTabsBezelBorder) { cRect.size.height -= 8; cRect.origin.y = 8; } return cRect; } // Drawing. - (void) drawRect: (NSRect)rect { NSGraphicsContext *ctxt = GSCurrentContext(); float borderThickness; int howMany = [_items count]; int i; NSRect previousRect; int previousState = 0; NSRect aRect = _bounds; DPSgsave(ctxt); switch (_type) { default: case NSTopTabsBezelBorder: aRect.size.height -= 16; NSDrawButton(aRect, NSZeroRect); borderThickness = 2; break; case NSBottomTabsBezelBorder: aRect.size.height -= 16; aRect.origin.y += 16; NSDrawButton(aRect, rect); aRect.origin.y -= 16; borderThickness = 2; break; case NSNoTabsBezelBorder: NSDrawButton(aRect, rect); borderThickness = 2; break; case NSNoTabsLineBorder: [[NSColor controlDarkShadowColor] set]; NSFrameRect(aRect); borderThickness = 1; break; case NSNoTabsNoBorder: borderThickness = 0; break; } if (!_selected) [self selectFirstTabViewItem: nil]; if (_type == NSNoTabsBezelBorder || _type == NSNoTabsLineBorder) { DPSgrestore(ctxt); return; } if (_type == NSBottomTabsBezelBorder) { for (i = 0; i < howMany; i++) { // where da tab be at? NSSize s; NSRect r; NSPoint iP; NSTabViewItem *anItem = [_items objectAtIndex: i]; NSTabState itemState; itemState = [anItem tabState]; s = [anItem sizeOfLabel: NO]; if (i == 0) { int iFlex = 0; iP.x = aRect.origin.x; iP.y = aRect.origin.y; if (itemState == NSSelectedTab) { iP.y += 1; [[NSImage imageNamed: @"common_TabDownSelectedLeft.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; iFlex = 1; } else if (itemState == NSBackgroundTab) { iP.y += 1; [[NSImage imageNamed: @"common_TabDownUnSelectedLeft.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; } else NSLog(@"Not finished yet. Luff ya.\n"); r.origin.x = aRect.origin.x + 13; r.origin.y = aRect.origin.y + 2; r.size.width = s.width; r.size.height = 15 + iFlex; DPSsetlinewidth(ctxt,1); DPSsetgray(ctxt, NSWhite); DPSmoveto(ctxt, r.origin.x, r.origin.y-1); DPSrlineto(ctxt, r.size.width, 0); DPSstroke(ctxt); [anItem drawLabel: NO inRect: r]; previousRect = r; previousState = itemState; } else { int iFlex = 0; iP.x = previousRect.origin.x + previousRect.size.width; iP.y = aRect.origin.y; if (itemState == NSSelectedTab) { iP.y += 1; iFlex = 1; [[NSImage imageNamed: @"common_TabDownUnSelectedToSelectedJunction.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; } else if (itemState == NSBackgroundTab) { if (previousState == NSSelectedTab) { iP.y += 1; [[NSImage imageNamed: @"common_TabDownSelectedToUnSelectedJunction.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y -= 1; iFlex = -1; } else { // iP.y += 1; [[NSImage imageNamed: @"common_TabDownUnSelectedJunction.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; //iP.y -= 1; iFlex = -1; } } else NSLog(@"Not finished yet. Luff ya.\n"); r.origin.x = iP.x + 13; r.origin.y = aRect.origin.y + 2; r.size.width = s.width; r.size.height = 15 + iFlex; // was 15 iFlex = 0; DPSsetlinewidth(ctxt,1); DPSsetgray(ctxt, NSWhite); DPSmoveto(ctxt, r.origin.x, r.origin.y - 1); DPSrlineto(ctxt, r.size.width, 0); DPSstroke(ctxt); [anItem drawLabel: NO inRect: r]; previousRect = r; previousState = itemState; } if (i == howMany-1) { iP.x += s.width + 13; if ([anItem tabState] == NSSelectedTab) [[NSImage imageNamed: @"common_TabDownSelectedRight.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; else if ([anItem tabState] == NSBackgroundTab) { // iP.y += 1; [[NSImage imageNamed: @"common_TabDownUnSelectedRight.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; // iP.y -= 1; } else NSLog(@"Not finished yet. Luff ya.\n"); } } } else if (_type == NSTopTabsBezelBorder) { for (i = 0; i < howMany; i++) { // where da tab be at? NSSize s; NSRect r; NSPoint iP; NSTabViewItem *anItem = [_items objectAtIndex: i]; NSTabState itemState; itemState = [anItem tabState]; s = [anItem sizeOfLabel: NO]; if (i == 0) { iP.x = aRect.origin.x; iP.y = aRect.size.height; if (itemState == NSSelectedTab) { iP.y -= 1; [[NSImage imageNamed: @"common_TabSelectedLeft.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; } else if (itemState == NSBackgroundTab) [[NSImage imageNamed: @"common_TabUnSelectedLeft.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; else NSLog(@"Not finished yet. Luff ya.\n"); r.origin.x = aRect.origin.x + 13; r.origin.y = aRect.size.height; r.size.width = s.width; r.size.height = 15; DPSsetlinewidth(ctxt,1); DPSsetgray(ctxt, NSWhite); DPSmoveto(ctxt, r.origin.x, r.origin.y+16); DPSrlineto(ctxt, r.size.width, 0); DPSstroke(ctxt); [anItem drawLabel: NO inRect: r]; previousRect = r; previousState = itemState; } else { iP.x = previousRect.origin.x + previousRect.size.width; iP.y = aRect.size.height; if (itemState == NSSelectedTab) { iP.y -= 1; [[NSImage imageNamed: @"common_TabUnSelectToSelectedJunction.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; } else if (itemState == NSBackgroundTab) { if (previousState == NSSelectedTab) { iP.y -= 1; [[NSImage imageNamed: @"common_TabSelectedToUnSelectedJunction.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; iP.y += 1; } else { [[NSImage imageNamed: @"common_TabUnSelectedJunction.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; } } else NSLog(@"Not finished yet. Luff ya.\n"); r.origin.x = iP.x + 13; r.origin.y = aRect.size.height; r.size.width = s.width; r.size.height = 15; DPSsetlinewidth(ctxt,1); DPSsetgray(ctxt, NSWhite); DPSmoveto(ctxt, r.origin.x, r.origin.y+16); DPSrlineto(ctxt, r.size.width, 0); DPSstroke(ctxt); [anItem drawLabel: NO inRect: r]; previousRect = r; previousState = itemState; } if (i == howMany-1) { iP.x += s.width + 13; if ([anItem tabState] == NSSelectedTab) [[NSImage imageNamed: @"common_TabSelectedRight.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; else if ([anItem tabState] == NSBackgroundTab) [[NSImage imageNamed: @"common_TabUnSelectedRight.tiff"] compositeToPoint: iP operation: NSCompositeSourceOver]; else NSLog(@"Not finished yet. Luff ya.\n"); } } } DPSgrestore(ctxt); } - (BOOL) isOpaque { return NO; } // Event handling. - (NSTabViewItem*) tabViewItemAtPoint: (NSPoint)point { int howMany = [_items count]; int i; point = [self convertPoint: point fromView: nil]; for (i = 0; i < howMany; i++) { NSTabViewItem *anItem = [_items objectAtIndex: i]; if(NSPointInRect(point,[anItem _tabRect])) return anItem; } return nil; } - (void) mouseDown: (NSEvent *)theEvent { NSPoint location = [theEvent locationInWindow]; NSTabViewItem *anItem = [self tabViewItemAtPoint: location]; if (anItem != nil && ![anItem isEqual: _selected]) { [self selectTabViewItem: anItem]; } } - (NSControlSize) controlSize { // FIXME return NSRegularControlSize; } /** * Not implemented. */ - (void) setControlSize: (NSControlSize)controlSize { // FIXME } - (NSControlTint) controlTint { // FIXME return NSDefaultControlTint; } /** * Not implemented. */ - (void) setControlTint: (NSControlTint)controlTint { // FIXME } // Coding. - (void) encodeWithCoder: (NSCoder*)aCoder { [super encodeWithCoder: aCoder]; [aCoder encodeObject: _items]; [aCoder encodeObject: _font]; [aCoder encodeValueOfObjCType: @encode(NSTabViewType) at: &_type]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_draws_background]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_truncated_label]; [aCoder encodeConditionalObject: _delegate]; [aCoder encodeValueOfObjCType: "i" at: &_selected_item]; } - (id) initWithCoder: (NSCoder*)aDecoder { self = [super initWithCoder: aDecoder]; if ([aDecoder allowsKeyedCoding]) { if ([aDecoder containsValueForKey: @"NSAllowTruncatedLabels"]) { [self setAllowsTruncatedLabels: [aDecoder decodeBoolForKey: @"NSAllowTruncatedLabels"]]; } if ([aDecoder containsValueForKey: @"NSDrawsBackground"]) { [self setDrawsBackground: [aDecoder decodeBoolForKey: @"NSDrawsBackground"]]; } if ([aDecoder containsValueForKey: @"NSFont"]) { [self setFont: [aDecoder decodeObjectForKey: @"NSFont"]]; } if ([aDecoder containsValueForKey: @"NSTabViewItems"]) { NSArray *items = [aDecoder decodeObjectForKey: @"NSTabViewItems"]; NSEnumerator *enumerator = [items objectEnumerator]; NSTabViewItem *item; while ((item = [enumerator nextObject]) != nil) { [self addTabViewItem: item]; } } if ([aDecoder containsValueForKey: @"NSSelectedTabViewItem"]) { [self selectTabViewItem: [aDecoder decodeObjectForKey: @"NSSelectedTabViewItem"]]; } if ([aDecoder containsValueForKey: @"NSTvFlags"]) { //int flags = [aDecoder decodeObjectForKey: @"NSTvFlags"]]; } } else { [aDecoder decodeValueOfObjCType: @encode(id) at: &_items]; [aDecoder decodeValueOfObjCType: @encode(id) at: &_font]; [aDecoder decodeValueOfObjCType: @encode(NSTabViewType) at: &_type]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_draws_background]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_truncated_label]; _delegate = [aDecoder decodeObject]; [aDecoder decodeValueOfObjCType: "i" at: &_selected_item]; _selected = [_items objectAtIndex: _selected_item]; } return self; } @end