mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-31 05:50:48 +00:00
1280 lines
33 KiB
Objective-C
1280 lines
33 KiB
Objective-C
/* 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 <Foundation/NSArray.h>
|
|
#import "AppKit/NSGridView.h"
|
|
#import "GSFastEnumeration.h"
|
|
|
|
// Private interfaces...
|
|
@interface NSGridCell (Private)
|
|
- (void) _setOwningRow: (NSGridRow *)r;
|
|
- (void) _setOwningColumn: (NSGridColumn *)c;
|
|
@end
|
|
|
|
@interface NSGridView (Private)
|
|
- (NSArray *) _cellsForRowAtIndex: (NSUInteger)rowIndex;
|
|
- (NSArray *) _viewsForRowAtIndex: (NSUInteger)rowIndex;
|
|
- (NSArray *) _cellsForColumnAtIndex: (NSUInteger)columnIndex;
|
|
- (NSArray *) _viewsForColumnAtIndex: (NSUInteger)columnIndex;
|
|
@end
|
|
|
|
@implementation NSGridView (Private)
|
|
- (NSArray *) _cellsForRowAtIndex: (NSUInteger)rowIndex
|
|
{
|
|
NSMutableArray *result = [NSMutableArray arrayWithCapacity: [_columns count]];
|
|
NSGridRow *row = [_columns 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 _cellsForColumnAtIndex: 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: [_columns 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
|
|
{
|
|
NSUInteger i = 0;
|
|
NSUInteger num_col = [self numberOfColumns];
|
|
// NSUInteger num_rows = [self numberOfRows];
|
|
NSRect f = [self frame];
|
|
CGFloat current_x = 0.0, current_y = f.size.height;
|
|
NSMutableArray *colWidths = [NSMutableArray array];
|
|
NSMutableArray *rowHeights = [NSMutableArray array];
|
|
|
|
// precalculate w/h
|
|
FOR_IN(NSGridCell*, c, _cells)
|
|
{
|
|
NSView *v = [c contentView];
|
|
NSUInteger ri = 0, ci = 0;
|
|
NSRect rect = NSMakeRect(0,0,100,30); // default size by observation...
|
|
|
|
// Get row and column index...
|
|
ci = i % num_col;
|
|
ri = i / num_col;
|
|
|
|
if (v != nil)
|
|
{
|
|
rect = [v frame];
|
|
// NOTE: I am not sure why this is needed, the row and column heights are coming in via the nib
|
|
// as VERY small numbers (1.175...e-38) (see PR for this work, I have attached the XML nib there)
|
|
// so it is necessary to figure out the width of each column so that things can be properly spaced.
|
|
if (ci == 0)
|
|
{
|
|
if (rect.size.width > 0.0)
|
|
{
|
|
[rowHeights addObject: [NSNumber numberWithFloat: rect.size.height]];
|
|
}
|
|
}
|
|
|
|
if (ri == 0)
|
|
{
|
|
if (rect.size.width > 0.0)
|
|
{
|
|
[colWidths addObject: [NSNumber numberWithFloat: rect.size.width]];
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the first column or row is blank... then take the next value that is non-zero
|
|
if (ri > 0 && [colWidths count] == 0)
|
|
{
|
|
if (rect.size.width > 0.0)
|
|
{
|
|
[colWidths addObject: [NSNumber numberWithFloat: rect.size.width]];
|
|
}
|
|
}
|
|
|
|
if (ci > 0 && [rowHeights count] == 0)
|
|
{
|
|
if (rect.size.width > 0.0)
|
|
{
|
|
[rowHeights addObject: [NSNumber numberWithFloat: rect.size.height]];
|
|
}
|
|
}
|
|
}
|
|
END_FOR_IN(_cells);
|
|
|
|
// 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];
|
|
}
|
|
|
|
// Do the math for the frame...
|
|
// NOTE: I am not sure why this is needed, the row and column heights are coming in via the nib
|
|
// as VERY small numbers (1.175... e-38) (see PR for this work, I have attached the XML nib there)
|
|
// so it is necessary to figure out the width of each column so that things can be properly spaced.
|
|
if (ci == 0)
|
|
{
|
|
current_y -= [[rowHeights objectAtIndex: ci] floatValue]; // rect.size.height;
|
|
current_x = 0.0;
|
|
}
|
|
|
|
current_y -= [c yPlacement] - [row topPadding];
|
|
current_x += [c xPlacement] + [col leadingPadding] + [col width];
|
|
|
|
if (v != nil)
|
|
{
|
|
rect.origin.x = current_x;
|
|
rect.origin.y = current_y;
|
|
[v setFrame: rect];
|
|
[self addSubview: v];
|
|
}
|
|
|
|
current_x += [col trailingPadding] + [col width] + [[colWidths objectAtIndex: ci] floatValue] + _columnSpacing;
|
|
current_y -= [row bottomPadding] - [row height]; // - _rowSpacing; // add paddings after view...
|
|
|
|
// 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];
|
|
}
|
|
|
|
[self _refreshCells];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (instancetype) initWithViews: (NSArray *)rows // an array of arrays
|
|
{
|
|
self = [self initWithFrame: NSZeroRect];
|
|
|
|
NSUInteger c = 0;
|
|
NSUInteger r = 0;
|
|
|
|
if (self != nil)
|
|
{
|
|
NSUInteger rc = [rows count], cc = 0;
|
|
|
|
if (rc > 0)
|
|
{
|
|
cc = [[rows objectAtIndex: 0] count];
|
|
}
|
|
|
|
_cells = [[NSMutableArray alloc] initWithCapacity: rc * cc];
|
|
_rows = [[NSMutableArray alloc] initWithCapacity: rc];
|
|
_columns = [[NSMutableArray alloc] initWithCapacity: cc];
|
|
|
|
FOR_IN(NSArray*, row, rows)
|
|
{
|
|
NSArray *columns = [row objectAtIndex: c];
|
|
FOR_IN(NSArray*, column, columns)
|
|
{
|
|
NSView *v = [column objectAtIndex: c];
|
|
NSGridCell *cell = [[NSGridCell alloc] init];
|
|
|
|
if (r == 0)
|
|
{
|
|
NSGridRow *gr = [[NSGridRow alloc] init];
|
|
[gr setGridView: self];
|
|
[_rows addObject: gr];
|
|
[cell _setOwningRow: gr];
|
|
}
|
|
|
|
if (c == 0)
|
|
{
|
|
NSGridColumn *gc = [[NSGridColumn alloc] init];
|
|
[gc setGridView: self];
|
|
[_columns addObject: gc];
|
|
[cell _setOwningColumn: gc];
|
|
}
|
|
|
|
[cell setContentView: v];
|
|
[_cells addObject: cell];
|
|
c++;
|
|
}
|
|
END_FOR_IN(columns);
|
|
r++;
|
|
}
|
|
END_FOR_IN(rows);
|
|
[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++)
|
|
{
|
|
NSGridCell *gc = [[NSGridCell alloc] init];
|
|
[col addObject: gc];
|
|
RELEASE(gc);
|
|
}
|
|
[rows addObject: col];
|
|
}
|
|
|
|
return AUTORELEASE([self gridViewWithViews: rows]);
|
|
}
|
|
|
|
+ (instancetype) gridViewWithViews: (NSArray *)rows
|
|
{
|
|
return [[self alloc] initWithViews: rows];
|
|
}
|
|
|
|
- (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];
|
|
}
|
|
|
|
- (NSRect) _findProtypeView
|
|
{
|
|
NSRect f = NSMakeRect(0,0,10,10);
|
|
|
|
// Find a cell to base the size off of.
|
|
if ([_cells count] > 0)
|
|
{
|
|
FOR_IN(NSGridCell*, acell, _cells)
|
|
{
|
|
NSView *av = [acell contentView];
|
|
if (av)
|
|
{
|
|
f = [av frame];
|
|
break;
|
|
}
|
|
}
|
|
END_FOR_IN(_cells);
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
- (NSGridRow *) insertRowAtIndex: (NSInteger)index withViews: (NSArray *)views
|
|
{
|
|
NSGridRow *gr = [[NSGridRow alloc] init];
|
|
|
|
// Insert the row and release...
|
|
[_rows insertObject: gr atIndex: index];
|
|
[gr setGridView: self];
|
|
RELEASE(gr);
|
|
|
|
NSRect f = [self _findProtypeView];
|
|
NSUInteger i = 0;
|
|
NSUInteger pos = index * [self numberOfColumns];
|
|
FOR_IN(NSView*, v, views)
|
|
{
|
|
NSGridCell *c = [[NSGridCell alloc] init];
|
|
NSGridColumn *col = [_columns objectAtIndex: i];
|
|
|
|
[col setGridView: self];
|
|
[c _setOwningRow: gr];
|
|
[c _setOwningColumn: col];
|
|
[v setFrame: f];
|
|
[c setContentView: v];
|
|
RELEASE(v);
|
|
[_cells insertObject: c
|
|
atIndex: pos + i];
|
|
RELEASE(c);
|
|
i++;
|
|
}
|
|
END_FOR_IN(views);
|
|
|
|
// Insert remaineder of cells for views not present..
|
|
NSUInteger r = [self numberOfColumns] - i;
|
|
NSUInteger idx = 0;
|
|
pos += i;
|
|
for(idx = 0; idx < r; idx++)
|
|
{
|
|
NSGridCell *c = [[NSGridCell alloc] init];
|
|
[_cells insertObject: c atIndex: pos + idx];
|
|
}
|
|
|
|
// Refresh...
|
|
[self _refreshCells];
|
|
return gr;
|
|
}
|
|
|
|
- (void) moveRowAtIndex: (NSInteger)fromIndex toIndex: (NSInteger)toIndex
|
|
{
|
|
NSArray *views = [self _viewsForRowAtIndex: fromIndex];
|
|
[self removeRowAtIndex: fromIndex];
|
|
[self insertRowAtIndex: toIndex withViews: views];
|
|
}
|
|
|
|
- (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 withViews: (NSArray *)views
|
|
{
|
|
NSGridColumn *gc = [[NSGridColumn alloc] init];
|
|
|
|
// Insert the row and release...
|
|
[_columns insertObject: gc atIndex: index];
|
|
[gc setGridView: self];
|
|
RELEASE(gc);
|
|
|
|
NSRect f = [self _findProtypeView];
|
|
NSUInteger i = 0;
|
|
NSUInteger pos = index; // * [self numberOfColumns];
|
|
FOR_IN(NSView*, v, views)
|
|
{
|
|
NSGridCell *c = [[NSGridCell alloc] init];
|
|
NSGridRow *row = [_rows objectAtIndex: i];
|
|
|
|
[row setGridView: self];
|
|
[c _setOwningRow: row];
|
|
[c _setOwningColumn: gc];
|
|
[v setFrame: f];
|
|
[c setContentView: v];
|
|
RELEASE(v);
|
|
[_cells insertObject: c
|
|
atIndex: pos + i * [self numberOfColumns]];
|
|
RELEASE(c);
|
|
i++;
|
|
}
|
|
END_FOR_IN(views);
|
|
|
|
// Insert remaineder of cells for views not present..
|
|
NSUInteger r = [self numberOfColumns] - i;
|
|
NSUInteger idx = 0;
|
|
pos += i;
|
|
for(idx = 0; idx < r; idx++)
|
|
{
|
|
NSGridCell *c = [[NSGridCell alloc] init];
|
|
[_cells insertObject: c atIndex: pos + idx * [self numberOfColumns]];
|
|
}
|
|
|
|
// Refresh...
|
|
[self _refreshCells];
|
|
return gc;
|
|
}
|
|
|
|
- (void) moveColumnAtIndex: (NSInteger)fromIndex toIndex: (NSInteger)toIndex
|
|
{
|
|
NSArray *views = [self _viewsForColumnAtIndex: fromIndex];
|
|
[self removeColumnAtIndex: fromIndex];
|
|
[self insertColumnAtIndex: toIndex withViews: views];
|
|
}
|
|
|
|
- (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 encodeFloat: _columnSpacing
|
|
forKey: @"NSGrid_columnSpacing"];
|
|
[coder encodeObject: _columns
|
|
forKey: @"NSGrid_columns"];
|
|
[coder encodeFloat: _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)
|
|
{
|
|
NSDebugLog(@"%@ %@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
|
|
if ([coder allowsKeyedCoding])
|
|
{
|
|
if ([coder containsValueForKey: @"NSGrid_alignment"])
|
|
{
|
|
_rowAlignment = (NSGridRowAlignment)[coder decodeIntegerForKey: @"NSGrid_alignment"];
|
|
NSDebugLog(@"_rowAlignment = %ld", _rowAlignment);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_columns"])
|
|
{
|
|
ASSIGN(_columns, [coder decodeObjectForKey: @"NSGrid_columns"]);
|
|
NSDebugLog(@"_columns = %@", _columns);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_rows"])
|
|
{
|
|
ASSIGN(_rows, [coder decodeObjectForKey: @"NSGrid_rows"]);
|
|
NSDebugLog(@"_rows = %@", _rows);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_cells"])
|
|
{
|
|
ASSIGN(_cells, [coder decodeObjectForKey: @"NSGrid_cells"]);
|
|
NSDebugLog(@"_cells = %@", _cells);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_columnSpacing"])
|
|
{
|
|
_columnSpacing = [coder decodeFloatForKey: @"NSGrid_columnSpacing"];
|
|
NSDebugLog(@"_columnSpacing = %f", _columnSpacing);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_rowSpacing"])
|
|
{
|
|
_rowSpacing = [coder decodeFloatForKey: @"NSGrid_rowSpacing"];
|
|
NSDebugLog(@"_rowSpacing = %f", _rowSpacing);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_xPlacement"])
|
|
{
|
|
_xPlacement = [coder decodeIntegerForKey: @"NSGrid_xPlacement"];
|
|
NSDebugLog(@"_xPlacement = %ld", _xPlacement);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_yPlacement"])
|
|
{
|
|
_yPlacement = [coder decodeIntegerForKey: @"NSGrid_yPlacement"];
|
|
NSDebugLog(@"_yPlacement = %ld", _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];
|
|
}
|
|
}
|
|
|
|
/*
|
|
- (instancetype) init
|
|
{
|
|
self = [super init];
|
|
if (self != nil)
|
|
{
|
|
[self setContentView: [[self class] emptyContentView]];
|
|
}
|
|
return self;
|
|
}
|
|
*/
|
|
|
|
- (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 nil;
|
|
}
|
|
|
|
// 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 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)
|
|
{
|
|
NSDebugLog(@"%@ %@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
|
|
|
|
if ([coder allowsKeyedCoding])
|
|
{
|
|
if ([coder containsValueForKey: @"NSGrid_content"])
|
|
{
|
|
[self setContentView: [coder decodeObjectForKey: @"NSGrid_content"]];
|
|
NSDebugLog(@"contentView = %@", [self contentView]);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_mergeHead"])
|
|
{
|
|
_mergeHead = [coder decodeObjectForKey: @"NSGrid_mergeHead"];
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_owningRow"])
|
|
{
|
|
_owningRow = [coder decodeObjectForKey: @"NSGrid_owningRow"]; // weak
|
|
NSDebugLog(@"_owningRow = %@", _owningRow);
|
|
}
|
|
if ([coder containsValueForKey: @"NSGrid_owningColumn"])
|
|
{
|
|
_owningColumn = [coder decodeObjectForKey: @"NSGrid_owningColumn"]; // weak
|
|
NSDebugLog(@"_owningColumn = %@", _owningColumn);
|
|
}
|
|
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
|
|
[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
|
|
{
|
|
NSUInteger ci = [_gridView indexOfColumn: self];
|
|
NSArray *arr = [_gridView _cellsForColumnAtIndex: ci];
|
|
return [arr count];
|
|
}
|
|
|
|
- (NSGridCell *) cellAtIndex:(NSInteger)index
|
|
{
|
|
NSUInteger ci = [_gridView indexOfColumn: self];
|
|
NSArray *arr = [_gridView _cellsForColumnAtIndex: ci];
|
|
return [arr objectAtIndex: 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
|
|
{
|
|
NSLog(@"Method %@ unimplemented.", NSStringFromSelector(_cmd));
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
NSDebugLog(@"%@ %@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
|
|
// _cells = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
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"];
|
|
NSDebugLog(@"_width = %f", _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
|
|
{
|
|
NSUInteger ri = [_gridView indexOfRow: self];
|
|
NSArray *arr = [_gridView _cellsForRowAtIndex: ri];
|
|
return [arr count];
|
|
}
|
|
|
|
- (NSGridCell *) cellAtIndex:(NSInteger)index
|
|
{
|
|
NSUInteger ri = [_gridView indexOfRow: self];
|
|
NSArray *arr = [_gridView _cellsForRowAtIndex: ri];
|
|
return [arr objectAtIndex: index];
|
|
}
|
|
|
|
- (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
|
|
{
|
|
NSLog(@"Method %@ unimplemented.", NSStringFromSelector(_cmd));
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
NSDebugLog(@"%@ %@",NSStringFromClass([self class]), NSStringFromSelector(_cmd));
|
|
// _cells = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
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"];
|
|
NSDebugLog(@"_height = %f", _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
|