Hi, I'm relatively new to Cocoa and brand new to this list. I have a
question about laying out text in an NSTextField.
I have a grid of NSTextFields. The fields wrap and change height based
on the number of lines of text in them. I would like to automatically
indent lines of text after the first line to visually distinguish
fields in the same column from each other (i.e. have the NSTextFields
lay out their automatically wrapped contents using hanging
indentation).
I've looked over (and been somewhat overwhelmed by) Apple's Text
Layout documentation
(http://developer.apple.com/documentation/Cocoa/Conceptual/
TextLayout/index.html)
and tried delving into the documentation for what seem to be the
relevant classes: NSLayoutManager, NSTypesetter, NSTextContainer, and
NSTextView. I've tried a few different solutions but nothing works
quite right.
I'm fairly sure I need to be using a subclass of NSTextContainer,
let's call it ReverseIndentationTextContainer. It contains one
instance variable: a float to store the indentation level (in pixels)
and relevant accessors, and it overrides
lineFragmentRectForProposedRect as follows:
- (NSRect)lineFragmentRectForProposedRect:(NSRect)proposedRect
sweepDirection:(NSLineSweepDirection)sweepDirection
movementDirection:(NSLineMovementDirection)movementDirection
remainingRect:(NSRect *)remainingRect;
{
if (proposedRect.origin.y > 0) {
proposedRect.origin.x += [self indentation];
}
return [super lineFragmentRectForProposedRect:proposedRect
sweepDirection:sweepDirection movementDirection:movementDirection
remainingRect:remainingRect];
}
So the question now is how to hook this into the app so it gets used.
Since we're dealing with textfields, it seems to make sense that we
need to attach it to the field editor. I tried simply calling
replaceTextContainer: on the field editor when editing of the fields
begins, in the textfield delegate's controlTextDidBeginEditing method.
It works beautifully until editing finishes, then the lines are no
longer indented.
Perhaps I need to subclass NSTextView and create a custom field editor
for the relevant fields? I also tried doing this. My subclass looks as
follows:
@interface ReverseIndentationFieldEditor : NSTextView {
ReverseIndentationTextContainer *textContainer;
float REVERSE_INDENTATION = 20.0;
}
@end
@implementation ReverseIndentationFieldEditor
-(id)init;
{
if ( self = [super init] ) {
[self setFieldEditor:YES];
textContainer = [[ReverseIndentationTextContainer alloc] init];
[textContainer setIndentation:REVERSE_INDENTATION];
[self replaceTextContainer:textContainer];
}
return self;
}
-(void)dealloc;
{
[textContainer release];
[super dealloc];
}
@end
I tried returning this field editor from my window delegate's
windowWillReturnFieldEditor method as follows:
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)
anObject;
{
if ( [[[anObject cell] representedObject]
isKindOfClass:[ReverseIndentContent class]] ) {
if (!reverseIndentFieldEditor)
reverseIndentFieldEditor = [[ReverseIndentFieldEditor alloc] init];
return reverseIndentFieldEditor;
}
return nil;
}
but had no luck. Same problem as before, only now the text fields
don't seem to honour the setWrap flag I pass in.
The latest thing I've tried doing is subclassing NSTextField and
NSTextFieldCell so I can hook in my NSTextView subclass through them,
overriding the following method in NSTextFieldCell:
- (NSText *)setUpFieldEditorAttributes:(NSText *)textObj;
{
textObj = [super setUpFieldEditorAttributes:textObj];
ReverseIndentationTextContainer *container =
[[ReverseIndentationTextContainer alloc] init];
[container setIndentation:20.0];
[(NSTextView*)textObj replaceTextContainer:container];
return textObj;
}
My NSTextField subclass is empty and exists solely so I can call
setCellClass: on it and assign it my custom cell class.
Nevermind the fact that the above code is horribly wasteful and
allocates a new field editor for each textfield - I'm still just
experimenting. This does pretty much the same thing as setting the
field editor in the window delegate, as you might expect.
So, obviously I have no idea what I'm doing.
Thanks in advance for any help.
-Greg