Multiple drawing fixes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@4006 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-04-01 06:19:37 +00:00
parent a0e8d526a3
commit 1ee7514981
6 changed files with 718 additions and 378 deletions

View file

@ -1,3 +1,15 @@
Wed Mar 31 21:06:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSCell.m: Make bezeled and bordered mutually exclusive
- bug report by Jonathan Gapen
* Headers/AppKit/NSStringDrawing.h: Add all the string drawing stuff
* Source/NSStringDrawing.m: Rewrite from scratch - preliminary work.
* Source/NSButton.m: Removed redundant lock/unlock in drawing ops.
* Source/NSControl.m: tidy.
* Source/NSSplitView.m: avoid compiler warning.
* Source/NSTextFieldCell.m: tidy up, set draws background color in
initialisation, fix border/bezel drawing.
Wed Mar 31 17:32:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk> Wed Mar 31 17:32:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSView: ([-viewWithTag:]) complete rewrite to find nearest * Source/NSView: ([-viewWithTag:]) complete rewrite to find nearest

View file

@ -8,6 +8,8 @@
Author: Felipe A. Rodriguez <far@ix.netcom.com> Author: Felipe A. Rodriguez <far@ix.netcom.com>
Date: Aug 1998 Date: Aug 1998
Rewrite: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: Mar 1999
This file is part of the GNUstep GUI Library. This file is part of the GNUstep GUI Library.
@ -34,45 +36,42 @@
#include <Foundation/NSAttributedString.h> #include <Foundation/NSAttributedString.h>
#include <Foundation/NSGeometry.h> #include <Foundation/NSGeometry.h>
// global NSString attribute names used in ascessing // global NSString attribute names used in accessing
// the respective property in a text attributes // the respective property in a text attributes
// dictionary. if the key is not in the dictionary // dictionary. if the key is not in the dictionary
// the default value is assumed // the default value is assumed
extern NSString *NSFontAttributeName; // NSFont, Helvetica 12 extern NSString *NSFontAttributeName;
extern NSString *NSParagraphStyleAttributeName; // defaultParagraphStyle extern NSString *NSParagraphStyleAttributeName;
extern NSString *NSForegroundColorAttributeName; // NSColor, blackColor extern NSString *NSForegroundColorAttributeName;
extern NSString *NSUnderlineStyleAttributeName; // NSNumber int, 0 no line extern NSString *NSUnderlineStyleAttributeName;
extern NSString *NSSuperscriptAttributeName; // NSNumber int, 0 extern NSString *NSSuperscriptAttributeName;
extern NSString *NSBackgroundColorAttributeName; // NSColor, nil extern NSString *NSBackgroundColorAttributeName;
extern NSString *NSAttachmentAttributeName; // NSTextAttachment, nil extern NSString *NSAttachmentAttributeName;
extern NSString *NSLigatureAttributeName; // NSNumber int, 1 extern NSString *NSLigatureAttributeName;
extern NSString *NSBaselineOffsetAttributeName; // NSNumber float, 0 points extern NSString *NSBaselineOffsetAttributeName;
extern NSString *NSKernAttributeName; // NSNumber float, 0 extern NSString *NSKernAttributeName;
//
// Extended definitions:
//
// NSParagraphStyleAttributeName NSParagraphStyle, default is
// defaultParagraphStyle
//
// NSKernAttributeName NSNumber float, offset from
// baseline, amount to modify default
// kerning, if 0 kerning is off
// Currently supported values for NSUnderlineStyleAttributeName
enum enum
{ // Currently supported values for {
NSSingleUnderlineStyle = 1 // NSUnderlineStyleAttributeName GSNoUnderlineStyle = 0,
NSSingleUnderlineStyle = 1
}; };
@interface NSString (NSStringDrawing) @interface NSString (NSStringDrawing)
- (NSSize)sizeWithAttributes:(NSDictionary *)attrs; - (void) drawAtPoint: (NSPoint)point withAttributes: (NSDictionary*)attrs;
- (void) drawInRect: (NSRect)rect withAttributes: (NSDictionary*)attrs;
- (NSSize) sizeWithAttributes: (NSDictionary*)attrs;
@end @end
@interface NSAttributedString (NSStringDrawing) @interface NSAttributedString (NSStringDrawing)
- (NSSize)size; - (NSSize) size;
- (void) drawAtPoint: (NSPoint)point;
- (void) drawInRect: (NSRect)rect;
@end @end

View file

