Skip to content

Instantly share code, notes, and snippets.

@boucher
Created March 24, 2010 22:57
Show Gist options
  • Save boucher/342932 to your computer and use it in GitHub Desktop.
Save boucher/342932 to your computer and use it in GitHub Desktop.
/*
* AppController.j
* CPBrowserTest
*
* Created by Ross Boucher on March 23, 2010.
* Copyright 2010, Your Company All rights reserved.
*/
@import <Foundation/CPObject.j>
@import "CPBrowser.j"
@implementation Node : CPObject
{
id value;
}
+ (id)withValue:(id)aValue
{
var a = [[self alloc] init];
a.value = aValue;
return a;
}
- (id)value
{
return value;
}
- (CPArray)children
{
return [[Node withValue:1],
[Node withValue:2],
[Node withValue:3],
[Node withValue:4]];
}
@end
@implementation AppController : CPObject
{
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
contentView = [theWindow contentView];
browser = [[CPBrowser alloc] initWithFrame:CGRectMake(0,0,500,300)];
//[browser setBackgroundColor:[CPColor blueColor]];
[browser setCenter:[contentView center]];
[contentView addSubview:browser];
[theWindow orderFront:self];
[browser setDelegate:self];
// Uncomment the following line to turn on the standard menu bar.
//[CPMenu setMenuBarVisible:YES];
}
- (id)rootItemForBrowser:(id)aBrowser
{
return [Node withValue:0];
}
- (id)browser:(id)aBrowser numberOfChildrenOfItem:(id)anItem
{
return [[anItem children] count];
}
- (id)browser:(id)aBrowser child:(int)index ofItem:(id)anItem
{
return [[anItem children] objectAtIndex:index];
}
- (id)browser:(id)aBrowser objectValueOfItem:(id)anItem
{
return [anItem value];
}
- (id)browser:(id)aBrowser itemIsLeaf:(id)anItem
{
return [[anItem children] count] && [anItem value] !== 4;
}
@end
/*
* CPBrowser.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2010, 280 North, Inc.
*
* 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-1301 USA
*/
@import <AppKit/CPControl.j>
CPBrowserIllegalDelegateException = "CPBrowserIllegalDelegateException";
/*!
@ingroup appkit
@class CPBrowser
*/
@implementation CPBrowser : CPControl
{
id _delegate;
CPString _pathSeparator;
CPView _contentView;
CPScrollView _horizontalScrollView;
CPView _prototypeView;
CPArray _tableViews;
CPArray _tableDelegates;
id _rootItem;
BOOL _delegateSupportsImages;
}
+ (CPImage)branchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
pathForResource:"browser-leaf.png"]
size:CGSizeMake(9,9)];
}
+ (CPImage)highlightedBranchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
pathForResource:"browser-leaf-highlighted.png"]
size:CGSizeMake(9,9)];
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMake(0, 0, 100.0, 23.0)];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
return self;
}
- (void)setDelegate:(id)anObject
{
_delegate = anObject;
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
[self loadColumnZero];
}
- (id)delegate
{
return _delegate;
}
- (CPTableView)tableViewInColumn:(unsigned)index
{
return _tableViews[index];
}
- (void)loadColumnZero
{
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
_rootItem = [_delegate rootItemForBrowser:self];
else
_rootItem = nil;
[self _loadColumn:0];
}
- (void)_loadColumn:(int)index
{
[_tableViews.slice(index) makeObjectsPerformSelector:@selector(removeFromSuperview)];
_tableViews = _tableViews.slice(0, index);
_tableDelegates = _tableDelegates.slice(0, index);
var table = [[CPTableView alloc] initWithFrame:CGRectMake(0, 0, 150, 150)];
[self _addTableColumnsToTableView:table];
var delegate = [[_CPBrowserTableDelegate alloc] init];
[delegate _setDelegate:_delegate];
[delegate _setBrowser:self];
[delegate _setIndex:index];
var itemForColumn = index === 0 ? _rootItem : [_tableDelegates[index - 1] _item];
[delegate _setItem:itemForColumn];
_tableViews[index] = table;
_tableDelegates[index] = delegate;
//[table setDelegate:delegate];
[table setDataSource:delegate];
var x = CGRectGetWidth([_contentView bounds]);
var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, x, 150.0, CGRectGetHeight([self bounds]))];
[scrollView setDocumentView:table];
[scrollView setHasHorizontalScroller:NO];
[_contentView addSubview:scrollView];
[_contentView setFrameSize:CGRectMake(x+150.0, CGRectGetHeight([_contentView bounds]))];
}
- (void)_addTableColumnsToTableView:(CPTableView)aTableView
{
if (_delegateSupportsImages)
{
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
view = [[CPImageView alloc] initWithFrame:CGRectMake(0, 0, 23, 23)];
[view setImageScaling:CPScaleProportionally];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[column setWidth:23];
[aTableView addTableColumn:column];
}
var column = [[CPTableColumn alloc] initWithIdentifier:@"Content"];
[column setDataView:_prototypeView];
[column setResizingMask:CPTableColumnNoResizing];
[column setWidth:CGRectGetWidth([_prototypeView frame])];
[aTableView addTableColumn:column];
/*
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero(0, 0, 23, 23)];
[view setBranchImage:[[self class] branchImage]];
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[column setWidth:23];
[aTableView addTableColumn:column];
*/
}
@end
@implementation _CPBrowserTableDelegate : CPObject
{
CPBrowser _browser @accessors;
unsigned _index @accessors;
id _delegate @accessors;
id _item @accessors;
}
- (unsigned)numberOfRowsInTableView:(CPTableView)aTableView
{
console.log([aTableView tableColumns].toString());
console.log("number of rows: "+aTableView+" - "+[_delegate browser:_browser numberOfChildrenOfItem:_item]);
return [_delegate browser:_browser numberOfChildrenOfItem:_item];
}
- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(unsigned)row
{console.log("tableView: "+aTableView+" objectValueForColumn: "+column+" row: "+row);
if ([column identifier] === "Image")
return [_delegate browser:_browser imageValueForItem:[self childAtIndex:row]];
else if ([column identifier] === "Leaf")
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:_browser isLeafItem:[self childAtIndex:row]];
else
return [_delegate browser:_browser objectValueForItem:[self childAtIndex:row]];
}
- (id)childAtIndex:(unsigned)index
{console.log("here: "+index);
return [_delegate browser:_browser child:index ofItem:_item];
}
@end
@implementation _CPBrowserLeafView : CPView
{
BOOL _isLeaf @accessors(readonly, property=isLeaf);
CPImage _branchImage @accessors(property=branchImage);
CPImage _highlightedBranchImage @accessors(property=highlightedBranchImage);
}
- (BOOL)objectValue
{
return _isLeaf;
}
- (void)setObjectValue:(id)aValue
{
_isLeaf = !!aValue;
[self setNeedsLayout];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
if (aName === "image-view")
return CGRectInset([self bounds], 1, 1);
return [super rectForEphemeralSubviewNamed:aName];
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if (aName === "image-view")
return [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
return [super createEphemeralSubviewNamed:aName];
}
- (void)layoutSubviews
{
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil];
var isHighlighted = [self themeState] & CPThemeStateHighlighted;
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
[imageView setImageScaling:CPScaleNone];
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
[aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
}
- (void)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
_branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
_highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
}
return self;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment