/* Implementation of class NSGridView Copyright (C) 2020 Free Software Foundation, Inc. By: Gregory John Casamento Date: 08-08-2020 This file is part of the GNUstep 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.1 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; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 USA. */ #import #import "AppKit/NSGridView.h" #import "GSFastEnumeration.h" // // This is, admittedly, a kludge. Some controls were not working // when placed so close together (the checkbox, in particular). // #define MIN_SPACING 5.0 // Private interfaces... @interface NSGridCell (Private) - (void) _setOwningRow: (NSGridRow *)r; - (void) _setOwningColumn: (NSGridColumn *)c; @end @interface NSGridView (Private) - (NSRect) _prototypeFrame; - (NSArray *) _cellsForRowAtIndex: (NSUInteger)rowIndex; - (NSArray *) _viewsForRowAtIndex: (NSUInteger)rowIndex; - (NSArray *) _cellsForColumnAtIndex: (NSUInteger)columnIndex; - (NSArray *) _viewsForColumnAtIndex: (NSUInteger)columnIndex; @end @implementation NSGridView (Private) - (NSRect) _prototypeFrame { NSRect vf = [self frame]; NSRect f = NSMakeRect(0.0, 0.0, ((vf.size.width - (_columnSpacing + MIN_SPACING)) / [self numberOfColumns]), ((vf.size.height - (_rowSpacing + MIN_SPACING)) / [self numberOfRows])); return f; } - (NSArray *) _cellsForRowAtIndex: (NSUInteger)rowIndex { NSMutableArray *result = [NSMutableArray arrayWithCapacity: [_columns count]]; NSGridRow *row = [_rows objectAtIndex: rowIndex]; FOR_IN(NSGridCell*, c, _cells) { if ([c row] == row) { [result addObject: c]; } } END_FOR_IN(_cells); return result; } - (NSArray *) _viewsForRowAtIndex: (NSUInteger)rowIndex { NSArray *cells = [self _cellsForRowAtIndex: rowIndex]; NSMutableArray *result = [NSMutableArray arrayWithCapacity: [_columns count]]; FOR_IN(NSGridCell*, c, cells) { NSView *v = [c contentView]; if (c != nil) { [result addObject: v]; } else { [result addObject: [NSGridCell emptyContentView]]; } } END_FOR_IN(cells); return result; } - (NSArray *) _cellsForColumnAtIndex: (NSUInteger)columnIndex { NSMutableArray *result = [NSMutableArray arrayWithCapacity: [_rows count]]; NSGridColumn *col = [_columns objectAtIndex: columnIndex]; FOR_IN(NSGridCell*, c, _cells) { if ([c column] == col) { [result addObject: c]; } } END_FOR_IN(_cells); return result; } - (NSArray *) _viewsForColumnAtIndex: (NSUInteger)columnIndex { NSArray *cells = [self _cellsForColumnAtIndex: columnIndex]; NSMutableArray *result = [NSMutableArray arrayWithCapacity: [_rows count]]; FOR_IN(NSGridCell*, c, cells) { NSView *v = [c contentView]; if (c != nil) { [result addObject: v]; } else { [result addObject: [NSGridCell emptyContentView]]; } } END_FOR_IN(cells); return result; } @end // Private methods... @implementation NSGridCell (Private) - (void) _setOwningRow: (NSGridRow *)r { _owningRow = r; } - (void) _setOwningColumn: (NSGridColumn *)c { _owningColumn = c; } @end @implementation NSGridView + (void) initialize { if (self == [NSGridView class]) { [self setVersion: 1]; } } - (void) _refreshCells { if ([self isHidden]) { return; } else { NSUInteger i = 0; NSUInteger num_col = [self numberOfColumns]; NSRect f = [self frame]; CGFloat current_x = 0.0, current_y = f.size.height; NSRect p = [self _prototypeFrame]; // Format the grid... FOR_IN(NSGridCell*, c, _cells) { NSView *v = [c contentView]; NSUInteger ri = 0, ci = 0; // Get row and column index... ci = i % num_col; ri = i / num_col; // Get the row and col... NSGridRow *row = [self rowAtIndex: ri]; NSGridColumn *col = [self columnAtIndex: ci]; NSRect rect = NSZeroRect; if (v != nil) { rect = [v frame]; } if (ci == 0) { current_y -= [row topPadding]; current_y -= p.size.height; current_x = 0.0; } // current_x += [col leadingPadding]; if (v != nil) { rect = p; rect.origin.x = current_x; rect.origin.y = current_y; [v setFrame: rect]; [self addSubview: v]; } current_x += [col leadingPadding]; current_x += p.size.width; current_x += [col trailingPadding]; if (ci == 0) { current_y -= [row bottomPadding]; } // inc i++; } END_FOR_IN(_cells); } } - (instancetype) initWithFrame: (NSRect)frameRect { self = [super initWithFrame: frameRect]; if (self != nil) { _rows = [[NSMutableArray alloc] init]; _columns = [[NSMutableArray alloc] init]; _cells = [[NSMutableArray alloc] init]; } return self; } - (instancetype) initWithViews: (NSArray *)views // an array of arrays { self = [self initWithFrame: NSZeroRect]; if (self == nil) { return self; } NSUInteger c = 0; NSUInteger r = 0; FOR_IN(NSArray*, row, views) { NSGridRow *gr = [[NSGridRow alloc] init]; [gr setGridView: self]; [_rows addObject: gr]; RELEASE(gr); c = 0; FOR_IN(NSView*, v, row) { NSGridColumn *gc = nil; NSGridCell *cell = [[NSGridCell alloc] init]; if (r == 0) // first row, create all of the columns... { gc = [[NSGridColumn alloc] init]; [_columns addObject: gc]; RELEASE(gc); [gc setGridView: self]; } else { gc = [_columns objectAtIndex: c]; } [cell _setOwningRow: gr]; [cell _setOwningColumn: gc]; [cell setContentView: v]; [_cells addObject: cell]; c++; } END_FOR_IN(row); r++; } END_FOR_IN(views); [self _refreshCells]; return self; } + (instancetype) gridViewWithNumberOfColumns: (NSInteger)columnCount rows: (NSInteger)rowCount { NSUInteger r = 0; NSUInteger c = 0; NSMutableArray *rows = [[NSMutableArray alloc] initWithCapacity: rowCount]; for (r = 0; r < rowCount; r++) { NSMutableArray *col = [[NSMutableArray alloc] initWithCapacity: columnCount]; for (c = 0; c < columnCount; c++) { NSView *gv = [[NSView alloc] init]; [col addObject: gv]; RELEASE(gv); } [rows addObject: col]; } return [self gridViewWithViews: rows]; } + (instancetype) gridViewWithViews: (NSArray *)views { return AUTORELEASE([[self alloc] initWithViews: views]); } - (void) setFrame: (NSRect)f { [super setFrame: f]; [self _refreshCells]; } - (NSInteger) numberOfRows { return [_rows count]; } - (NSInteger) numberOfColumns { return [_columns count]; } - (NSGridRow *) rowAtIndex: (NSInteger)index { return [_rows objectAtIndex: index]; } - (NSInteger) indexOfRow: (NSGridRow *)row { return [_rows indexOfObject: row]; } - (NSGridColumn *) columnAtIndex: (NSInteger)index { return [_columns objectAtIndex: index]; } - (NSInteger) indexOfColumn: (NSGridColumn *)column { return [_columns indexOfObject: column]; } - (NSGridCell *) cellAtColumnIndex: (NSInteger)columnIndex rowIndex: (NSInteger)rowIndex { NSUInteger idx = rowIndex * [self numberOfColumns] + columnIndex; return [_cells objectAtIndex: idx]; } - (NSGridCell *) cellForView: (NSView*)view { NSGridCell *result = nil; FOR_IN(NSGridCell*, c, _cells) { NSView *v = [c contentView]; if (v == view) { result = c; break; } } END_FOR_IN(_cells); return result; } - (NSGridRow *) addRowWithViews: (NSArray *)views { return [self insertRowAtIndex: [self numberOfRows] withViews: views]; } - (NSGridRow *) _insertRowAtIndex: (NSInteger)index withCells: (NSArray *)cells { NSGridRow *gr = [[NSGridRow alloc] init]; // Insert the row and release... [_rows insertObject: gr atIndex: index]; [gr setGridView: self]; RELEASE(gr); NSUInteger i = 0; NSUInteger pos = index * [self numberOfColumns]; for(i = 0; i < [self numberOfColumns]; i++) { NSGridCell *c = nil; NSGridColumn *col = [_columns objectAtIndex: i]; if (i > ([cells count] - 1)) { c = AUTORELEASE([[NSGridCell alloc] init]); } else { c = [cells objectAtIndex: i]; } [c _setOwningRow: gr]; [c _setOwningColumn: col]; [_cells insertObject: c atIndex: pos + i]; } // Refresh... [self _refreshCells]; return gr; } - (NSGridRow *) insertRowAtIndex: (NSInteger)index withViews: (NSArray *)views { NSRect f = [self _prototypeFrame]; NSMutableArray *cells = [NSMutableArray arrayWithCapacity: [views count]]; FOR_IN(NSView*, v, views) { NSGridCell *c = [[NSGridCell alloc] init]; [v setFrame: f]; [c setContentView: v]; [cells addObject: c]; RELEASE(c); } END_FOR_IN(views); return [self _insertRowAtIndex: index withCells: cells]; } - (void) moveRowAtIndex: (NSInteger)fromIndex toIndex: (NSInteger)toIndex { NSArray *cells = [self _cellsForRowAtIndex: fromIndex]; [self removeRowAtIndex: fromIndex]; [self _insertRowAtIndex: toIndex withCells: cells]; } - (void) removeRowAtIndex: (NSInteger)index { NSArray *objs = [self _cellsForRowAtIndex: index]; [_rows removeObjectAtIndex: index]; [_cells removeObjectsInArray: objs]; [self _refreshCells]; } - (NSGridColumn *) addColumnWithViews: (NSArray*)views { return [self insertColumnAtIndex: [self numberOfColumns] withViews: views]; } - (NSGridColumn *) _insertColumnAtIndex: (NSInteger)index withCells: (NSArray *)cells { NSGridColumn *gc = [[NSGridColumn alloc] init]; // Insert the row and release... [_columns insertObject: gc atIndex: index]; [gc setGridView: self]; RELEASE(gc); NSUInteger i = 0; NSUInteger pos = index; for(i = 0; i < [self numberOfRows]; i++) { NSGridCell *c = nil; NSGridRow *row = [_rows objectAtIndex: i]; if (i > ([cells count] - 1)) { c = AUTORELEASE([[NSGridCell alloc] init]); } else { c = [cells objectAtIndex: i]; } [c _setOwningRow: row]; [c _setOwningColumn: gc]; [_cells insertObject: c atIndex: pos + i * [self numberOfColumns]]; } // Refresh... [self _refreshCells]; return gc; } - (NSGridColumn *) insertColumnAtIndex: (NSInteger)index withViews: (NSArray *)views { NSRect f = [self _prototypeFrame]; NSMutableArray *cells = [NSMutableArray arrayWithCapacity: [views count]]; FOR_IN(NSView*, v, views) { NSGridCell *c = [[NSGridCell alloc] init]; [v setFrame: f]; [c setContentView: v]; [cells addObject: c]; RELEASE(c); } END_FOR_IN(views); return [self _insertColumnAtIndex: index withCells: cells]; } - (void) moveColumnAtIndex: (NSInteger)fromIndex toIndex: (NSInteger)toIndex { NSArray *cells = [self _cellsForColumnAtIndex: fromIndex]; [self removeColumnAtIndex: fromIndex]; [self _insertColumnAtIndex: toIndex withCells: cells]; } - (void) removeColumnAtIndex: (NSInteger)index { NSArray *objs = [self _cellsForColumnAtIndex: index]; [_columns removeObjectAtIndex: index]; [_cells removeObjectsInArray: objs]; [self _refreshCells]; } - (NSGridCellPlacement) xPlacement { return _xPlacement; } - (void) setXPlacement: (NSGridCellPlacement)x { _xPlacement = x; } - (NSGridCellPlacement) yPlacement { return _yPlacement; } - (void) setYPlacement: (NSGridCellPlacement)y { _yPlacement = y; } - (NSGridRowAlignment) rowAlignment { return _rowAlignment; } - (void) setRowAlignment: (NSGridRowAlignment)a { _rowAlignment = a; } - (CGFloat) rowSpacing { return _rowSpacing; } - (void) setRowSpacing: (CGFloat)f { _rowSpacing = f; } - (CGFloat) columnSpacing { return _columnSpacing; } - (void) setColumnSpacing: (CGFloat)f { _columnSpacing = f; } - (void) mergeCellsInHorizontalRange: (NSRange)hRange verticalRange: (NSRange)vRange { NSLog(@"Method %@ unimplemented.", NSStringFromSelector(_cmd)); } // coding - (void) encodeWithCoder: (NSCoder *)coder { [super encodeWithCoder: coder]; if ([coder allowsKeyedCoding]) { [coder encodeInteger: _rowAlignment forKey: @"NSGrid_alignment"]; [coder encodeDouble: _columnSpacing forKey: @"NSGrid_columnSpacing"]; [coder encodeObject: _columns forKey: @"NSGrid_columns"]; [coder encodeDouble: _rowSpacing forKey: @"NSGrid_rowSpacing"]; [coder encodeObject: _rows forKey: @"NSGrid_rows"]; [coder encodeInteger: _xPlacement forKey: @"NSGrid_xPlacement"]; [coder encodeInteger: _yPlacement forKey: @"NSGrid_yPlacement"]; [coder encodeObject: _cells forKey: @"NSGrid_cells"]; } else { [coder encodeValueOfObjCType: @encode(NSUInteger) at: &_rowAlignment]; [coder encodeObject: _columns]; [coder encodeObject: _rows]; [coder encodeObject: _cells]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_columnSpacing]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_rowSpacing]; [coder encodeValueOfObjCType: @encode(NSUInteger) at: &_xPlacement]; [coder encodeValueOfObjCType: @encode(NSUInteger) at: &_yPlacement]; } } - (instancetype) initWithCoder: (NSCoder *)coder { self = [super initWithCoder: coder]; if (self != nil) { if ([coder allowsKeyedCoding]) { if ([coder containsValueForKey: @"NSGrid_alignment"]) { _rowAlignment = (NSGridRowAlignment)[coder decodeIntegerForKey: @"NSGrid_alignment"]; } if ([coder containsValueForKey: @"NSGrid_columns"]) { ASSIGN(_columns, [coder decodeObjectForKey: @"NSGrid_columns"]); } if ([coder containsValueForKey: @"NSGrid_rows"]) { ASSIGN(_rows, [coder decodeObjectForKey: @"NSGrid_rows"]); } if ([coder containsValueForKey: @"NSGrid_cells"]) { ASSIGN(_cells, [coder decodeObjectForKey: @"NSGrid_cells"]); } if ([coder containsValueForKey: @"NSGrid_columnSpacing"]) { _columnSpacing = [coder decodeFloatForKey: @"NSGrid_columnSpacing"]; } if ([coder containsValueForKey: @"NSGrid_rowSpacing"]) { _rowSpacing = [coder decodeFloatForKey: @"NSGrid_rowSpacing"]; } if ([coder containsValueForKey: @"NSGrid_xPlacement"]) { _xPlacement = [coder decodeIntegerForKey: @"NSGrid_xPlacement"]; } if ([coder containsValueForKey: @"NSGrid_yPlacement"]) { _yPlacement = [coder decodeIntegerForKey: @"NSGrid_yPlacement"]; } } else { [coder decodeValueOfObjCType: @encode(NSUInteger) at: &_rowAlignment]; ASSIGN(_columns, [coder decodeObject]); ASSIGN(_rows, [coder decodeObject]); ASSIGN(_cells, [coder decodeObject]); [coder decodeValueOfObjCType: @encode(CGFloat) at: &_columnSpacing]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_rowSpacing]; [coder decodeValueOfObjCType: @encode(NSUInteger) at: &_xPlacement]; [coder decodeValueOfObjCType: @encode(NSUInteger) at: &_yPlacement]; } } [self _refreshCells]; return self; } - (void) dealloc { RELEASE(_columns); RELEASE(_rows); RELEASE(_cells); [super dealloc]; } @end /// Cell /// @implementation NSGridCell + (void) initialize { if (self == [NSGridCell class]) { [self setVersion: 1]; } } - (NSView *) contentView { return _contentView; } - (void) setContentView: (NSView *)v { ASSIGN(_contentView, v); } + (NSView *) emptyContentView { return AUTORELEASE([[NSView alloc] initWithFrame: NSZeroRect]); } // Weak references to row/column - (NSGridRow *) row { return _owningRow; } - (NSGridColumn *) column { return _owningColumn; } // Placement - (NSGridCellPlacement) xPlacement { return _xPlacement; } - (void) setXPlacement: (NSGridCellPlacement)x { _xPlacement = x; } - (NSGridCellPlacement) yPlacement { return _yPlacement; } - (void) setYPlacement: (NSGridCellPlacement)y { _yPlacement = y; } - (NSGridRowAlignment) rowAlignment { return _rowAlignment; } - (void) setRowAlignment: (NSGridRowAlignment)a { _rowAlignment = a; } // Constraints - (NSArray *) customPlacementConstraints { return _customPlacementConstraints; } - (void) setCustomPlacementConstraints: (NSArray *)constraints { ASSIGNCOPY(_customPlacementConstraints, constraints); } // coding - (void) encodeWithCoder: (NSCoder *)coder { if ([coder allowsKeyedCoding]) { [coder encodeObject: _contentView forKey: @"NSGrid_content"]; [coder encodeObject: _mergeHead forKey: @"NSGrid_mergeHead"]; [coder encodeObject: _owningRow forKey: @"NSGrid_owningRow"]; // weak [coder encodeObject: _owningColumn forKey: @"NSGrid_owningColumn"]; // weak [coder encodeInteger: _xPlacement forKey: @"NSGrid_xPlacement"]; [coder encodeInteger: _yPlacement forKey: @"NSGrid_yPlacement"]; [coder encodeInteger: _rowAlignment forKey: @"NSGrid_alignment"]; } else { [coder encodeObject: [self contentView]]; [coder encodeObject: _mergeHead]; [coder encodeObject: _owningRow]; [coder encodeObject: _owningColumn]; [coder encodeObject: _customPlacementConstraints]; [coder encodeValueOfObjCType:@encode(NSInteger) at: &_xPlacement]; [coder encodeValueOfObjCType:@encode(NSInteger) at: &_yPlacement]; [coder encodeValueOfObjCType:@encode(NSInteger) at: &_rowAlignment]; } } - (instancetype) initWithCoder: (NSCoder *)coder { self = [super init]; if (self != nil) { if ([coder allowsKeyedCoding]) { if ([coder containsValueForKey: @"NSGrid_content"]) { [self setContentView: [coder decodeObjectForKey: @"NSGrid_content"]]; } if ([coder containsValueForKey: @"NSGrid_mergeHead"]) { _mergeHead = [coder decodeObjectForKey: @"NSGrid_mergeHead"]; } if ([coder containsValueForKey: @"NSGrid_owningRow"]) { _owningRow = [coder decodeObjectForKey: @"NSGrid_owningRow"]; // weak } if ([coder containsValueForKey: @"NSGrid_owningColumn"]) { _owningColumn = [coder decodeObjectForKey: @"NSGrid_owningColumn"]; // weak } if ([coder containsValueForKey: @"NSGrid_xPlacement"]) { _xPlacement = [coder decodeIntegerForKey: @"NSGrid_xPlacement"]; } if ([coder containsValueForKey: @"NSGrid_yPlacement"]) { _yPlacement = [coder decodeIntegerForKey: @"NSGrid_yPlacement"]; } if ([coder containsValueForKey: @"NSGrid_alignment"]) { _rowAlignment = [coder decodeIntegerForKey: @"NSGrid_alignment"]; } } else { [self setContentView: [coder decodeObject]]; ASSIGN(_mergeHead, [coder decodeObject]); _owningRow = [coder decodeObject]; // weak _owningColumn = [coder decodeObject]; // weak ASSIGN(_customPlacementConstraints, [coder decodeObject]); [coder decodeValueOfObjCType: @encode(NSInteger) at: &_xPlacement]; [coder decodeValueOfObjCType:@encode(NSInteger) at: &_yPlacement]; [coder decodeValueOfObjCType:@encode(NSInteger) at: &_rowAlignment]; } } return self; } - (void) dealloc { RELEASE(_contentView); RELEASE(_mergeHead); [super dealloc]; } @end /// Column /// @implementation NSGridColumn + (void) initialize { if (self == [NSGridColumn class]) { [self setVersion: 1]; } } - (void) setGridView: (NSGridView *)gv { _gridView = gv; } - (NSGridView *) gridView { return _gridView; } - (NSInteger) numberOfCells { // The number of cells in a column = # of rows return [_gridView numberOfRows]; } - (NSGridCell *) cellAtIndex: (NSInteger)index { NSUInteger ci = [_gridView indexOfColumn: self]; // First we get the columnIndex (ci) then we get the member of that column // referred to by index. The method called here gets the correct cell out of // the _cells array in the containing NSGridView. return [_gridView cellAtColumnIndex: ci rowIndex: index]; } - (NSGridCellPlacement) xPlacement { return _xPlacement; } - (void) setXPlacement: (NSGridCellPlacement)x { _xPlacement = x; } - (CGFloat) width { return _width; } - (void) setWidth: (CGFloat)f { _width = f; } - (CGFloat) leadingPadding { return _leadingPadding; } - (void) setLeadingPadding: (CGFloat)f { _leadingPadding = f; } - (CGFloat) trailingPadding { return _trailingPadding; } - (void) setTrailingPadding: (CGFloat)f { _trailingPadding = f; } - (BOOL) isHidden { return _isHidden; } - (void) mergeCellsInRange: (NSRange)range { NSUInteger ci = [_gridView indexOfColumn: self]; NSRange hRange = NSMakeRange(ci, 1); [_gridView mergeCellsInHorizontalRange: hRange verticalRange: range]; } // coding - (void) encodeWithCoder: (NSCoder *)coder { if ([coder allowsKeyedCoding]) { [coder encodeBool: _isHidden forKey: @"NSGrid_hidden"]; [coder encodeFloat: _leadingPadding forKey: @"NSGrid_leadingPadding"]; [coder encodeObject: _gridView forKey: @"NSGrid_owningGrid"]; // weak [coder encodeFloat: _trailingPadding forKey: @"NSGrid_trailingPadding"]; [coder encodeFloat: _width forKey: @"NSGrid_width"]; [coder encodeInteger: _xPlacement forKey: @"NSGrid_xPlacement"]; } else { [coder encodeValueOfObjCType: @encode(BOOL) at: &_isHidden]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_leadingPadding]; [coder encodeObject: _gridView]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_trailingPadding]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_width]; [coder encodeValueOfObjCType: @encode(NSInteger) at: &_xPlacement]; } } - (instancetype) initWithCoder: (NSCoder *)coder { self = [super init]; if (self != nil) { if ([coder allowsKeyedCoding]) { if ([coder containsValueForKey: @"NSGrid_hidden"]) { _isHidden = [coder decodeBoolForKey: @"NSGrid_hidden"]; } if ([coder containsValueForKey: @"NSGrid_leadingPadding"]) { _leadingPadding = [coder decodeFloatForKey: @"NSGrid_leadingPadding"]; } if ([coder containsValueForKey: @"NSGrid_owningGrid"]) { _gridView = [coder decodeObjectForKey: @"NSGrid_owningGrid"]; // weak } if ([coder containsValueForKey: @"NSGrid_trailingPadding"]) { _trailingPadding = [coder decodeFloatForKey: @"NSGrid_trailingPadding"]; } if ([coder containsValueForKey: @"NSGrid_width"]) { _width = [coder decodeFloatForKey: @"NSGrid_width"]; } if ([coder containsValueForKey: @"NSGrid_xPlacement"]) { _xPlacement = [coder decodeIntegerForKey: @"NSGrid_xPlacement"]; } } else { [coder decodeValueOfObjCType: @encode(BOOL) at: &_isHidden]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_leadingPadding]; _gridView = [coder decodeObject]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_trailingPadding]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_width]; [coder decodeValueOfObjCType: @encode(NSInteger) at: &_xPlacement]; } } return self; } @end /// Row /// @implementation NSGridRow + (void) initialize { if (self == [NSGridRow class]) { [self setVersion: 1]; } } - (void) setGridView: (NSGridView *)gridView { _gridView = gridView; // weak reference... } - (NSGridView *) gridView { return _gridView; } - (NSInteger) numberOfCells { // The number of cells in a row = # of columns return [_gridView numberOfColumns]; } - (NSGridCell *) cellAtIndex: (NSInteger)index { NSUInteger ri = [_gridView indexOfRow: self]; // First we get the rowIndex (ri) then we get the member of that row // referred to by index. The method called here gets the correct cell out of // the _cells array in the containing NSGridView. return [_gridView cellAtColumnIndex: index rowIndex: ri]; } - (NSGridCellPlacement) yPlacement { return _yPlacement; } - (void) setYPlacement: (NSGridCellPlacement)y { _yPlacement = y; } - (CGFloat) height { return _height; } - (void) setHeight: (CGFloat)f { _height = f; } - (CGFloat) topPadding { return _topPadding; } - (void) setTopPadding: (CGFloat)f { _topPadding = f; } - (CGFloat) bottomPadding { return _bottomPadding; } - (void) setBottomPadding: (CGFloat)f { _bottomPadding = f; } - (BOOL) isHidden { return _isHidden; } - (void) setHidden: (BOOL)flag { _isHidden = flag; } - (void) mergeCellsInRange: (NSRange)range { NSUInteger ri = [_gridView indexOfRow: self]; NSRange vRange = NSMakeRange(ri, 1); [_gridView mergeCellsInHorizontalRange: range verticalRange: vRange]; } // coding - (void) encodeWithCoder: (NSCoder *)coder { if ([coder allowsKeyedCoding]) { [coder encodeBool: _isHidden forKey: @"NSGrid_hidden"]; [coder encodeFloat: _bottomPadding forKey: @"NSGrid_bottomPadding"]; [coder encodeObject: _gridView forKey: @"NSGrid_owningGrid"]; [coder encodeFloat: _topPadding forKey: @"NSGrid_topPadding"]; [coder encodeFloat: _height forKey: @"NSGrid_height"]; [coder encodeFloat: _yPlacement forKey: @"NSGrid_yPlacement"]; } else { [coder encodeValueOfObjCType: @encode(BOOL) at: &_isHidden]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_bottomPadding]; [coder encodeObject: _gridView]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_topPadding]; [coder encodeValueOfObjCType: @encode(CGFloat) at: &_height]; [coder encodeValueOfObjCType: @encode(NSInteger) at: &_yPlacement]; } } - (instancetype) initWithCoder: (NSCoder *)coder { self = [super init]; if (self != nil) { if ([coder allowsKeyedCoding]) { if ([coder containsValueForKey: @"NSGrid_hidden"]) { _isHidden = [coder decodeBoolForKey: @"NSGrid_hidden"]; } if ([coder containsValueForKey: @"NSGrid_bottomPadding"]) { _bottomPadding = [coder decodeFloatForKey: @"NSGrid_bottomPadding"]; } if ([coder containsValueForKey: @"NSGrid_owningGrid"]) { _gridView = [coder decodeObjectForKey: @"NSGrid_owningGrid"]; } if ([coder containsValueForKey: @"NSGrid_topPadding"]) { _topPadding = [coder decodeFloatForKey: @"NSGrid_topPadding"]; } if ([coder containsValueForKey: @"NSGrid_height"]) { _height = [coder decodeFloatForKey: @"NSGrid_height"]; } if ([coder containsValueForKey: @"NSGrid_yPlacement"]) { _yPlacement = [coder decodeFloatForKey: @"NSGrid_yPlacement"]; } } else { [coder decodeValueOfObjCType: @encode(BOOL) at: &_isHidden]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_bottomPadding]; _gridView = [coder decodeObject]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_topPadding]; [coder decodeValueOfObjCType: @encode(CGFloat) at: &_height]; [coder decodeValueOfObjCType: @encode(NSInteger) at: &_yPlacement]; } } return self; } @end