Created
December 4, 2015 13:19
-
-
Save Thesaurus/f6e6d60495cb8f29eb48 to your computer and use it in GitHub Desktop.
Using NSTableView as a grid control.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TSGridView.h | |
// | |
// Created by Jonathan Mitchell on 06/07/2015. | |
// Copyright (c) 2015 Thesaurus Software Limited. All rights reserved. | |
// | |
#import <Cocoa/Cocoa.h> | |
extern NSString *TSGridColumns; | |
extern NSString *TSGridIdentifier; | |
extern NSString *TSGridWidth; | |
extern NSString *TSGridObject; | |
extern NSString *TSGridPath; | |
extern NSString *TSGridOptions; | |
extern NSString *TSGridItems; | |
extern NSString *TSGridItemValue; | |
extern NSString *TSGridItemFormatter; | |
extern NSString *TSGridItemControlSize; | |
extern NSString *TSGridItemValueBinding; | |
extern NSString *TSGridItemType; | |
extern NSString *TSGridItemTypeLabel; | |
extern NSString *TSGridItemTypeInput; | |
@interface TSGridView : NSTableView <NSTabViewDelegate, NSObject> | |
- (id)initWithDictionary:(NSDictionary *)config; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TSGridView.m | |
// | |
// Created by Jonathan Mitchell on 06/07/2015. | |
// Copyright (c) 2015 Thesaurus Software Limited. All rights reserved. | |
// | |
#import "TSGridView.h" | |
#import "BPTableCellView.h" | |
#import "BPPercentageInputTableCellView.h" | |
NSString *TSGridColumns = @"columns"; | |
NSString *TSGridIdentifier = @"identifier"; | |
NSString *TSGridWidth = @"width"; | |
NSString *TSGridItems = @"items"; | |
NSString *TSGridObject = @"object"; | |
NSString *TSGridPath = @"path"; | |
NSString *TSGridOptions = @"options"; | |
NSString *TSGridItemValue = @"value"; | |
NSString *TSGridItemFormatter = @"formatter"; | |
NSString *TSGridItemControlSize = @"controlSize"; | |
NSString *TSGridItemValueBinding = @"valueBinding"; | |
NSString *TSGridItemType = @"type"; | |
NSString *TSGridItemTypeLabel = @"label"; | |
NSString *TSGridItemTypeInput = @"input"; | |
@interface TSGridView() | |
@property (strong) NSArray *gridRows; | |
@end | |
@implementation TSGridView | |
#pragma mark - | |
#pragma mark Lifecycle | |
- (id)initWithDictionary:(NSDictionary *)config | |
{ | |
self = [super init]; | |
if (self) { | |
[self configure]; | |
[self configureWithDictionary:config]; | |
} | |
return self; | |
} | |
- (void)dealloc | |
{ | |
} | |
- (void)configureWithDictionary:(NSDictionary *)config | |
{ | |
// define columns | |
NSArray *columns = config[TSGridColumns]; | |
for (NSDictionary *columnInfo in columns) { | |
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:columnInfo[TSGridIdentifier]]; | |
column.minWidth = 50; | |
column.resizingMask = NSTableColumnAutoresizingMask; | |
column.width = [columnInfo[TSGridWidth] doubleValue]; | |
[self addTableColumn:column]; | |
} | |
} | |
- (void)configure | |
{ | |
// basic grid configuration | |
self.focusRingType = NSFocusRingTypeNone; | |
self.selectionHighlightStyle = NSTableViewSelectionHighlightStyleNone; | |
self.gridStyleMask = NSTableViewSolidVerticalGridLineMask | NSTableViewSolidHorizontalGridLineMask; | |
self.gridColor = [NSColor lightGrayColor]; | |
self.rowHeight = 30; | |
self.columnAutoresizingStyle = NSTableViewUniformColumnAutoresizingStyle; | |
self.intercellSpacing = NSMakeSize(0, 0); | |
// in order to keep things self contained we will act as our own delegate | |
self.delegate = (id)self; | |
// register cell views for the supported grid item type | |
NSNib *columnCellNib = nil; | |
columnCellNib = [[NSNib alloc] initWithNibNamed:[BPTableCellView className] bundle:nil]; | |
[self registerNib:columnCellNib forIdentifier:TSGridItemTypeLabel]; | |
columnCellNib = [[NSNib alloc] initWithNibNamed:[BPPercentageInputTableCellView className] bundle:nil]; | |
[self registerNib:columnCellNib forIdentifier:TSGridItemTypeInput]; | |
} | |
#pragma mark - | |
#pragma mark Overrides | |
- (void)reloadData | |
{ | |
// called when content binding changes | |
NSDictionary *bindingInfo = [self infoForBinding:NSContentBinding]; | |
NSObject *bindingObject = bindingInfo[NSObservedObjectKey]; | |
NSString *bindingKeyPath = bindingInfo[NSObservedKeyPathKey]; | |
self.gridRows = [bindingObject valueForKeyPath:bindingKeyPath]; | |
[super reloadData]; | |
} | |
#pragma mark - | |
#pragma mark NSTableView delegate | |
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row | |
{ | |
// use tableColumn identifier to access row item data | |
NSDictionary *gridRow = self.gridRows[row]; | |
NSDictionary *rowItems = gridRow[TSGridItems]; | |
NSDictionary *rowItem = rowItems[tableColumn.identifier]; | |
// make view according to row item type rather than by tableColumn idenitifer | |
NSString *gridItemType = rowItem[TSGridItemType]; | |
NSView *view = nil; | |
// query the row item | |
id itemValue = rowItem[TSGridItemValue]; | |
NSFormatter *formatter = rowItem[TSGridItemFormatter]; | |
NSControlSize controlSize = NSRegularControlSize; | |
if (rowItem[TSGridItemControlSize]) { | |
controlSize = [rowItem[TSGridItemControlSize] integerValue]; | |
} | |
float fontSize = [NSFont systemFontSizeForControlSize:controlSize]; | |
NSFont *font = [NSFont systemFontOfSize:fontSize]; | |
// get binding info | |
NSDictionary *valueBinding = rowItem[TSGridItemValueBinding]; | |
NSString *valueBindingKeyPath = nil; | |
NSDictionary *valueBindingOptions = nil; | |
if (valueBinding) { | |
valueBindingKeyPath = valueBinding[TSGridPath]; | |
valueBindingOptions = valueBinding[TSGridOptions]; | |
} | |
NSObject *bindTo = gridRow[TSGridObject]; | |
// load required table cell view | |
if ([gridItemType isEqualToString:TSGridItemTypeLabel] || | |
[gridItemType isEqualToString:TSGridItemTypeInput]) { | |
// make the cell | |
BPTableCellView *cellView = [self makeViewWithIdentifier:gridItemType owner:nil]; | |
// cells can get recycled | |
cellView.textField.objectValue = nil; | |
[cellView.textField unbind:NSValueBinding]; | |
cellView.textField.formatter = formatter; | |
// set size | |
((NSCell *)(cellView.textField.cell)).controlSize = controlSize; | |
cellView.textField.font = font; | |
// set value | |
if (itemValue) { | |
cellView.textField.objectValue = itemValue; | |
} | |
// binding | |
if (bindTo && valueBindingKeyPath) { | |
[cellView.textField bind:NSValueBinding toObject:bindTo withKeyPath:valueBindingKeyPath options:valueBindingOptions]; | |
} | |
view = cellView; | |
} | |
return view; | |
} | |
- (NSSize)intrinsicContentSize | |
{ | |
CGFloat h = self.gridRows.count * self.rowHeight; | |
return NSMakeSize(NSViewNoInstrinsicMetric, h); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment