1/* NSTextBlock.m 2 3 Copyright (C) 2008 Free Software Foundation, Inc. 4 5 Author: H. Nikolaus Schaller 6 Date: 2007 7 Author: Fred Kiefer <fredkiefer@gmx.de> 8 Date: January 2008 9 10 This file is part of the GNUstep GUI Library. 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 2 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; see the file COPYING.LIB. 24 If not, see <http://www.gnu.org/licenses/> or write to the 25 Free Software Foundation, 51 Franklin Street, Fifth Floor, 26 Boston, MA 02110-1301, USA. 27*/ 28 29#import <Foundation/NSCoder.h> 30#import <Foundation/NSException.h> 31#import <Foundation/NSString.h> 32 33#import "AppKit/NSColor.h" 34#import "AppKit/NSGraphics.h" 35#import "AppKit/NSTextTable.h" 36#import "GSGuiPrivate.h" 37 38@implementation NSTextBlock 39 40- (id) init 41{ 42 // FIXME 43 return self; 44} 45 46- (void) dealloc 47{ 48 RELEASE(_backgroundColor); 49 RELEASE(_borderColorForEdge[NSMinXEdge]); 50 RELEASE(_borderColorForEdge[NSMinYEdge]); 51 RELEASE(_borderColorForEdge[NSMaxXEdge]); 52 RELEASE(_borderColorForEdge[NSMaxYEdge]); 53 [super dealloc]; 54} 55 56- (NSColor *) backgroundColor 57{ 58 return _backgroundColor; 59} 60 61- (void) setBackgroundColor: (NSColor *)color 62{ 63 ASSIGN(_backgroundColor, color); 64} 65 66- (NSColor *) borderColorForEdge: (NSRectEdge)edge 67{ 68 return _borderColorForEdge[edge]; 69} 70 71- (void) setBorderColor: (NSColor *)color forEdge: (NSRectEdge)edge 72{ 73 if (edge >= sizeof(_borderColorForEdge) / sizeof(_borderColorForEdge[0])) 74 [NSException raise: NSInvalidArgumentException 75 format: @"invalid edge %lu", (unsigned long) edge]; 76 ASSIGN(_borderColorForEdge[edge], color); 77} 78 79- (void) setBorderColor: (NSColor *)color 80{ 81 ASSIGN(_borderColorForEdge[NSMinXEdge], color); 82 ASSIGN(_borderColorForEdge[NSMinYEdge], color); 83 ASSIGN(_borderColorForEdge[NSMaxXEdge], color); 84 ASSIGN(_borderColorForEdge[NSMaxYEdge], color); 85} 86 87- (CGFloat) contentWidth 88{ 89 return [self valueForDimension: NSTextBlockWidth]; 90} 91 92- (NSTextBlockValueType) contentWidthValueType 93{ 94 return [self valueTypeForDimension: NSTextBlockWidth]; 95} 96 97- (void) setContentWidth: (CGFloat)val type: (NSTextBlockValueType)type 98{ 99 [self setValue: val type: type forDimension: NSTextBlockWidth]; 100} 101 102- (NSTextBlockVerticalAlignment) verticalAlignment 103{ 104 return _verticalAlignment; 105} 106 107- (void) setVerticalAlignment: (NSTextBlockVerticalAlignment)alignment 108{ 109 _verticalAlignment = alignment; 110} 111 112- (CGFloat) valueForDimension: (NSTextBlockDimension)dimension 113{ 114 if (dimension >= sizeof(_valueType) / sizeof(_valueType[0])) 115 [NSException raise: NSInvalidArgumentException 116 format: @"invalid dimension %d", dimension]; 117 return _value[dimension]; 118} 119 120- (NSTextBlockValueType) valueTypeForDimension: (NSTextBlockDimension)dimension 121{ 122 if (dimension >= sizeof(_valueType) / sizeof(_valueType[0])) 123 [NSException raise: NSInvalidArgumentException 124 format: @"invalid dimension %d", dimension]; 125 return _valueType[dimension]; 126} 127 128- (CGFloat) _scaledValue: (NSTextBlockDimension)dimension : (NSSize)size 129{ 130 if (_valueType[dimension] == NSTextBlockAbsoluteValueType) 131 { 132 return _value[dimension]; 133 } 134 else 135 { 136 // specified in percent 137 switch(dimension) 138 { 139 case NSTextBlockWidth: 140 case NSTextBlockMinimumWidth: 141 case NSTextBlockMaximumWidth: 142 return _value[dimension] * size.width; 143 case NSTextBlockHeight: 144 case NSTextBlockMinimumHeight: 145 case NSTextBlockMaximumHeight: 146 return _value[dimension] * size.height; 147 } 148 } 149 return 0.0; 150} 151 152- (void) setValue: (CGFloat)val 153 type: (NSTextBlockValueType)type 154 forDimension: (NSTextBlockDimension)dimension 155{ 156 if (dimension >= sizeof(_valueType) / sizeof(_valueType[0])) 157 [NSException raise: NSInvalidArgumentException 158 format: @"invalid dimension %d", dimension]; 159 _value[dimension] = val; 160 _valueType[dimension] = type; 161} 162 163- (CGFloat) widthForLayer: (NSTextBlockLayer)layer edge: (NSRectEdge)edge 164{ 165 if (layer >= sizeof(_width) / sizeof(_width[0])) 166 [NSException raise: NSInvalidArgumentException 167 format: @"invalid layer %d", layer]; 168 if (edge >= sizeof(_width[0]) / sizeof(_width[0][0])) 169 [NSException raise: NSInvalidArgumentException 170 format: @"invalid edge %lu", (unsigned long) edge]; 171 return _width[layer][edge]; 172} 173 174- (NSTextBlockValueType) widthValueTypeForLayer: (NSTextBlockLayer)layer 175 edge: (NSRectEdge)edge 176{ 177 if (layer >= sizeof(_width) / sizeof(_width[0])) 178 [NSException raise: NSInvalidArgumentException 179 format: @"invalid layer %d", layer]; 180 if (edge >= sizeof(_width[0]) / sizeof(_width[0][0])) 181 [NSException raise: NSInvalidArgumentException 182 format: @"invalid edge %lu", (unsigned long) edge]; 183 return _widthType[layer][edge]; 184} 185 186- (void) setWidth: (CGFloat)val 187 type: (NSTextBlockValueType)type 188 forLayer: (NSTextBlockLayer)layer 189 edge: (NSRectEdge)edge 190{ 191 if (layer >= sizeof(_width) / sizeof(_width[0])) 192 [NSException raise: NSInvalidArgumentException 193 format: @"invalid layer %d", layer]; 194 if (edge >= sizeof(_width[0]) / sizeof(_width[0][0])) 195 [NSException raise: NSInvalidArgumentException 196 format: @"invalid edge %lu", (unsigned long) edge]; 197 _width[layer][edge] = val; 198 _widthType[layer][edge] = type; 199} 200 201- (void) setWidth: (CGFloat)val 202 type: (NSTextBlockValueType)type 203 forLayer: (NSTextBlockLayer)layer 204{ 205 if (layer >= sizeof(_width) / sizeof(_width[0])) 206 [NSException raise: NSInvalidArgumentException 207 format: @"invalid layer %d", layer]; 208 _width[layer][NSMinXEdge] = val; 209 _widthType[layer][NSMinXEdge] = type; 210 _width[layer][NSMinYEdge] = val; 211 _widthType[layer][NSMinYEdge] = type; 212 _width[layer][NSMaxXEdge] = val; 213 _widthType[layer][NSMaxXEdge] = type; 214 _width[layer][NSMaxYEdge] = val; 215 _widthType[layer][NSMaxYEdge] = type; 216} 217 218- (CGFloat) _scaledWidthValue: (NSTextBlockLayer) layer : (NSRectEdge) edge : (NSSize) size 219{ 220 if (_widthType[layer][edge] == NSTextBlockAbsoluteValueType) 221 { 222 // absolute 223 return _width[layer][edge]; 224 } 225 else 226 { 227 // specified in percent 228 switch(edge) 229 { 230 case NSMinXEdge: 231 case NSMaxXEdge: 232 return _widthType[layer][edge]*size.width; 233 case NSMinYEdge: 234 case NSMaxYEdge: 235 return _widthType[layer][edge]*size.height; 236 } 237 } 238 return 0.0; 239} 240 241- (NSRect) boundsRectForContentRect: (NSRect)cont 242 inRect: (NSRect)rect 243 textContainer: (NSTextContainer *)container 244 characterRange: (NSRange)range 245{ 246 CGFloat minx = [self _scaledWidthValue: NSTextBlockPadding : NSMinXEdge: rect.size] 247 + [self _scaledWidthValue: NSTextBlockBorder : NSMinXEdge : rect.size] 248 + [self _scaledWidthValue: NSTextBlockMargin : NSMinXEdge : rect.size]; 249 250 CGFloat maxx = [self _scaledWidthValue: NSTextBlockPadding: NSMaxXEdge: rect.size] 251 + [self _scaledWidthValue: NSTextBlockBorder : NSMaxXEdge : rect.size] 252 + [self _scaledWidthValue: NSTextBlockMargin : NSMaxXEdge : rect.size]; 253 CGFloat miny= [self _scaledWidthValue: NSTextBlockPadding : NSMinYEdge: rect.size] 254 + [self _scaledWidthValue: NSTextBlockBorder : NSMinYEdge : rect.size] 255 + [self _scaledWidthValue: NSTextBlockMargin : NSMinYEdge : rect.size]; 256 257 CGFloat maxy = [self _scaledWidthValue: NSTextBlockPadding: NSMaxYEdge: rect.size] 258 + [self _scaledWidthValue: NSTextBlockBorder : NSMaxYEdge : rect.size] 259 + [self _scaledWidthValue: NSTextBlockMargin : NSMaxYEdge : rect.size]; 260 261 cont.origin.x -= minx; 262 cont.size.width += minx + maxx; 263 cont.origin.y -= miny; 264 cont.size.height += miny + maxy; 265 return cont; 266} 267 268/** 269 * POINT is the point in NSTextContainer where the TextBlock should be laid out. 270 * RECT is the bounding rect (e.g. the rect of the container or the rect of the 271 * outer table cell) 272 * what are we doing with CONT? Do we limit to width of container? 273 * what are we doing with RANGE? We don't know the layout manager 274 * This is the default implementation for a single-cell 275 * (NSTextTableBlock can handle cell span) 276 * raises internal inconsisteny exception if the layout manager 277 * (the one owning the textContainer) 278 * does not have a table at the given characterRange 279 */ 280- (NSRect) rectForLayoutAtPoint: (NSPoint)point 281 inRect: (NSRect)rect 282 textContainer: (NSTextContainer *)cont 283 characterRange: (NSRange)range 284{ 285 NSRect r; 286 NSSize size = (NSSize){[self _scaledValue: NSTextBlockWidth : rect.size], 287 [self _scaledValue: NSTextBlockHeight : rect.size]}; 288 // when and how do we define size by content? If size is (0, 0)? 289 // or is this the input to calculating size of enclosed text? 290 size.width = MAX(size.width, [self _scaledValue: NSTextBlockMinimumWidth : rect.size]); 291 // not smaller than minimum 292 size.height = MAX(size.height, [self _scaledValue: NSTextBlockMinimumHeight : rect.size]); 293 size.width = MIN(size.width, [self _scaledValue: NSTextBlockMaximumWidth : rect.size]); 294 // but also not larger than maximum 295 size.height = MIN(size.height, [self _scaledValue: NSTextBlockMaximumHeight : rect.size]); 296 r = (NSRect){point, size}; 297 // who handles vertical alignment? 298 // limit to what is available 299 return NSIntersectionRect(r, rect); 300} 301 302- (void) drawBackgroundWithFrame: (NSRect)rect // this is the frame of the cell 303 inView: (NSView *)view 304 characterRange: (NSRange)range 305 layoutManager: (NSLayoutManager *)lm 306{ 307 CGFloat minx = [self _scaledWidthValue: NSTextBlockPadding : NSMinXEdge : rect.size]; 308 CGFloat maxx = [self _scaledWidthValue: NSTextBlockPadding : NSMaxXEdge : rect.size]; 309 CGFloat miny = [self _scaledWidthValue: NSTextBlockPadding : NSMinYEdge : rect.size]; 310 CGFloat maxy = [self _scaledWidthValue: NSTextBlockPadding : NSMaxYEdge : rect.size]; 311 312 // FIXME - inset from frame by margin in the first step 313 rect.origin.x -= minx; 314 rect.size.width += minx + maxx; 315 rect.origin.y -= miny; 316 rect.size.height += miny + maxy; 317 [_backgroundColor set]; 318 // fill inner rect 319 NSRectFill(rect); 320 321 minx = [self _scaledWidthValue: NSTextBlockBorder : NSMinXEdge : rect.size]; 322 maxx = [self _scaledWidthValue: NSTextBlockBorder : NSMaxXEdge : rect.size]; 323 miny = [self _scaledWidthValue: NSTextBlockBorder : NSMinYEdge : rect.size]; 324 maxy = [self _scaledWidthValue: NSTextBlockBorder : NSMaxYEdge : rect.size]; 325 [_borderColorForEdge[NSMinXEdge] set]; 326 NSRectFill(NSMakeRect(rect.origin.x - minx, rect.origin.y, minx, rect.size.height)); 327 [_borderColorForEdge[NSMaxYEdge] set]; 328 NSRectFill(NSMakeRect(rect.origin.x, rect.origin.y + rect.size.height + maxy, rect.size.width, maxy)); 329 [_borderColorForEdge[NSMaxXEdge] set]; 330 NSRectFill(NSMakeRect(rect.origin.x + rect.size.width, rect.origin.y, maxx, rect.size.height)); 331 [_borderColorForEdge[NSMinYEdge] set]; 332 NSRectFill(NSMakeRect(rect.origin.x, rect.origin.y - maxy, rect.size.width, miny)); 333 // FIXME: how do we handle the corners of differenly sized and colored borders? 334 // Do we have to fill trapezoids? 335} 336 337- (id) copyWithZone: (NSZone*)zone 338{ 339 NSTextBlock *t = (NSTextBlock*)NSCopyObject(self, 0, zone); 340 341 _backgroundColor = TEST_RETAIN(_backgroundColor); 342 _borderColorForEdge[NSMinXEdge] = 343 TEST_RETAIN(_borderColorForEdge[NSMinXEdge]); 344 _borderColorForEdge[NSMinYEdge] = 345 TEST_RETAIN(_borderColorForEdge[NSMinYEdge]); 346 _borderColorForEdge[NSMaxXEdge] = 347 TEST_RETAIN(_borderColorForEdge[NSMaxXEdge]); 348 _borderColorForEdge[NSMaxYEdge] = 349 TEST_RETAIN(_borderColorForEdge[NSMaxYEdge]); 350 351 return t; 352} 353 354- (void) encodeWithCoder: (NSCoder*)aCoder 355{ 356 // FIXME 357 if ([aCoder allowsKeyedCoding]) 358 { 359 } 360 else 361 { 362 } 363} 364 365- (id) initWithCoder: (NSCoder*)aDecoder 366{ 367 // FIXME 368 if ([aDecoder allowsKeyedCoding]) 369 { 370 } 371 else 372 { 373 } 374 return self; 375} 376 377@end 378