1/** <title>NSFormCell</title> 2 3 <abstract>The cell class for the NSForm control</abstract> 4 5 Copyright (C) 1996, 1999 Free Software Foundation, Inc. 6 7 Author: Ovidiu Predescu <ovidiu@net-community.com> 8 Date: March 1997 9 Author: Nicola Pero <n.pero@mi.flashnet.it> 10 Date: November 1999 11 12 This file is part of the GNUstep GUI Library. 13 14 This library is free software; you can redistribute it and/or 15 modify it under the terms of the GNU Lesser General Public 16 License as published by the Free Software Foundation; either 17 version 2 of the License, or (at your option) any later version. 18 19 This library is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 Lesser General Public License for more details. 23 24 You should have received a copy of the GNU Lesser General Public 25 License along with this library; see the file COPYING.LIB. 26 If not, see <http://www.gnu.org/licenses/> or write to the 27 Free Software Foundation, 51 Franklin Street, Fifth Floor, 28 Boston, MA 02110-1301, USA. 29*/ 30 31#include "config.h" 32#import <Foundation/NSNotification.h> 33#import "AppKit/NSAttributedString.h" 34#import "AppKit/NSColor.h" 35#import "AppKit/NSFormCell.h" 36#import "AppKit/NSFont.h" 37#import "AppKit/NSGraphics.h" 38#import "AppKit/NSTextFieldCell.h" 39#import "GNUstepGUI/GSTheme.h" 40 41/** <p>TODO Description </p> 42 */ 43@implementation NSFormCell 44+ (void) initialize 45{ 46 if (self == [NSFormCell class]) 47 { 48 [self setVersion: 1]; 49 } 50} 51 52/* The title attributes are those inherited from the NSActionCell class. */ 53- (id) init 54{ 55 return [self initTextCell: @"Field:"]; 56} 57 58/** <p>Initializes and returns new NSFormCell with aString as its title and 59 the text cell with an empty NSString.</p> 60 <p>See Also: [NSCell-initTextCell:]</p> 61 */ 62- (id) initTextCell: (NSString *)aString 63{ 64 self = [super initTextCell: @""]; 65 if (nil == self) 66 return nil; 67 68 _cell.is_bezeled = YES; 69 _cell.is_editable = YES; 70 [self setAlignment: NSLeftTextAlignment]; 71 _titleCell = [[NSCell alloc] initTextCell: aString]; 72 [_titleCell setAlignment: NSRightTextAlignment]; 73 _formcell_auto_title_width = YES; 74 _displayedTitleWidth = -1; 75 76 return self; 77} 78 79- (void)dealloc 80{ 81 RELEASE(_titleCell); 82 TEST_RELEASE(_placeholder); 83 [super dealloc]; 84} 85 86/** <p>Returns whether the NSFormCell is Opaque. Returns YES if 87 the textCell and the title cell are both Opaque, NO otherwise</p> 88 <p>See Also: [NSCell-isOpaque]</p> 89 */ 90- (BOOL)isOpaque 91{ 92 return [_titleCell isOpaque] && [super isOpaque]; 93} 94 95- (void)setAttributedTitle: (NSAttributedString *)anAttributedString 96{ 97 [_titleCell setAttributedStringValue: anAttributedString]; 98 if (_formcell_auto_title_width) 99 { 100 // Invalidates title width 101 _displayedTitleWidth = -1; 102 // Update the control(s) 103 [[NSNotificationCenter defaultCenter] 104 postNotificationName: _NSFormCellDidChangeTitleWidthNotification 105 object: self]; 106 } 107} 108 109/** <p> Sets the NSFormCell title to aString. 110 TODO => _formcell_auto_title_width / Update the control(s)</p> 111 */ 112- (void)setTitle: (NSString*)aString 113{ 114 [_titleCell setStringValue: aString]; 115 116 if (_formcell_auto_title_width) 117 { 118 // Invalidates title width 119 _displayedTitleWidth = -1; 120 // Update the control(s) 121 [[NSNotificationCenter defaultCenter] 122 postNotificationName: _NSFormCellDidChangeTitleWidthNotification 123 object: self]; 124 } 125} 126 127- (void)setTitleWithMnemonic:(NSString *)titleWithAmpersand 128{ 129 [_titleCell setTitleWithMnemonic: titleWithAmpersand]; 130 if (_formcell_auto_title_width) 131 { 132 // Invalidates title width 133 _displayedTitleWidth = -1; 134 // Update the control(s) 135 [[NSNotificationCenter defaultCenter] 136 postNotificationName: _NSFormCellDidChangeTitleWidthNotification 137 object: self]; 138 } 139} 140 141/** <p>Sets the text alignment of the NSFormCell's title to mode. 142 NSRightTextAlignment by default. See <ref type="type" 143 id="NSTextAlignment">NSTextAlignment</ref> for more informations. 144 </p><p>See Also: -titleAlignment [NSCell-setAlignment:]</p> 145 */ 146- (void)setTitleAlignment: (NSTextAlignment)mode 147{ 148 [_titleCell setAlignment: mode]; 149} 150 151/** <p>Set the text font of the NSFormCell's title to fontObject.</p> 152 <p>See Also: -titleFont [NSCell-setFont:]</p> 153 */ 154- (void)setTitleFont: (NSFont*)fontObject 155{ 156 [_titleCell setFont: fontObject]; 157 if (_formcell_auto_title_width) 158 { 159 // Invalidates title width 160 _displayedTitleWidth = -1; 161 // Update the control(s) 162 [[NSNotificationCenter defaultCenter] 163 postNotificationName: _NSFormCellDidChangeTitleWidthNotification 164 object: self]; 165 } 166} 167 168/**<p>Sets the width of the NSFormCell's title to width. All NSFormCell 169 of the NSForm are updated</p><p>See Also: -titleWidth</p> 170*/ 171- (void)setTitleWidth: (CGFloat)width 172{ 173 if (width >= 0) 174 { 175 _formcell_auto_title_width = NO; 176 _displayedTitleWidth = width; 177 } 178 else 179 { 180 _formcell_auto_title_width = YES; 181 _displayedTitleWidth = -1; 182 } 183 // TODO: Don't updated the control if nothing changed. 184 185 // Update the control(s) 186 [[NSNotificationCenter defaultCenter] 187 postNotificationName: _NSFormCellDidChangeTitleWidthNotification 188 object: self]; 189} 190 191- (NSAttributedString *)attributedTitle 192{ 193 return [_titleCell attributedStringValue]; 194} 195 196/** <p>Returns the NSFormCell's title.</p> 197 <p>See Also: -setTitle: [NSCell-stringValue]</p> 198 */ 199- (NSString*)title 200{ 201 return [_titleCell stringValue]; 202} 203 204/** <p>Returns the text alignment of the NSFormCell's title. 205 NSRightTextAlignment by default. See NSTextAlignment for more informations 206 </p><p>See Also: -setTitleAlignment:</p> 207 */ 208- (NSTextAlignment)titleAlignment 209{ 210 return [_titleCell alignment]; 211} 212 213/** <p>Returns the text font of the NSFormCell's title</p> 214 <p>See Also: -setTitleFont: [NSCell-font]</p> 215 */ 216- (NSFont*)titleFont 217{ 218 return [_titleCell font]; 219} 220 221/** <p>Returns the writing direction of the NSFormCell's title</p> 222 <p>See Also: -setTitleBaseWritingDirection: [NSCell-baseWritingDirection]</p> 223 */ 224- (NSWritingDirection)titleBaseWritingDirection 225{ 226 return [_titleCell baseWritingDirection]; 227} 228 229/** <p>Sets the writing direction of the NSFormCell's title</p> 230 <p>See Also: -titleBaseWritingDirection: [NSCell-setBaseWritingDirection]</p> 231 */ 232- (void)setTitleBaseWritingDirection: (NSWritingDirection)writingDirection 233{ 234 [_titleCell setBaseWritingDirection: writingDirection]; 235} 236 237// 238// Warning: this method returns the width of the title; the width the 239// title would have if the cell was the only cell in the form. This 240// is used by NSForm to align all the cells in its form. This is to 241// say that this title width is *not* what you are going to see on the 242// screen if more than one cell is present. Setting a titleWidth 243// manually with setTitleWidth: disables any alignment with other 244// cells. 245// 246- (CGFloat)titleWidth 247{ 248 if (_formcell_auto_title_width == NO) 249 return _displayedTitleWidth; 250 else 251 { 252 NSSize titleSize = [_titleCell cellSize]; 253 return titleSize.width; 254 } 255} 256 257- (CGFloat)titleWidth: (NSSize)aSize 258{ 259 if (_formcell_auto_title_width == NO) 260 return _displayedTitleWidth; 261 else 262 { 263 NSSize titleSize = [_titleCell cellSize]; 264 265 if (aSize.width > titleSize.width) 266 return titleSize.width; 267 else 268 return aSize.width; 269 } 270} 271 272- (NSAttributedString*)placeholderAttributedString 273{ 274 if (_formcell_placeholder_is_attributed_string == YES) 275 { 276 return (NSAttributedString*)_placeholder; 277 } 278 else 279 { 280 return nil; 281 } 282} 283 284- (NSString*)placeholderString 285{ 286 if (_formcell_placeholder_is_attributed_string == YES) 287 { 288 return nil; 289 } 290 else 291 { 292 return (NSString*)_placeholder; 293 } 294} 295 296- (void)setPlaceholderAttributedString: (NSAttributedString*)string 297{ 298 ASSIGN(_placeholder, string); 299 _formcell_placeholder_is_attributed_string = YES; 300} 301 302- (void)setPlaceholderString: (NSString*)string 303{ 304 ASSIGN(_placeholder, string); 305 _formcell_placeholder_is_attributed_string = NO; 306} 307 308// Updates the title width. The width of aRect is the new title width 309// to display. Invoked by NSForm to align the editable parts of the 310// cells. 311- (void) calcDrawInfo: (NSRect)aRect 312{ 313 if (_formcell_auto_title_width == NO) 314 return; 315 316 _displayedTitleWidth = aRect.size.width; 317} 318 319 320- (NSSize)cellSize 321{ 322 NSSize returnedSize; 323 NSSize titleSize = [_titleCell cellSize]; 324 NSSize textSize; 325 326 if (_contents != nil) 327 textSize = [super cellSize]; 328 else 329 { 330 ASSIGN (_contents, @"Minimum"); 331 _cell.contents_is_attributed_string = NO; 332 textSize = [super cellSize]; 333 DESTROY (_contents); 334 } 335 336 returnedSize.width = titleSize.width + 3 + textSize.width; 337 338 if (titleSize.height > textSize.height) 339 returnedSize.height = titleSize.height; 340 else 341 returnedSize.height = textSize.height; 342 343 return returnedSize; 344} 345 346- (NSRect) drawingRectForBounds: (NSRect)theRect 347{ 348 // Safety check 349 if (_displayedTitleWidth == -1) 350 _displayedTitleWidth = [self titleWidth]; 351 352 theRect.origin.x += _displayedTitleWidth + 3; 353 theRect.size.width -= _displayedTitleWidth + 3; 354 355 return [super drawingRectForBounds: theRect]; 356} 357 358- (void) resetCursorRect: (NSRect)cellFrame inView: (NSView *)controlView 359{ 360 NSRect rect = NSMakeRect(cellFrame.origin.x + 3 + [self titleWidth], 361 NSMinY(cellFrame), 362 NSWidth(cellFrame) - 3 - [self titleWidth], 363 NSHeight(cellFrame)); 364 365 [super resetCursorRect: rect 366 inView: controlView]; 367} 368 369- (void) _drawBorderAndBackgroundWithFrame: (NSRect)cellFrame inView: (NSView*)controlView 370{ 371 NSRect borderedFrame = cellFrame; 372 373 // 374 // Draw border 375 // 376 borderedFrame.origin.x += _displayedTitleWidth + 3; 377 borderedFrame.size.width -= _displayedTitleWidth + 3; 378 379 [super _drawBorderAndBackgroundWithFrame: borderedFrame inView: controlView]; 380 // Draw text background 381 [[NSColor textBackgroundColor] set]; 382 NSRectFill([self drawingRectForBounds: cellFrame]); 383} 384 385- (void) drawWithFrame: (NSRect)cellFrame inView: (NSView*)controlView 386{ 387 NSRect titleFrame = cellFrame; 388 389 // Safety check 390 if (_displayedTitleWidth == -1) 391 _displayedTitleWidth = [self titleWidth]; 392 393 // Draw title 394 titleFrame.size.width = _displayedTitleWidth; 395 [_titleCell drawWithFrame: titleFrame inView: controlView]; 396 397 // Draw text 398 [super drawWithFrame: cellFrame inView: controlView]; 399} 400 401/* 402 Attributed string that will be displayed. 403 */ 404- (NSAttributedString*)_drawAttributedString 405{ 406 NSAttributedString *attrStr; 407 408 attrStr = [super _drawAttributedString]; 409 if (attrStr == nil) 410 { 411 attrStr = [self placeholderAttributedString]; 412 if (attrStr == nil) 413 { 414 NSString *string; 415 NSDictionary *attributes; 416 NSMutableDictionary *newAttribs; 417 418 string = [self placeholderString]; 419 if (string == nil) 420 { 421 return nil; 422 } 423 424 attributes = [self _nonAutoreleasedTypingAttributes]; 425 newAttribs = [NSMutableDictionary 426 dictionaryWithDictionary: attributes]; 427 [newAttribs setObject: [NSColor disabledControlTextColor] 428 forKey: NSForegroundColorAttributeName]; 429 430 return AUTORELEASE([[NSAttributedString alloc] 431 initWithString: string 432 attributes: newAttribs]); 433 } 434 else 435 { 436 return attrStr; 437 } 438 } 439 else 440 { 441 return attrStr; 442 } 443} 444 445/* 446 * Copying 447 */ 448- (id) copyWithZone: (NSZone*)zone 449{ 450 NSFormCell *c = (NSFormCell *)[super copyWithZone:zone]; 451 452 /* We need to copy the title cell (as opposed to simply copying the 453 pointer to it), otherwise if eg we change the string value of the 454 title cell of the copied cell, the string value of the title cell 455 of the original cell would be changed too ! */ 456 c->_titleCell = [_titleCell copyWithZone: zone]; 457 c->_placeholder = [_placeholder copyWithZone: zone]; 458 459 return c; 460} 461 462 463- (void) encodeWithCoder: (NSCoder*)aCoder 464{ 465 [super encodeWithCoder: aCoder]; 466 if ([aCoder allowsKeyedCoding]) 467 { 468 /* 469 if ([self stringValue] != nil) 470 { 471 [aCoder encodeObject: [self stringValue] forKey: @"NSContents"]; 472 } 473 */ 474 [aCoder encodeFloat: [self titleWidth] forKey: @"NSTitleWidth"]; 475 [aCoder encodeObject: _titleCell forKey: @"NSTitleCell"]; 476 } 477 else 478 { 479 BOOL tmp = _formcell_auto_title_width; 480 [aCoder encodeValueOfObjCType: @encode(BOOL) at: &tmp]; 481 [aCoder encodeValueOfObjCType: @encode(float) at: &_displayedTitleWidth]; 482 [aCoder encodeObject: _titleCell]; 483 } 484} 485 486- (id) initWithCoder: (NSCoder*)aDecoder 487{ 488 self = [super initWithCoder: aDecoder]; 489 if (nil == self) 490 return nil; 491 492 if ([aDecoder allowsKeyedCoding]) 493 { 494 if ([aDecoder containsValueForKey: @"NSContents"]) 495 { 496 [self setStringValue: [aDecoder decodeObjectForKey: @"NSContents"]]; 497 } 498 if ([aDecoder containsValueForKey: @"NSTitleWidth"]) 499 { 500 [self setTitleWidth: [aDecoder decodeFloatForKey: @"NSTitleWidth"]]; 501 } 502 if ([aDecoder containsValueForKey: @"NSTitleCell"]) 503 { 504 ASSIGN(_titleCell, [aDecoder decodeObjectForKey: @"NSTitleCell"]); 505 } 506 } 507 else 508 { 509 BOOL tmp; 510 [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &tmp]; 511 _formcell_auto_title_width = tmp; 512 [aDecoder decodeValueOfObjCType: @encode(float) at: &_displayedTitleWidth]; 513 [aDecoder decodeValueOfObjCType: @encode(id) at: &_titleCell]; 514 } 515 return self; 516} 517 518@end 519 520