@ -508,11 +508,15 @@
- (void) setBezeled: (BOOL)flag - (void) setBezeled: (BOOL)flag
{ {
cell_bezeled = flag; cell_bezeled = flag;
if (cell_bezeled)
cell_bordered = NO;
} }
- (void) setBordered: (BOOL)flag - (void) setBordered: (BOOL)flag
{ {
cell_bordered = flag; cell_bordered = flag;
if (cell_bordered)
cell_bezeled = NO;
} }
// //
@ -670,14 +674,11 @@ static inline NSPoint centerSizeInRect(NSSize innerSize, NSRect outerRect)
// draw the border if needed // draw the border if needed
if ([self isBordered]) if ([self isBordered])
{ {
if ([self isBezeled]) NSFrameRect(cellFrame);
{ }
NSDrawWhiteBezel(cellFrame, cellFrame); else if ([self isBezeled])
} {
else NSDrawWhiteBezel(cellFrame, cellFrame);
{
NSFrameRect(cellFrame);
}
} }
[self drawInteriorWithFrame: cellFrame inView: controlView]; [self drawInteriorWithFrame: cellFrame inView: controlView];

View file

@ -1,4 +1,4 @@
/* /*
NSControl.m NSControl.m
The abstract control class The abstract control class
@ -9,14 +9,14 @@
Date: 1996 Date: 1996
Author: Felipe A. Rodriguez <far@ix.netcom.com> Author: Felipe A. Rodriguez <far@ix.netcom.com>
Date: August 1998 Date: August 1998
This file is part of the GNUstep GUI Library. This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version. version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@ -26,11 +26,13 @@
License along with this library; see the file COPYING.LIB. License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation, If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <gnustep/gui/config.h> #include <gnustep/gui/config.h>
#include <Foundation/NSException.h>
#include <AppKit/NSControl.h> #include <AppKit/NSControl.h>
#include <AppKit/NSColor.h>
#include <AppKit/NSEvent.h> #include <AppKit/NSEvent.h>
#include <AppKit/NSWindow.h> #include <AppKit/NSWindow.h>
#include <AppKit/NSApplication.h> #include <AppKit/NSApplication.h>
@ -48,39 +50,47 @@ static id _NSCONTROL_CELL_CLASS = nil;
// //
// Class methods // Class methods
// //
+ (void)initialize + (void) initialize
{ {
if (self == [NSControl class]) if (self == [NSControl class])
{ {
NSDebugLog(@"Initialize NSControl class\n"); NSDebugLog(@"Initialize NSControl class\n");
[self setVersion:1]; // Initial version [self setVersion: 1];
[self setCellClass:[NSCell class]]; // Set cell class }
}
} }
// //
// Setting the Control's Cell // Setting the Control's Cell
// //
+ (Class)cellClass { return _NSCONTROL_CELL_CLASS; } + (Class) cellClass
+ (void)setCellClass:(Class)factoryId { _NSCONTROL_CELL_CLASS = factoryId; } {
return _NSCONTROL_CELL_CLASS;
}
+ (void) setCellClass: (Class)factoryId
{
_NSCONTROL_CELL_CLASS = factoryId;
}
// //
// Instance methods // Instance methods
// //
- (id)initWithFrame:(NSRect)frameRect - (id) initWithFrame: (NSRect)frameRect
{ {
[super initWithFrame:frameRect]; [super initWithFrame: frameRect];
// create our cell if (_NSCONTROL_CELL_CLASS)
[self setCell:[[_NSCONTROL_CELL_CLASS new] autorelease]]; [self setCell: [[_NSCONTROL_CELL_CLASS new] autorelease]];
tag = 0; else
[self setCell: [[NSCell new] autorelease]];
tag = 0;
return self; return self;
} }
- (void)dealloc - (void) dealloc
{ {
[cell release]; // release our cell [cell release];
[super dealloc]; [super dealloc];
} }
// //
@ -97,219 +107,259 @@ static id _NSCONTROL_CELL_CLASS = nil;
} }
// //
// Setting the Control's Cell // Setting the Control's Cell
// //
- (id)cell { return cell; } - (id) cell
- (void)setCell:(NSCell *)aCell
{ {
if (![aCell isKindOfClass:[NSCell class]]) // must be a cell return cell;
return; }
[cell setControlView:nil]; - (void) setCell: (NSCell *)aCell
[aCell setControlView:self]; {
if (![aCell isKindOfClass: [NSCell class]])
[aCell retain]; [NSException raise: NSInvalidArgumentException
[cell release]; format: @"attempt to set silly value for control cell"];
cell = aCell;
[cell setControlView: nil];
[aCell setControlView: self];
[aCell retain];
[cell release];
cell = aCell;
} }
// //
// Enabling and Disabling the Control // Enabling and Disabling the Control
// //
- (BOOL)isEnabled { return [[self selectedCell] isEnabled]; } - (BOOL) isEnabled
- (void)setEnabled:(BOOL)flag { [[self selectedCell] setEnabled:flag]; }
//
// Identifying the Selected Cell
//
- (id)selectedCell
{ {
if ([cell state]) return [[self selectedCell] isEnabled];
return cell;
else
return nil;
} }
- (int)selectedTag - (void) setEnabled: (BOOL)flag
{ {
return [[self selectedCell] tag]; [[self selectedCell] setEnabled: flag];
} }
// //
// Setting the Control's Value // Identifying the Selected Cell
// //
- (double)doubleValue - (id) selectedCell
{ {
return [[self selectedCell] doubleValue]; if ([cell state])
return cell;
else
return nil;
} }
- (float)floatValue - (int) selectedTag
{ {
return [[self selectedCell] floatValue]; return [[self selectedCell] tag];
}
- (int)intValue
{
return [[self selectedCell] intValue];
}
- (void)setDoubleValue:(double)aDouble
{
[[self selectedCell] setDoubleValue:aDouble];
[self setNeedsDisplay:YES];
}
- (void)setFloatValue:(float)aFloat
{
[[self selectedCell] setFloatValue:aFloat];
[self setNeedsDisplay:YES];
}
- (void)setIntValue:(int)anInt
{
[[self selectedCell] setIntValue:anInt];
[self setNeedsDisplay:YES];
}
- (void)setNeedsDisplay { [super setNeedsDisplay:YES]; }
- (void)setStringValue:(NSString *)aString
{
[[self selectedCell] setStringValue:aString];
[self setNeedsDisplay:YES];
}
- (NSString *)stringValue
{
return [[self selectedCell] stringValue];
} }
// //
// Interacting with Other Controls // Setting the Control's Value
// //
- (void)takeDoubleValueFrom:(id)sender - (double) doubleValue
{ {
[[self selectedCell] takeDoubleValueFrom:sender]; return [[self selectedCell] doubleValue];
[self setNeedsDisplay:YES];
} }
- (void)takeFloatValueFrom:(id)sender - (float) floatValue
{ {
[[self selectedCell] takeFloatValueFrom:sender]; return [[self selectedCell] floatValue];
[self setNeedsDisplay:YES];
} }
- (void)takeIntValueFrom:(id)sender - (int) intValue
{ {
[[self selectedCell] takeIntValueFrom:sender]; return [[self selectedCell] intValue];
[self setNeedsDisplay:YES];
} }
- (void)takeStringValueFrom:(id)sender - (void) setDoubleValue: (double)aDouble
{ {
[[self selectedCell] takeStringValueFrom:sender]; [[self selectedCell] setDoubleValue: aDouble];
[self setNeedsDisplay:YES]; [self setNeedsDisplay: YES];
}
- (void) setFloatValue: (float)aFloat
{
[[self selectedCell] setFloatValue: aFloat];
[self setNeedsDisplay: YES];
}
- (void) setIntValue: (int)anInt
{
[[self selectedCell] setIntValue: anInt];
[self setNeedsDisplay: YES];
}
- (void) setNeedsDisplay
{
[super setNeedsDisplay: YES];
}
- (void) setStringValue: (NSString *)aString
{
[[self selectedCell] setStringValue: aString];
[self setNeedsDisplay: YES];
}
- (NSString *) stringValue
{
return [[self selectedCell] stringValue];
} }
// //
// Formatting Text // Interacting with Other Controls
// //
- (NSTextAlignment)alignment - (void) takeDoubleValueFrom: (id)sender
{ {
if (cell) [[self selectedCell] takeDoubleValueFrom: sender];
return [cell alignment]; [self setNeedsDisplay: YES];
else
return NSLeftTextAlignment;
} }
- (NSFont *)font - (void) takeFloatValueFrom: (id)sender
{ {
if (cell) [[self selectedCell] takeFloatValueFrom: sender];
return [cell font]; [self setNeedsDisplay: YES];
else
return nil;
} }
- (void)setAlignment:(NSTextAlignment)mode - (void) takeIntValueFrom: (id)sender
{ {
if (cell) [[self selectedCell] takeIntValueFrom: sender];
{ [self setNeedsDisplay: YES];
[cell setAlignment:mode];
[self setNeedsDisplay:YES];
}
} }
- (void)setFont:(NSFont *)fontObject - (void) takeStringValueFrom: (id)sender
{ {
if (cell) [[self selectedCell] takeStringValueFrom: sender];
[cell setFont:fontObject]; [self setNeedsDisplay: YES];
} }
- (void)setFloatingPointFormat:(BOOL)autoRange
left:(unsigned)leftDigits
right:(unsigned)rightDigits
{}
// //
// Managing the Field Editor // Formatting Text
// //
- (BOOL)abortEditing { return NO; } - (NSTextAlignment) alignment
- (NSText *)currentEditor { return nil; }
- (void)validateEditing {} // FIX ME
//
// Resizing the Control
//
- (void)calcSize {} // FIX ME
- (void)sizeToFit {}
//
// Displaying the Control and Cell
//
- (void)drawCell:(NSCell *)aCell
{ {
if (cell == aCell) if (cell)
{ return [cell alignment];
[self lockFocus]; else
[cell drawWithFrame:bounds inView:self]; return NSLeftTextAlignment;
[self unlockFocus];
}
} }
- (void)drawCellInside:(NSCell *)aCell - (NSFont *) font
{ {
if (cell == aCell) if (cell)
{ return [cell font];
[self lockFocus]; else
[cell drawInteriorWithFrame:bounds inView:self]; return nil;
[self unlockFocus];
}
} }
- (void)selectCell:(NSCell *)aCell - (void) setAlignment: (NSTextAlignment)mode
{ {
if (cell == aCell) if (cell)
[cell setState:1]; {
[cell setAlignment: mode];
[self setNeedsDisplay: YES];
}
} }
- (void)updateCell:(NSCell *)aCell { [self setNeedsDisplay:YES]; } - (void) setFont: (NSFont *)fontObject
- (void)updateCellInside:(NSCell *)aCell { [self setNeedsDisplay:YES]; }
//
// Target and Action
//
- (SEL)action { return [cell action]; }
- (BOOL)isContinuous { return [cell isContinuous]; }
- (BOOL)sendAction:(SEL)theAction to:(id)theTarget
{ {
NSApplication *theApp = [NSApplication sharedApplication]; if (cell)
[cell setFont: fontObject];
}
if (theAction && theTarget) - (void) setFloatingPointFormat: (BOOL)autoRange
return [theApp sendAction:theAction to:theTarget from:self]; left: (unsigned)leftDigits
else right: (unsigned)rightDigits
return NO; {
}
//
// Managing the Field Editor
//
- (BOOL) abortEditing
{
return NO;
}
- (NSText *) currentEditor
{
return nil;
}
- (void) validateEditing
{
} // FIX ME
//
// Resizing the Control
//
- (void) calcSize
{
} // FIX ME
- (void) sizeToFit
{
}
//
// Displaying the Control and Cell
//
- (void) drawCell: (NSCell *)aCell
{
if (cell == aCell)
{
[cell drawWithFrame: bounds inView: self];
}
}
- (void) drawCellInside: (NSCell *)aCell
{
if (cell == aCell)
{
[cell drawInteriorWithFrame: bounds inView: self];
}
}
- (void) selectCell: (NSCell *)aCell
{
if (cell == aCell)
[cell setState: 1];
}
- (void) updateCell: (NSCell *)aCell
{
[self setNeedsDisplay: YES];
}
- (void) updateCellInside: (NSCell *)aCell
{
[self setNeedsDisplay: YES];
}
//
// Target and Action
//
- (SEL) action
{
return [cell action];
}
- (BOOL) isContinuous
{
return [cell isContinuous];
}
- (BOOL) sendAction: (SEL)theAction to: (id)theTarget
{
NSApplication *theApp = [NSApplication sharedApplication];
if (theAction && theTarget)
return [theApp sendAction: theAction to: theTarget from: self];
else
return NO;
} }
- (int) sendActionOn: (int)mask - (int) sendActionOn: (int)mask
@ -317,124 +367,154 @@ NSApplication *theApp = [NSApplication sharedApplication];
return [cell sendActionOn: mask]; return [cell sendActionOn: mask];
} }
- (void)setAction:(SEL)aSelector { [cell setAction:aSelector]; } - (void) setAction: (SEL)aSelector
- (void)setContinuous:(BOOL)flag { [cell setContinuous:flag]; }
- (void)setTarget:(id)anObject { [cell setTarget:anObject]; }
- (id)target { return [cell target]; }
//
// Assigning a Tag
//
- (void)setTag:(int)anInt { tag = anInt; }
- (int)tag { return tag; }
//
// Tracking the Mouse
//
- (void)mouseDown:(NSEvent *)theEvent
{ {
NSApplication *theApp = [NSApplication sharedApplication]; [cell setAction: aSelector];
BOOL mouseUp = NO, done = NO;
NSEvent *e;
int oldActionMask;
NSPoint location;
unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask |
NSMouseMovedMask | NSLeftMouseDraggedMask |
NSRightMouseDraggedMask;
NSDebugLog(@"NSControl mouseDown\n");
if (![self isEnabled]) // If we are not enabled
return; // then ignore the mouse
if ([cell isContinuous]) // Have NSCell send action
oldActionMask = [cell sendActionOn:0]; // only if we're continuous
else
oldActionMask = [cell sendActionOn: NSPeriodicMask];
[window _captureMouse: self]; // capture the mouse
[self lockFocus];
e = theEvent;
while (!done) // loop until mouse goes up
{
location = [e locationInWindow];
location = [self convertPoint:location fromView:nil];
// ask the cell to track the mouse only
// if the mouse is within the cell
if ((location.x >= 0) && (location.x < bounds.size.width) &&
(location.y >= 0 && location.y < bounds.size.height))
{ // highlight the cell
[cell highlight: YES withFrame: bounds inView: self];
[window flushWindow];
if([cell trackMouse:e inRect:bounds ofView:self untilMouseUp:YES])
done = mouseUp = YES; // YES if the mouse
else // goes up in the cell
{
[cell highlight: NO withFrame: bounds inView: self];
[window flushWindow];
}
}
if (done) // if done break
break; // out of the loop
NSDebugLog(@"NSControl process another event\n");
e = [theApp nextEventMatchingMask:event_mask // get next event
untilDate:nil
inMode:NSEventTrackingRunLoopMode
dequeue:YES];
if ([e type] == NSLeftMouseUp) // If mouse went up
done = YES; // then we are done
}
[window _releaseMouse: self]; // Release mouse
if (mouseUp) // the mouse went up in the button
{
[self lockFocus]; // lockFocus gets released when button is
// drawn presseddown (NSView's displayRect)
// so we call it again, one of these needs
// to be optimized out FAR FIX ME
// [cell setState:![cell state]];
[cell highlight: NO withFrame: bounds inView: self]; // Unhighlight
[window flushWindow];
}
[self unlockFocus];
// Restore the old
[cell sendActionOn:oldActionMask]; // action mask
if (mouseUp) // Have the target
[self sendAction:[self action] to:[self target]]; // perform action
} }
- (BOOL)ignoresMultiClick { return NO; } - (void) setContinuous: (BOOL)flag
- (void)setIgnoresMultiClick:(BOOL)flag {} // FIX ME {
[cell setContinuous: flag];
}
- (void) setTarget: (id)anObject
{
[cell setTarget: anObject];
}
- (id) target
{
return [cell target];
}
//
// Assigning a Tag
//
- (void) setTag: (int)anInt
{
tag = anInt;
}
- (int) tag
{
return tag;
}
//
// Tracking the Mouse
//
- (void) mouseDown: (NSEvent *)theEvent
{
NSApplication *theApp = [NSApplication sharedApplication];
BOOL mouseUp = NO, done = NO;
NSEvent *e;
int oldActionMask;
NSPoint location;
unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask |
NSMouseMovedMask | NSLeftMouseDraggedMask |
NSRightMouseDraggedMask;
NSDebugLog(@"NSControl mouseDown\n");
if (![self isEnabled])
return;
if ([cell isContinuous])
oldActionMask = [cell sendActionOn: 0];
else
oldActionMask = [cell sendActionOn: NSPeriodicMask];
[window _captureMouse: self];
[self lockFocus];
e = theEvent;
while (!done) // loop until mouse goes up
{
location = [e locationInWindow];
location = [self convertPoint: location fromView: nil];
// ask the cell to track the mouse only
// if the mouse is within the cell
if ((location.x >= 0) && (location.x < bounds.size.width) &&
(location.y >= 0 && location.y < bounds.size.height))
{
[cell highlight: YES withFrame: bounds inView: self];
[window flushWindow];
if ([cell trackMouse: e
inRect: bounds
ofView: self
untilMouseUp: YES])
done = mouseUp = YES;
else
{
[cell highlight: NO withFrame: bounds inView: self];
[window flushWindow];
}
}
if (done)
break;
NSDebugLog(@"NSControl process another event\n");
e = [theApp nextEventMatchingMask: event_mask
untilDate: nil
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
if ([e type] == NSLeftMouseUp)
done = YES;
}
[window _releaseMouse: self];
if (mouseUp)
{
[self lockFocus];
// [cell setState: ![cell state]];
[cell highlight: NO withFrame: bounds inView: self];
[window flushWindow];
}
[self unlockFocus];
[cell sendActionOn: oldActionMask];
if (mouseUp)
[self sendAction: [self action] to: [self target]];
}
- (BOOL) ignoresMultiClick
{
return NO;
}
- (void) setIgnoresMultiClick: (BOOL)flag
{
}
// //
// Methods Implemented by the Delegate // Methods Implemented by the Delegate
// //
- (BOOL)control:(NSControl *)control - (BOOL) control: (NSControl *)control
textShouldBeginEditing:(NSText *)fieldEditor textShouldBeginEditing: (NSText *)fieldEditor
{ {
return NO; return NO;
} }
- (BOOL)control:(NSControl *)control - (BOOL) control: (NSControl *)control
textShouldEndEditing:(NSText *)fieldEditor textShouldEndEditing: (NSText *)fieldEditor
{ {
return NO; return NO;
} }
- (void)controlTextDidBeginEditing:(NSNotification *)aNotification - (void) controlTextDidBeginEditing: (NSNotification *)aNotification
{} {
}
- (void)controlTextDidEndEditing:(NSNotification *)aNotification - (void) controlTextDidEndEditing: (NSNotification *)aNotification
{} {
}
- (void)controlTextDidChange:(NSNotification *)aNotification - (void) controlTextDidChange: (NSNotification *)aNotification
{} {
}
// //
// NSCoding protocol // NSCoding protocol
@ -442,7 +522,7 @@ unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask |
- (void) encodeWithCoder: (NSCoder*)aCoder - (void) encodeWithCoder: (NSCoder*)aCoder
{ {
[super encodeWithCoder: aCoder]; [super encodeWithCoder: aCoder];
[aCoder encodeValueOfObjCType: @encode(int) at: &tag]; [aCoder encodeValueOfObjCType: @encode(int) at: &tag];
[aCoder encodeObject: cell]; [aCoder encodeObject: cell];
} }
@ -450,7 +530,7 @@ unsigned int event_mask = NSLeftMouseDownMask | NSLeftMouseUpMask |
- (id) initWithCoder: (NSCoder*)aDecoder - (id) initWithCoder: (NSCoder*)aDecoder
{ {
[super initWithCoder: aDecoder]; [super initWithCoder: aDecoder];
[aDecoder decodeValueOfObjCType: @encode(int) at: &tag]; [aDecoder decodeValueOfObjCType: @encode(int) at: &tag];
[aDecoder decodeValueOfObjCType: @encode(id) at: &cell]; [aDecoder decodeValueOfObjCType: @encode(id) at: &cell];

View file

@ -57,7 +57,7 @@
NSPoint p; NSPoint p;
NSEvent *e; NSEvent *e;
NSRect r, r1, bigRect, vis; NSRect r, r1, bigRect, vis;
id v, prev = nil; id v = nil, prev = nil;
float minCoord, maxCoord; float minCoord, maxCoord;
NSArray *subs = [self subviews]; NSArray *subs = [self subviews];
int offset = 0,i,count = [subs count]; int offset = 0,i,count = [subs count];

View file

@ -1,21 +1,23 @@
/* /*
NSStringDrawing.m NSStringDrawing.m
Categories which add measure capabilities to NSAttributedString Categories which add measure capabilities to NSAttributedString
and NSString. and NSString.
Copyright (C) 1997 Free Software Foundation, Inc. Copyright (C) 1997,1999 Free Software Foundation, Inc.
Author: Felipe A. Rodriguez <far@ix.netcom.com> Author: Felipe A. Rodriguez <far@ix.netcom.com>
Date: Aug 1998 Date: Aug 1998
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: Mar 1999 - rewrite from scratch
This file is part of the GNUstep GUI Library. This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version. version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@ -25,79 +27,325 @@
License along with this library; see the file COPYING.LIB. License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation, If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <Foundation/Foundation.h>
#include <AppKit/NSStringDrawing.h> #include <AppKit/NSStringDrawing.h>
#include <AppKit/AppKit.h> #include <AppKit/AppKit.h>
// by default tabs are measured as one
#define TABWIDTH 3 // char so this value is set to one
// minus the default tab width of 4
/*
* I know it's severely sub-optimal, but the NSString methods just
* use NSAttributes string to do the job.
*/
@implementation NSString (NSStringDrawing) @implementation NSString (NSStringDrawing)
- (NSSize)sizeWithAttributes:(NSDictionary *)attrs - (void) drawAtPoint: (NSPoint)point withAttributes: (NSDictionary *)attrs
{ {
NSFont *font; NSAttributedString *a;
const char *str = [self cString];
int i = 0, j = TABWIDTH;
static float tabSize;
float tabSumSize;
static float pointSize;
static NSFont *lastFont = nil;
while(*str != '\0') // calc the additional size a = [NSAttributedString allocWithZone: NSDefaultMallocZone()];
{ // to be added for tabs. [a initWithString: self attributes: attrs];
if(*str++ == '\t') [a drawAtPoint: point];
{ // j is initialized to the [a release];
i += j; // max number of spaces
j = TABWIDTH; // needed per tab. it then
} // varies in order to align
else // tabs to even multiples
j = j-- > 0 ? j : TABWIDTH; // of TABWIDTH + 1.
};
// if font is not
if(!(font = [attrs objectForKey:NSFontAttributeName])) // specified, use
font = [NSFont userFontOfSize:12]; // the default
if(font != lastFont) // update font info
{ // if font changes
tabSize = [font widthOfString:@"\t"];
lastFont = font;
pointSize = [font pointSize];
}
tabSumSize = (float)i * tabSize;
return NSMakeSize(([font widthOfString:self] + tabSumSize), pointSize);
} }
- (void) drawInRect: (NSRect)rect withAttributes: (NSDictionary *)attrs
{
NSAttributedString *a;
a = [NSAttributedString allocWithZone: NSDefaultMallocZone()];
[a initWithString: self attributes: attrs];
[a drawInRect: rect];
[a release];
}
- (NSSize) sizeWithAttributes: (NSDictionary *)attrs
{
NSAttributedString *a;
NSSize s;
a = [NSAttributedString allocWithZone: NSDefaultMallocZone()];
[a initWithString: self attributes: attrs];
s = [a size];
[a release];
return s;
}
@end @end
@implementation NSAttributedString (NSStringDrawing) @implementation NSAttributedString (NSStringDrawing)
- (NSSize)size // this method is static NSCharacterSet *nlset = nil;
{ // untested FIX ME
NSFont *font;
unsigned int length;
NSRange effectiveRange;
NSString *subString;
float pointSize;
float sumOfCharacterRange = 0;
length = [self length]; /* FIXME completely ignores paragraph style attachments and other layout info */
effectiveRange = NSMakeRange(0, 0); - (void) drawAtPoint: (NSPoint)point
{
NSGraphicsContext *ctxt = [NSGraphicsContext currentContext];
NSString *allText = [self string];
unsigned length = [allText length];
unsigned linePos = 0;
NSFont *defFont = [NSFont userFontOfSize: 12];
NSParagraphStyle *defStyle = [NSParagraphStyle defaultParagraphStyle];
NSColor *defFgCol = [NSColor textColor];
NSColor *defBgCol = nil;
BOOL isFlipped = [[ctxt focusView] isFlipped];
NSPoint start = point;
while (NSMaxRange(effectiveRange) < length) /*
{ * Build a character set containing only newline characters if necessary.
font = (NSFont*)[self attribute:NSFontAttributeName */
atIndex:NSMaxRange(effectiveRange) if (nlset == nil)
effectiveRange:&effectiveRange]; {
subString = [self attributedSubstringFromRange:effectiveRange]; NSCharacterSet *not_ws;
sumOfCharacterRange += [font widthOfString:subString]; NSMutableCharacterSet *new_set;
pointSize = MAX([font pointSize], pointSize);
} not_ws = [[NSCharacterSet whitespaceCharacterSet] invertedSet];
new_set = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
return NSMakeSize(sumOfCharacterRange, pointSize); [new_set formIntersectionWithCharacterSet: not_ws];
nlset = [new_set copy];
[new_set release];
}
/*
* Now produce output on a per-line basis.
*/
while (linePos < length)
{
NSRange line; // Range of current line.
NSRange eol; // Rnage of newline character.
float lineHeight; // Height of text in this line.
unsigned position; // Position in NSString.
/*
* Determine the range of the next line of text (in 'line') and set
* 'linePos' to point after the terminating newline character (if any).
*/
line = NSMakeRange(linePos, length - linePos);
eol = [allText rangeOfCharacterFromSet: nlset
options: NSLiteralSearch
range: line];
if (eol.length == 0)
eol.location = length;
else
line.length = eol.location - line.location;
linePos = NSMaxRange(eol);
position = line.location;
while (position < eol.location)
{
NSAttributedString *subAttr;
NSString *subString;
NSSize size;
NSFont *font;
NSParagraphStyle *style;
NSColor *bg;
NSColor *fg;
int underline;
int superscript;
float base;
float kern;
float ypos;
int ligature;
NSNumber *num;
NSRange maxRange;
NSRange range;
// Maximum range is up to end of line.
maxRange = NSMakeRange(position, eol.location - position);
// Get font and range over which it applies.
font = (NSFont*)[self attribute: NSFontAttributeName
atIndex: position
effectiveRange: &range];
if (font == nil)
font = defFont;
maxRange = NSIntersectionRange(maxRange, range);
// Get style and range over which it applies.
style = (NSParagraphStyle*)[self attribute: NSParagraphStyleAttributeName
atIndex: position
effectiveRange: &range];
if (style == nil)
style = defStyle;
maxRange = NSIntersectionRange(maxRange, range);
// Get background color and range over which it applies.
bg = (NSColor*)[self attribute: NSBackgroundColorAttributeName
atIndex: position
effectiveRange: &range];
if (bg == nil)
bg = defBgCol;
maxRange = NSIntersectionRange(maxRange, range);
// Get foreground color and range over which it applies.
fg = (NSColor*)[self attribute: NSForegroundColorAttributeName
atIndex: position
effectiveRange: &range];
if (fg == nil)
fg = defFgCol;
maxRange = NSIntersectionRange(maxRange, range);
// Get underline style and range over which it applies.
num = (NSNumber*)[self attribute: NSUnderlineStyleAttributeName
atIndex: position
effectiveRange: &range];
if (num == nil)
underline = GSNoUnderlineStyle; // No underline
else
underline = [num intValue];
maxRange = NSIntersectionRange(maxRange, range);
// Get superscript and range over which it applies.
num = (NSNumber*)[self attribute: NSSuperscriptAttributeName
atIndex: position
effectiveRange: &range];
if (num == nil)
superscript = 0;
else
superscript = [num intValue];
maxRange = NSIntersectionRange(maxRange, range);
// Get baseline offset and range over which it applies.
num = (NSNumber*)[self attribute: NSBaselineOffsetAttributeName
atIndex: position
effectiveRange: &range];
if (num == nil)
base = 0.0;
else
base = [num floatValue];
maxRange = NSIntersectionRange(maxRange, range);
// Get kern attribute and range over which it applies.
num = (NSNumber*)[self attribute: NSKernAttributeName
atIndex: position
effectiveRange: &range];
if (num == nil)
kern = 0.0;
else
kern = [num floatValue];
maxRange = NSIntersectionRange(maxRange, range);
// Get ligature attribute and range over which it applies.
num = (NSNumber*)[self attribute: NSLigatureAttributeName
atIndex: position
effectiveRange: &range];
if (num == nil)
ligature = 1;
else
ligature = [num intValue];
maxRange = NSIntersectionRange(maxRange, range);
/*
* Now, at last we have all the required text drawing attributes and
* we have a range over which ALL of them apply. We update our
* position to point past this range, then we grab the substring from
* the range, draw it, and update our drawing position.
*/
range = maxRange;
position = NSMaxRange(range); // Next position in string.
subAttr = [self attributedSubstringFromRange: range];
subString = [subAttr string];
size.width = [font widthOfString: subString];
size.height = [font pointSize];
lineHeight = size.height;
/*
* If we have a background color set - we fill in the
* region occupied by this substring.
*/
if (bg)
{
NSRect rect;
rect.origin = point;
rect.size = size;
if (isFlipped == NO)
rect.origin.y -= size.height;
[bg set];
NSRectFill(rect);
}
/*
* Set font and color, then draw the substring.
* NB. Our origin is top-left of the string so we need to
* calculate a vertical coordinate for the baseline of the
* text produced by psshow.
*/
if (isFlipped)
ypos = point.y + size.height - [font descender];
else
ypos = point.y - size.height + [font descender];
[fg set];
[font set];
DPSmoveto(ctxt, point.x, ypos);
DPSshow(ctxt, [subString cString]);
if (underline == NSSingleUnderlineStyle)
{
DPSmoveto(ctxt, point.x, ypos);
DPSlineto(ctxt, point.x + size.width - 1, ypos);
}
point.x += size.width; // Next point to draw from.
}
point.x = start.x;
if (isFlipped)
point.y += lineHeight;
else
point.y -= lineHeight;
}
}
- (void) drawInRect: (NSRect)rect
{
NSPoint point;
NSView *view = [NSView focusView];
NSRectClip(rect);
/*
* Since [-drawAtPoint:] positions the top-left corner of the text at
* the point, we locate the top-left corner of the rectangle to do the
* drawing.
*/
point.x = rect.origin.x;
if ([view isFlipped])
point.y = rect.origin.y;
else
point.y = rect.origin.y + rect.size.height;
[self drawAtPoint: point];
NSRectClip([view bounds]);
}
/* FIXME completely ignores paragraph style attachments and other layout info */
- (NSSize) size
{
unsigned length = [self length];
unsigned position = 0;
float height = 0;
float width = 0;
while (position < length)
{
NSRange range;
NSFont *font;
NSString *subString;
font = (NSFont*)[self attribute: NSFontAttributeName
atIndex: position
effectiveRange: &range];
subString = [[self attributedSubstringFromRange: range] string];
width += [font widthOfString: subString];
height = MAX([font pointSize], height);
position = NSMaxRange(range);
}
return NSMakeSize(width, height);
} }
@end @end