/** NSControl The abstract control class Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 Author: Richard Frith-Macdonald Date: August 1998 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 Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, see or write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #import #import #import #import #import #import #import "AppKit/NSActionCell.h" #import "AppKit/NSApplication.h" #import "AppKit/NSCell.h" #import "AppKit/NSControl.h" #import "AppKit/NSColor.h" #import "AppKit/NSEvent.h" #import "AppKit/NSFont.h" #import "AppKit/NSFontManager.h" #import "AppKit/NSKeyValueBinding.h" #import "AppKit/NSTextStorage.h" #import "AppKit/NSTextView.h" #import "AppKit/NSWindow.h" #import "GSBindingHelpers.h" #import "NSViewPrivate.h" #import "GSGuiPrivate.h" /* * Class variables */ static Class usedCellClass; static Class cellClass; static Class actionCellClass; static NSNotificationCenter *nc; /**

TODO Description

*/ @implementation NSControl /* * Class methods */ + (void) initialize { if (self == [NSControl class]) { [self setVersion: 1]; cellClass = [NSCell class]; usedCellClass = cellClass; actionCellClass = [NSActionCell class]; // Cache the notifiaction centre for editing notifications nc = [NSNotificationCenter defaultCenter]; // expose bindings [self exposeBinding: NSValueBinding]; [self exposeBinding: NSEnabledBinding]; [self exposeBinding: NSAlignmentBinding]; [self exposeBinding: NSFontBinding]; [self exposeBinding: NSFontNameBinding]; [self exposeBinding: NSFontSizeBinding]; } } /**

Returns the cell Class used by NSControl. Used by subclasses.

See Also: +setCellClass:

*/ + (Class) cellClass { return usedCellClass; } /**

Sets the cell Class used by NSControl to factoryId. Used by subclasses.

See Also: +setCellClass:

*/ + (void) setCellClass: (Class)factoryId { usedCellClass = factoryId ? factoryId : cellClass; } /**

Initializes and returns a new NSControl into the rectangle frameRect and create a new associated NSCell

See Also: -setCell:

*/ - (id) initWithFrame: (NSRect)frameRect { NSCell *cell = [[[self class] cellClass] new]; [super initWithFrame: frameRect]; [self setCell: cell]; RELEASE(cell); //_tag = 0; return self; } - (void) dealloc { RELEASE(_cell); [super dealloc]; } /**

Returns the NSControl's cell.

See Also: -setCell:

*/ - (id) cell { return _cell; } /**

Sets the NSControl's cell to aCell, Raises an NSInvalidArgumentException exception if aCell is not nil and if it is not a cell class.

See Also: -cell

*/ - (void) setCell: (NSCell *)aCell { if (aCell != nil && [aCell isKindOfClass: cellClass] == NO) [NSException raise: NSInvalidArgumentException format: @"attempt to set non-cell object for control cell"]; ASSIGN(_cell, aCell); } /**

Returns whether the selected cell of the NSControl is enabled.

See Also: -setEnabled: [NSCell-isEnabled]

*/ - (BOOL) isEnabled { return [[self selectedCell] isEnabled]; } /**

Sets whether the NSControl's selected cell is enabled. If flag is NO, this method abort the editing. This method marks self for display.

See Also: -isEnabled [NSCell-setEnabled:]

*/ - (void) setEnabled: (BOOL)flag { [[self selectedCell] setEnabled: flag]; if (!flag) [self abortEditing]; [self setNeedsDisplay: YES]; } /**

Returns the NSControl's selected cell.

*/ - (id) selectedCell { return _cell; } /**

Returns the tag of the NSControl's selected cell (if exists). -1 otherwise.

See Also: [NSCell-tag]

*/ - (NSInteger) selectedTag { NSCell *selected = [self selectedCell]; if (selected == nil) return -1; else return [selected tag]; } /**

Returns the value of the NSControl's selected cell as double.

See Also: -setDoubleValue: [NSCell-doubleValue] -intValue -floatValue -doubleValue -stringValue

*/ - (double) doubleValue { // The validation is performed by the NSActionCell return [[self selectedCell] doubleValue]; } /**

Returns the value of the NSControl's selected cell as float.

See Also: -setFloatValue: [NSCell-floatValue] -intValue -stringValue -doubleValue

*/ - (float) floatValue { return [[self selectedCell] floatValue]; } /**

Returns the value of the NSControl's selected cell as int.

See Also: -setIntValue: [NSCell-intValue] -floatValue -doubleValue -stringValue

*/ - (int) intValue { return [[self selectedCell] intValue]; } /**

Returns the value of the NSControl's selected cell as int.

See Also: -setIntegerValue: [NSCell-integerValue] -floatValue -doubleValue -stringValue

*/ - (NSInteger) integerValue { return [[self selectedCell] integerValue]; } /**

Returns the value of the NSControl's selected cell as NSString.

See Also: -setStringValue: [NSCell-stringValue] -intValue -floatValue -doubleValue -stringValue

*/ - (NSString *) stringValue { return [[self selectedCell] stringValue]; } - (id) objectValue { return [[self selectedCell] objectValue]; } /**

Sets the value of the NSControl's selected cell to double. If the selected cell is an action cell, it marks self for display.

See Also: -doubleValue [NSCell-setDoubleValue:] -setIntValue: -setStringValue: -setFloatValue:

*/ - (void) setDoubleValue: (double)aDouble { NSCell *selected = [self selectedCell]; BOOL wasEditing = [self abortEditing]; [selected setDoubleValue: aDouble]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; if (wasEditing) { [[self window] makeFirstResponder: self]; } } /**

Sets the value of the NSControl's selected cell to float. If the selected cell is an action cell, it marks self for display.

See Also: -floatValue [NSCell-setFloatValue:] -setIntValue: -setStringValue: -setDoubleValue:

*/ - (void) setFloatValue: (float)aFloat { NSCell *selected = [self selectedCell]; BOOL wasEditing = [self abortEditing]; [selected setFloatValue: aFloat]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; if (wasEditing) { [[self window] makeFirstResponder: self]; } } /**

Sets the value of the NSControl's selected cell to int. If the selected cell is an action cell, it marks self for display.

See Also: -intValue [NSCell-setIntValue:] -setDoubleValue: -setFloatValue: -setStringValue:

*/ - (void) setIntValue: (int)anInt { NSCell *selected = [self selectedCell]; BOOL wasEditing = [self abortEditing]; [selected setIntValue: anInt]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; if (wasEditing) { [[self window] makeFirstResponder: self]; } } /**

Sets the value of the NSControl's selected cell to int. If the selected cell is an action cell, it marks self for display.

See Also: -integerValue [NSCell-setIntegerValue:] -setDoubleValue: -setFloatValue: -setStringValue:

*/ - (void) setIntegerValue: (NSInteger)anInt { NSCell *selected = [self selectedCell]; BOOL wasEditing = [self abortEditing]; [selected setIntegerValue: anInt]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; if (wasEditing) { [[self window] makeFirstResponder: self]; } } /**

Sets the value of the NSControl's selected cell to NSString. If the selected cell is an action cell, it marks self for display.

See Also: -stringValue [NSCell-setStringValue:] -setIntValue: -setFloatValue: -setDoubleValue:

*/ - (void) setStringValue: (NSString *)aString { NSCell *selected = [self selectedCell]; BOOL wasEditing = [self abortEditing]; [selected setStringValue: aString]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; if (wasEditing) { [[self window] makeFirstResponder: self]; } } - (void) setObjectValue: (id)anObject { NSCell *selected = [self selectedCell]; BOOL wasEditing = [self abortEditing]; [selected setObjectValue: anObject]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; if (wasEditing) { [[self window] makeFirstResponder: self]; } } /**

Marks self for display.

*/ - (void) setNeedsDisplay { [super setNeedsDisplay: YES]; } /**

Sets the NSControl's selected cell to the sender's double value.

See Also: [NSCell-takeDoubleValueFrom:] -takeFloatValueFrom: takeIntValueFrom: takeStringValueFrom:

*/ - (void) takeDoubleValueFrom: (id)sender { [[self selectedCell] takeDoubleValueFrom: sender]; [self setNeedsDisplay: YES]; } /**

Sets the NSControl's selected cell to the sender's float value.

See Also: [NSCell-takeDoubleValueFrom:] -takeDoubleValueFrom: -takeIntValueFrom: -takeStringValueFrom:

*/ - (void) takeFloatValueFrom: (id)sender { [[self selectedCell] takeFloatValueFrom: sender]; [self setNeedsDisplay: YES]; } /**

Sets the NSControl's selected cell to the sender's float int.

See Also: [NSCell-takeIntValueFrom:] -takeDoubleValueFrom: -takeFloatValueFrom: -takeStringValueFrom:

*/ - (void) takeIntValueFrom: (id)sender { [[self selectedCell] takeIntValueFrom: sender]; [self setNeedsDisplay: YES]; } /**

Sets the NSControl's selected cell to the sender's float int.

See Also: [NSCell-takeIntegerValueFrom:] -takeDoubleValueFrom: -takeFloatValueFrom: -takeStringValueFrom:

*/ - (void) takeIntegerValueFrom: (id)sender { [[self selectedCell] takeIntegerValueFrom: sender]; [self setNeedsDisplay: YES]; } - (void) takeObjectValueFrom: (id)sender { [[self selectedCell] takeObjectValueFrom: sender]; [self setNeedsDisplay: YES]; } /**

Sets the NSControl's selected cell to the sender's float int.

See Also: [NSCell-takeDoubleValueFrom:] -takeDoubleValueFrom: -takeFloatValueFrom: -takeIntValueFrom:

*/ - (void) takeStringValueFrom: (id)sender { [[self selectedCell] takeStringValueFrom: sender]; [self setNeedsDisplay: YES]; } /**

Returns the alignment of the text in the NSControl's cell. Returns NSNaturalTextAlignment if the cell does not exists. See NSTextAlignment for more informations.

See Also: -setAlignment: [NSCell-alignment]

*/ - (NSTextAlignment) alignment { if (_cell) return [_cell alignment]; else return NSNaturalTextAlignment; } /**

Returns the font of the text in the NSControl's cell. Returns nil if the cell does not exists.

See Also: -setFont: [NSCell-font]

*/ - (NSFont *) font { if (_cell) return [_cell font]; else return nil; } /**

Sets the alignment of the text in the NSControl's cell to mode. This method abort the editing and marks self for display if the cell is an NSActionCell. See NSTextAlignment for more informations.

See Also: -alignment [NSCell-setAlignment:] -abortEditing

*/ - (void) setAlignment: (NSTextAlignment)mode { if (_cell) { [self abortEditing]; [_cell setAlignment: mode]; if (![_cell isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; } } /**

Sets the font of the text in the NSControl's cell and the editor object (if exists) to fontObject.

See Also: -font [NSCell-setFont:] -currentEditor

*/ - (void) setFont: (NSFont *)fontObject { if (_cell) { NSText *editor = [self currentEditor]; [_cell setFont: fontObject]; if (editor != nil) [editor setFont: fontObject]; } } - (void) setFloatingPointFormat: (BOOL)autoRange left: (NSUInteger)leftDigits right: (NSUInteger)rightDigits { [self abortEditing]; [_cell setFloatingPointFormat: autoRange left: leftDigits right: rightDigits]; if (![_cell isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; } - (void) setFormatter: (NSFormatter*)newFormatter { if (_cell) { [_cell setFormatter: newFormatter]; if (![_cell isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; } } - (id) formatter { return [_cell formatter]; } - (NSWritingDirection) baseWritingDirection { return [_cell baseWritingDirection]; } - (void) setBaseWritingDirection: (NSWritingDirection)direction { if (_cell) { [_cell setBaseWritingDirection: direction]; if (![_cell isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; } } /**

Sends an [NSCell-endEditing:] message to the current object used to edit the NSControl. Returns NO if the the currentEditor does not exists, YES otherwise.

*/ - (BOOL) abortEditing { NSText *text; text = [self currentEditor]; if (text == nil) { return NO; } [[self selectedCell] endEditing: text]; return YES; } /**

Returns the NSText object used when editing the NSControl.

*/ - (NSText *) currentEditor { if (_cell != nil) { NSText *text; text = [_window fieldEditor: NO forObject: self]; if (([text delegate] == self) && ([_window firstResponder] == text)) { return text; } } return nil; } /** */ - (void) validateEditing { NSText *text; text = [self currentEditor]; if (text == nil) { return; } if ([text isRichText]) { NSAttributedString *attr; NSTextStorage *storage; int len; storage = [(NSTextView*)text textStorage]; len = [storage length]; attr = [storage attributedSubstringFromRange: NSMakeRange(0, len)]; [[self selectedCell] setAttributedStringValue: attr]; } else { NSString *string; string = AUTORELEASE([[text string] copy]); [[self selectedCell] setStringValue: string]; } } /* * Text delegate methods */ /**

Invokes when the text cell starts to be editing.This methods posts a NSControlTextDidBeginEditingNotification with a dictionary containing the NSFieldEditor as user info

See Also: [NSNotificationCenter-postNotificationName:object:userInfo:]

*/ - (void) textDidBeginEditing: (NSNotification *)aNotification { NSMutableDictionary *dict; dict = [[NSMutableDictionary alloc] initWithDictionary: [aNotification userInfo]]; [dict setObject: [aNotification object] forKey: @"NSFieldEditor"]; [nc postNotificationName: NSControlTextDidBeginEditingNotification object: self userInfo: dict]; RELEASE(dict); } /**

Invokes when the text cell is changed. This methods posts a NSControlTextDidChangeNotification with a dictionary containing the NSFieldEditor as user info

See Also: [NSNotificationCenter-postNotificationName:object:userInfo:]

*/ - (void) textDidChange: (NSNotification *)aNotification { NSMutableDictionary *dict; GSKeyValueBinding *theBinding; dict = [[NSMutableDictionary alloc] initWithDictionary: [aNotification userInfo]]; [dict setObject: [aNotification object] forKey: @"NSFieldEditor"]; [nc postNotificationName: NSControlTextDidChangeNotification object: self userInfo: dict]; RELEASE(dict); theBinding = [GSKeyValueBinding getBinding: NSValueBinding forObject: self]; if (theBinding != nil) { NSDictionary *options = [theBinding->info objectForKey: NSOptionsKey]; NSNumber *num = [options objectForKey: NSContinuouslyUpdatesValueBindingOption]; if ([num boolValue]) { [theBinding reverseSetValueFor: @"objectValue"]; } } } /**

Invokes when the text cell is changed. This methods posts a NSControlTextDidEndEditingNotification a dictionary containing the NSFieldEditor as user info

See Also: [NSNotificationCenter-postNotificationName:object:userInfo:]

*/ - (void) textDidEndEditing: (NSNotification *)aNotification { NSMutableDictionary *dict; [self validateEditing]; [self abortEditing]; dict = [[NSMutableDictionary alloc] initWithDictionary: [aNotification userInfo]]; [dict setObject: [aNotification object] forKey: @"NSFieldEditor"]; [nc postNotificationName: NSControlTextDidEndEditingNotification object: self userInfo: dict]; RELEASE(dict); } /**

Recalculates the internal size by sending [NSCell-calcDrawInfo:] to the cell.

*/ - (void) calcSize { [_cell calcDrawInfo: [self bounds]]; } /**

Resizes the NSControl to fits the NSControl's cell size.

See Also: [NSCell-cellSize]

*/ - (void) sizeToFit { [self setFrameSize: [_cell cellSize]]; } /**

Returns whether the NSControl's cell is opaque

*/ - (BOOL) isOpaque { return [_cell isOpaque]; } - (void) drawRect: (NSRect)aRect { [self drawCell: _cell]; } /**

Redraws a aCell if it is the NSControl's cell.

See Also: -setCell: [NSCell-drawWithFrame:inView:]

*/ - (void) drawCell: (NSCell *)aCell { if (_cell == aCell) { [_cell drawWithFrame: _bounds inView: self]; } } /**

Redraws a aCell's inside if it is the NSControl's cell.

See Also: -setCell: [NSCell-drawInteriorWithFrame:inView:]

*/ - (void) drawCellInside: (NSCell *)aCell { if (_cell == aCell) { [_cell drawInteriorWithFrame: _bounds inView: self]; } } /**

Sets the aCell's state to NSOnState and marks self for display if it is the NSControl's cell.

*/ - (void) selectCell: (NSCell *)aCell { if (_cell == aCell) { [_cell setState: NSOnState]; [self setNeedsDisplay: YES]; } } /**

Marks self for display.

*/ - (void) updateCell: (NSCell *)aCell { [self setNeedsDisplay: YES]; } /**

Marks self for display.

*/ - (void) updateCellInside: (NSCell *)aCell { [self setNeedsDisplay: YES]; } /**

Returns the NSControl's cell action method.

See Also: -setAction: [NSCell-action]

*/ - (SEL) action { return [_cell action]; } /**

Returns whether the NSControl's cell can continuously sends its action message.

See Also: -setContinuous: [NSCell-isContinuous]

*/ - (BOOL) isContinuous { return [_cell isContinuous]; } /**

Asks the NSApplication to send an action theAction with theTarget as target to NSControl. Returns NO if theAction is nil or if NSApplication can not send the action.

See Also: [NSApplication-sendAction:to:from:]

*/ - (BOOL) sendAction: (SEL)theAction to: (id)theTarget { GSKeyValueBinding *theBinding; theBinding = [GSKeyValueBinding getBinding: NSValueBinding forObject: self]; if (theBinding != nil) [theBinding reverseSetValueFor: @"objectValue"]; if (theAction) return [NSApp sendAction: theAction to: theTarget from: self]; else return NO; } - (NSInteger) sendActionOn: (NSInteger)mask { return [_cell sendActionOn: mask]; } /**

Sets the NSControl's cell action method.

See Also: -action [NSCell-setAction:]

*/ - (void) setAction: (SEL)aSelector { [_cell setAction: aSelector]; } /**

Sets whether the NSControl's cell can continuously sends its action message.

See Also: -isContinuous [NSCell-setContinuous:]

*/ - (void) setContinuous: (BOOL)flag { [_cell setContinuous: flag]; } /**

Sets the target object of the NSControl's cell to anObject.

See Also: -target [NSCell-setTarget:]

*/ - (void) setTarget: (id)anObject { [_cell setTarget: anObject]; } /**

Returns the target object of the NSControl's cell.

See Also: -setTarget: [NSCell-target]

*/ - (id) target { return [_cell target]; } /* * Attributed string handling */ - (void) setAttributedStringValue: (NSAttributedString*)attribStr { NSCell *selected = [self selectedCell]; [self abortEditing]; [selected setAttributedStringValue: attribStr]; if (![selected isKindOfClass: actionCellClass]) [self setNeedsDisplay: YES]; } - (NSAttributedString*) attributedStringValue { NSCell *selected = [self selectedCell]; if (selected == nil) { return AUTORELEASE([NSAttributedString new]); } // As this method is not defined for NSActionCell, we have // to do the validation here. [self validateEditing]; return [selected attributedStringValue]; } /** Assigning a Tag */ - (void) setTag: (NSInteger)anInt { _tag = anInt; } /**

Returns the NSControl tag

See Also: -setTag:

*/ - (NSInteger) tag { return _tag; } /* * Activation */ /** * Simulates a single mouse click on the control. This method calls the cell's * method performClickWithFrame:inView:. Take note that sender is not * used. */ - (void) performClick: (id)sender { [_cell performClickWithFrame: [self bounds] inView: self]; } - (BOOL) refusesFirstResponder { return [[self selectedCell] refusesFirstResponder]; } - (void) setRefusesFirstResponder:(BOOL)flag { [[self selectedCell] setRefusesFirstResponder: flag]; } - (BOOL) acceptsFirstResponder { return [[self selectedCell] acceptsFirstResponder]; } - (void) mouseDown: (NSEvent *)theEvent { unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask | NSMouseMovedMask | NSLeftMouseDraggedMask | NSOtherMouseDraggedMask | NSRightMouseDraggedMask; NSEvent *e = nil; // If not enabled ignore mouse clicks if (![self isEnabled]) { [super mouseDown: theEvent]; return; } // Ignore multiple clicks, if configured to do so if (_ignoresMultiClick && ([theEvent clickCount] > 1)) { [super mouseDown: theEvent]; return; } // Make sure self does not go away during the processing of the event RETAIN(self); // loop until mouse goes up e = theEvent; while (1) { NSPoint location = [self convertPoint: [e locationInWindow] fromView: nil]; // ask the cell to track the mouse only, // if the mouse is within the cell if ([self mouse: location inRect: _bounds]) { BOOL done; [_cell setHighlighted: YES]; [self setNeedsDisplay: YES]; done = [_cell trackMouse: e inRect: _bounds ofView: self untilMouseUp: [[_cell class] prefersTrackingUntilMouseUp]]; [_cell setHighlighted: NO]; [self setNeedsDisplay: YES]; if (done) { break; } } e = [NSApp nextEventMatchingMask: event_mask untilDate: [NSDate distantFuture] inMode: NSEventTrackingRunLoopMode dequeue: YES]; if ([e type] == NSLeftMouseUp) { break; } } // undo initial retain RELEASE(self); } - (BOOL) shouldBeTreatedAsInkEvent: (NSEvent *)theEvent { return NO; } - (void) resetCursorRects { [_cell resetCursorRect: _bounds inView: self]; } /**

Returns wheter multiple clicks are ignored.

See Also: -setIgnoresMultiClick: -mouseDown:

*/ - (BOOL) ignoresMultiClick { return _ignoresMultiClick; } /**

Sets wheter multiple clicks are ignored.

See Also: -ignoresMultiClick -mouseDown:

*/ - (void) setIgnoresMultiClick: (BOOL)flag { _ignoresMultiClick = flag; } /**

Returns the mouse flags. This flags are usally sets in the NSCell-trackMouse:inRect:ofView:untilMouseUp: method.

This is a NeXTStep 3.3 method, no longer officially supported.

*/ - (NSInteger) mouseDownFlags { return [[self selectedCell] mouseDownFlags]; } /* * NSCoding protocol */ - (void) encodeWithCoder: (NSCoder*)aCoder { [super encodeWithCoder: aCoder]; if ([aCoder allowsKeyedCoding]) { [aCoder encodeObject: [self cell] forKey: @"NSCell"]; [aCoder encodeBool: [self isEnabled] forKey: @"NSEnabled"]; if (_tag) { [aCoder encodeInt: [self tag] forKey: @"NSTag"]; } } else { encode_NSInteger(aCoder, &_tag); [aCoder encodeObject: _cell]; [aCoder encodeValueOfObjCType: @encode(BOOL) at: &_ignoresMultiClick]; } } - (id) initWithCoder: (NSCoder*)aDecoder { self = [super initWithCoder: aDecoder]; if (self == nil) { return nil; } if ([aDecoder allowsKeyedCoding]) { NSCell *cell = [aDecoder decodeObjectForKey: @"NSCell"]; if (cell != nil) { [self setCell: cell]; } else { // This is needed for subclasses without cells, like NSColorWeel // as we store some properties only on the cell. cell = [[[self class] cellClass] new]; [self setCell: cell]; RELEASE(cell); } if ([aDecoder containsValueForKey: @"NSEnabled"]) { // Don't use this information as it also comes from the cell // and NSComboBox has always YES here, even when disabled //[self setEnabled: [aDecoder decodeBoolForKey: @"NSEnabled"]]; } if ([aDecoder containsValueForKey: @"NSTag"]) { int tag = [aDecoder decodeIntForKey: @"NSTag"]; [self setTag: tag]; } } else { decode_NSInteger(aDecoder, &_tag); [aDecoder decodeValueOfObjCType: @encode(id) at: &_cell]; [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_ignoresMultiClick]; } return self; } - (void) bind: (NSString *)binding toObject: (id)anObject withKeyPath: (NSString *)keyPath options: (NSDictionary *)options { if ([binding isEqual: NSValueBinding]) { GSKeyValueBinding *kvb; [self unbind: binding]; kvb = [[GSKeyValueBinding alloc] initWithBinding: @"objectValue" withName: NSValueBinding toObject: anObject withKeyPath: keyPath options: options fromObject: self]; // The binding will be retained in the binding table RELEASE(kvb); } else if ([binding hasPrefix: NSEnabledBinding]) { GSKeyValueBinding *kvb; [self unbind: binding]; kvb = [[GSKeyValueAndBinding alloc] initWithBinding: NSEnabledBinding withName: binding toObject: anObject withKeyPath: keyPath options: options fromObject: self]; // The binding will be retained in the binding table RELEASE(kvb); } else { [super bind: binding toObject: anObject withKeyPath: keyPath options: options]; } } - (void) setValue: (id)anObject forKey: (NSString*)aKey { if ([aKey isEqual: NSFontNameBinding]) { [self setFont: [[NSFontManager sharedFontManager] convertFont: [self font] toFace: anObject]]; } else if ([aKey isEqual: NSFontSizeBinding]) { [self setFont: [[NSFontManager sharedFontManager] convertFont: [self font] toSize: [anObject doubleValue]]]; } else { [super setValue: anObject forKey: aKey]; } } - (id) valueForKey: (NSString*)aKey { if ([aKey isEqual: NSFontNameBinding]) { return [[self font] fontName]; } else if ([aKey isEqual: NSFontSizeBinding]) { return [NSNumber numberWithDouble: (double)[[self font] pointSize]]; } else { return [super valueForKey: aKey]; } } - (NSSize) sizeThatFits: (NSSize)size { // FIXME: This is a stub return size; } @end @implementation NSControl(KeyViewLoop) - (void) _setUpKeyViewLoopWithNextKeyView: (NSView *)nextKeyView { // Controls are expected to have no subviews //NSLog(@"%@@%p -_setUpKeyViewLoopWithKeyKeyView:%@@%p", [self class], self, [nextKeyView class], nextKeyView); [self setNextKeyView: nextKeyView]; } @end