mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-16 21:41:18 +00:00
First pass at themes in Cappuccino.
Reviewed by me.
This commit is contained in:
1 parent
69cf9b34b1
commit
492f4b6480
45 files changed
+2401
-1104
No files matched your search
@@ -15,6 +15,7 @@
|
||||
<string>CPTableColumn.j</string>
|
||||
<string>CPTableView.j</string>
|
||||
<!-- These get compiled into CGContext -->
|
||||
<string>Themes</string>
|
||||
<string>CoreGraphics/CGContextCanvas.j</string>
|
||||
<string>CoreGraphics/CGContextVML.j</string>
|
||||
</array>
|
||||
@@ -29,6 +30,7 @@
|
||||
<string>CPOutlineView.j</string>
|
||||
<string>CPTableColumn.j</string>
|
||||
<string>CPTableView.j</string>
|
||||
<string>Themes</string>
|
||||
<!-- These get compiled into CGContext -->
|
||||
<string>CoreGraphics/CGContextCanvas.j</string>
|
||||
<string>CoreGraphics/CGContextVML.j</string>
|
||||
|
||||
+1
-1
@@ -324,7 +324,7 @@ var _hueComponent = 0,
|
||||
if (self)
|
||||
{
|
||||
_patternImage = anImage;
|
||||
_cssString = "url(\"" + _patternImage._filename + "\")";
|
||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
+1
-1
@@ -393,7 +393,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
if ((_sendActionOn & (1 << type)) && isWithinFrame)
|
||||
[self sendAction:_action to:_target];
|
||||
|
||||
_trackingWasInFrame = isWithinFrame;
|
||||
_trackingWasWithinFrame = isWithinFrame;
|
||||
_previousTrackingLocation = currentLocation;
|
||||
}
|
||||
|
||||
|
||||
@@ -338,6 +338,11 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (CPArray)imageSlices
|
||||
{
|
||||
return _imageSlices;
|
||||
@@ -402,6 +407,11 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (CPArray)imageSlices
|
||||
{
|
||||
return _imageSlices;
|
||||
|
||||
+392
-354
@@ -1,67 +1,28 @@
|
||||
/*
|
||||
* CPSlider.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 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 "CPControl.j"
|
||||
@import <AppKit/CPControl.j>
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
var CPSliderHorizontalKnobImage = nil,
|
||||
CPSliderHorizontalBarLeftImage = nil,
|
||||
CPSliderHorizontalBarRightImage = nil,
|
||||
CPSliderHorizontalBarCenterImage = nil;
|
||||
|
||||
/*! @class CPSlider
|
||||
|
||||
An CPSlider displays, and allows control of, some value in the application. It represents a continuous stream of values of type <code>float</code>, which can be retrieved by the method <code>floatValue</code> and set by the method <code>setFloatValue:</code>.
|
||||
*/
|
||||
@implementation CPSlider : CPControl
|
||||
{
|
||||
double _minValue;
|
||||
double _maxValue;
|
||||
double _altIncrementValue;
|
||||
BOOL _isVertical;
|
||||
double _minValue;
|
||||
double _maxValue;
|
||||
double _altIncrementValue;
|
||||
|
||||
CPView _bar;
|
||||
CPView _knob;
|
||||
|
||||
CPImageView _standardKnob;
|
||||
CPView _standardVerticalBar;
|
||||
CPView _standardHorizontalBar;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [CPSlider class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
CPColor _verticalTrackColor; // vertical-track-color
|
||||
CPColor _horizontalTrackColor; // horizontal-track-color
|
||||
|
||||
CPSliderKnobImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderKnobRegular.png"] size:CPSizeMake(11.0, 11.0)],
|
||||
CPSliderKnobPushedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderKnobRegularPushed.png"] size:CPSizeMake(11.0, 11.0)],
|
||||
CPSliderHorizontalBarLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderTrackHorizontalLeft.png"] size:CPSizeMake(2.0, 4.0)],
|
||||
CPSliderHorizontalBarRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderTrackHorizontalRight.png"] size:CPSizeMake(2.0, 4.0)],
|
||||
CPSliderHorizontalBarCenterImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderTrackHorizontalCenter.png"] size:CPSizeMake(1.0, 4.0)];
|
||||
CPColor _knobColor; // knob-color
|
||||
CPColor _highlightedKnobColor; // knob-color-highlighted
|
||||
|
||||
float _trackWidth; // track-width
|
||||
CGSize _knobSize; // knob-size
|
||||
|
||||
BOOL _isHighlighted;
|
||||
|
||||
CPView _trackView;
|
||||
CPView _knobView;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -70,83 +31,353 @@ var CPSliderHorizontalKnobImage = nil,
|
||||
|
||||
if (self)
|
||||
{
|
||||
_value = 50.0;
|
||||
_minValue = 0.0;
|
||||
_maxValue = 100.0;
|
||||
|
||||
_bar = [self bar];
|
||||
_knob = [self knob];
|
||||
_knobSize = [[self knobImage] size];
|
||||
_isVertical = [self isVertical];
|
||||
|
||||
[self setObjectValue:50.0];
|
||||
|
||||
[self setContinuous:YES];
|
||||
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
|
||||
[self addSubview:_bar];
|
||||
[self addSubview:_knob];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
|
||||
- (void)setMinValue:(float)aMinimumValue
|
||||
{
|
||||
if (aSize.height > 21.0)
|
||||
aSize.height = 21.0;
|
||||
if (_minValue === aMinimumValue)
|
||||
return;
|
||||
|
||||
if (_isVertical != [self isVertical])
|
||||
_minValue = aMinimumValue;
|
||||
|
||||
var doubleValue = [self doubleValue];
|
||||
|
||||
if (doubleValue < _minValue)
|
||||
[self setdoubleValue:_minValue];
|
||||
}
|
||||
|
||||
- (float)minValue
|
||||
{
|
||||
return _minValue;
|
||||
}
|
||||
|
||||
- (void)setMaxValue:(float)aMaximumValue
|
||||
{
|
||||
if (_maxValue === aMaximumValue)
|
||||
return;
|
||||
|
||||
_maxValue = aMaximumValue;
|
||||
|
||||
var doubleValue = [self doubleValue];
|
||||
|
||||
if (doubleValue > _maxValue)
|
||||
[self setdoubleValue:_maxValue];
|
||||
}
|
||||
|
||||
- (float)maxValue
|
||||
{
|
||||
return _maxValue;
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue
|
||||
{
|
||||
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: instead.");
|
||||
|
||||
[self setObjectValue:aValue];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)setHorizontalTrackColor:(CPColor)aColor
|
||||
{
|
||||
if (_horizontalTrackColor === aColor)
|
||||
return;
|
||||
|
||||
_horizontalTrackColor = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPColor)horizontalTrackColor
|
||||
{
|
||||
return _horizontalTrackColor;
|
||||
}
|
||||
|
||||
- (void)setVerticalTrackColor:(CPColor)aColor
|
||||
{
|
||||
if (_verticalTrackColor === aColor)
|
||||
return;
|
||||
|
||||
_verticalTrackColor = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPColor)verticalTrackColor
|
||||
{
|
||||
return _verticalTrackColor;
|
||||
}
|
||||
|
||||
- (void)setTrackWidth:(float)aTrackWidth
|
||||
{
|
||||
if (_trackWidth === aTrackWidth)
|
||||
return;
|
||||
|
||||
_trackWidth = aTrackWidth;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (float)trackWidth
|
||||
{
|
||||
return _trackWidth;
|
||||
}
|
||||
|
||||
- (CGRect)trackRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var trackWidth = [self trackWidth];
|
||||
|
||||
if (!trackWidth)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
_isVertical = [self isVertical];
|
||||
|
||||
var bar = [self bar],
|
||||
knob = [self knob];
|
||||
|
||||
if (_bar != bar)
|
||||
[self replaceSubview:_bar = bar withView:_bar];
|
||||
|
||||
if (_knob != knob)
|
||||
{
|
||||
[self replaceSubview:knob withView:_knob];
|
||||
|
||||
_knob = knob;
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
}
|
||||
bounds.origin.x = (_CGRectGetWidth(bounds) - trackWidth) / 2.0;
|
||||
bounds.size.width = _trackWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
bounds.origin.y = (_CGRectGetHeight(bounds) - trackWidth) / 2.0;
|
||||
bounds.size.height = _trackWidth;
|
||||
}
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (void)setHighlightedKnobColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightedKnobColor === aColor)
|
||||
_highlightedKnobColor = aColor;
|
||||
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
_highlightedKnobColor = aColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value by which the slider will be
|
||||
incremented if the user holds down the <code>ALT</code>s key.
|
||||
*/
|
||||
- (double)altIncrementValue
|
||||
- (CPColor)highlightedKnobColor
|
||||
{
|
||||
return _altIncrementValue;
|
||||
return _highlightedKnobColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the value the slider will be incremented if the user holds the <code>ALT</code> key.
|
||||
*/
|
||||
- (void)setAltIncrementValue:(double)anIncrementValue
|
||||
- (void)setKnobSize:(CGSize)aKnobSize
|
||||
{
|
||||
_altIncrementValue = anIncrementValue;
|
||||
if (_knobSize && (!aKnobSize || _CGSizeEqualToSize(_knobSize, aKnobSize)))
|
||||
return;
|
||||
|
||||
_knobSize = aKnobSize ? _CGSizeMakeCopy(aKnobSize) : nil;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the control can continuously send its action messages.
|
||||
*/
|
||||
- (BOOL)isContinuous
|
||||
- (void)setKnobColor:(CPColor)aColor
|
||||
{
|
||||
return (_sendActionOn & CPLeftMouseDraggedMask) != 0;
|
||||
if (_knobColor === aColor)
|
||||
return;
|
||||
|
||||
_knobColor = aColor;
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPColor)knobColor
|
||||
{
|
||||
return _knobColor;
|
||||
}
|
||||
|
||||
- (CGRect)knobRectForBounds:(CGRect)bounds
|
||||
{
|
||||
if (!_knobSize || _knobSize.width <= 0 || _knobSize.height <= 0)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var knobRect = _CGRectMake(0.0, 0.0, _knobSize.width, _knobSize.height),
|
||||
trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
// No track, do our best to approximate a place for this thing.
|
||||
if (!trackRect || _CGRectIsEmpty(trackRect))
|
||||
trackRect = bounds;
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
knobRect.origin.x = _CGRectGetMidX(trackRect) - _knobSize.width / 2.0;
|
||||
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - _knobSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
knobRect.origin.x = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetWidth(trackRect) - _knobSize.width);
|
||||
knobRect.origin.y = _CGRectGetMidY(trackRect) - _knobSize.height / 2.0;
|
||||
}
|
||||
|
||||
return knobRect;
|
||||
}
|
||||
|
||||
- (int)isVertical
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
width = CGRectGetWidth(bounds),
|
||||
height = CGRectGetHeight(bounds);
|
||||
|
||||
return width < height ? 1 : (width > height ? 0 : -1);
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
isVertical = [self isVertical],
|
||||
trackRect = nil;
|
||||
|
||||
if ((isVertical && _verticalTrackColor || !isVertical && _horizontalTrackColor) &&
|
||||
(trackRect = [self trackRectForBounds:_CGRectMakeCopy(bounds)]) && !_CGRectIsEmpty(trackRect))
|
||||
{
|
||||
if (!_trackView)
|
||||
{
|
||||
_trackView = [[CPView alloc] initWithFrame:trackRect];
|
||||
|
||||
[_trackView setHitTests:NO];
|
||||
|
||||
[self addSubview:_trackView positioned:CPWindowBelow relativeTo:_knobView];
|
||||
}
|
||||
else
|
||||
[_trackView setFrame:trackRect];
|
||||
|
||||
if ([self isVertical])
|
||||
[_trackView setBackgroundColor:_verticalTrackColor];
|
||||
else
|
||||
[_trackView setBackgroundColor:_horizontalTrackColor];
|
||||
}
|
||||
else if (_trackView)
|
||||
{
|
||||
[_trackView removeFromSuperview];
|
||||
|
||||
_trackView = nil;
|
||||
}
|
||||
|
||||
var knobRect = nil;
|
||||
|
||||
if (_knobColor && (knobRect = [self knobRectForBounds:bounds]) && !_CGRectIsEmpty(knobRect))
|
||||
{
|
||||
if (!_knobView)
|
||||
{
|
||||
_knobView = [[CPView alloc] initWithFrame:knobRect];
|
||||
|
||||
[_knobView setHitTests:NO];
|
||||
|
||||
[self addSubview:_knobView positioned:CPWindowAbove relativeTo:_trackView];
|
||||
}
|
||||
else
|
||||
[_knobView setFrame:knobRect];
|
||||
|
||||
if (_isHighlighted)
|
||||
{
|
||||
if (_highlightedKnobColor)
|
||||
[_knobView setBackgroundColor:_highlightedKnobColor];
|
||||
}
|
||||
else
|
||||
[_knobView setBackgroundColor:_knobColor];
|
||||
}
|
||||
else if (_knobView)
|
||||
{
|
||||
[_knobView removeFromSuperview];
|
||||
|
||||
_knobView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tracksMouseOutsideOfFrame
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (float)_valueAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
knobRect = [self knobRectForBounds:bounds],
|
||||
trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
var knobHeight = _CGRectGetHeight(knobRect);
|
||||
|
||||
trackRect.origin.y += knobHeight / 2;
|
||||
trackRect.size.height -= knobHeight;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else
|
||||
|
||||
var knobWidth = _CGRectGetWidth(knobRect);
|
||||
|
||||
trackRect.origin.x += knobWidth / 2;
|
||||
trackRect.size.width -= knobWidth;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.x - _CGRectGetMinX(trackRect)) / _CGRectGetWidth(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
|
||||
|
||||
if (_CGRectContainsPoint(knobRect, aPoint))
|
||||
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
|
||||
|
||||
else
|
||||
{
|
||||
var trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
|
||||
{
|
||||
_dragOffset = _CGSizeMakeZero();
|
||||
|
||||
[self setObjectValue:[self _valueAtPoint:aPoint]];
|
||||
}
|
||||
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
_isHighlighted = YES;
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||
{
|
||||
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
_isHighlighted = NO;
|
||||
|
||||
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
|
||||
[_target sliderDidFinish:self];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the cell can continuously send its action messages.
|
||||
*/
|
||||
@ignore
|
||||
shoudl we have _continuous?
|
||||
*/
|
||||
- (void)setContinuous:(BOOL)flag
|
||||
{
|
||||
if (flag)
|
||||
@@ -155,255 +386,52 @@ var CPSliderHorizontalKnobImage = nil,
|
||||
_sendActionOn &= ~CPLeftMouseDraggedMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the thickness of the slider's knob. This value is in pixels,
|
||||
and is the size of the knob along the slider's track.
|
||||
*/
|
||||
- (float)knobThickness
|
||||
{
|
||||
return CPRectGetWidth([_knob frame]);
|
||||
}
|
||||
@end
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)leftTrackImage
|
||||
{
|
||||
return CPSliderHorizontalBarLeftImage;
|
||||
}
|
||||
@implementation CPSlider (Theming)
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)rightTrackImage
|
||||
- (void)viewDidChangeTheme
|
||||
{
|
||||
return CPSliderHorizontalBarRightImage;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)centerTrackImage
|
||||
{
|
||||
return CPSliderHorizontalBarCenterImage
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)knobImage
|
||||
{
|
||||
return CPSliderKnobImage;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)pushedKnobImage
|
||||
{
|
||||
return CPSliderKnobPushedImage;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's knob.
|
||||
*/
|
||||
- (CPView)knob
|
||||
{
|
||||
if (!_standardKnob)
|
||||
{
|
||||
var knobImage = [self knobImage],
|
||||
knobSize = [knobImage size];
|
||||
|
||||
_standardKnob = [[CPImageView alloc] initWithFrame:CPRectMake(0.0, 0.0, knobSize.width, knobSize.height)];
|
||||
|
||||
[_standardKnob setHitTests:NO];
|
||||
[_standardKnob setImage:knobImage];
|
||||
}
|
||||
[super viewDidChangeTheme];
|
||||
|
||||
return _standardKnob;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's bar.
|
||||
*/
|
||||
- (CPView)bar
|
||||
{
|
||||
// FIXME: veritcal.
|
||||
if ([self isVertical])
|
||||
return nil;
|
||||
else
|
||||
{
|
||||
if (!_standardHorizontalBar)
|
||||
{
|
||||
var frame = [self frame],
|
||||
barFrame = CPRectMake(0.0, 0.0, CPRectGetWidth(frame), 4.0);
|
||||
|
||||
_standardHorizontalBar = [[CPView alloc] initWithFrame:barFrame];
|
||||
|
||||
[_standardHorizontalBar setBackgroundColor:[CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[[self leftTrackImage], [self centerTrackImage], [self rightTrackImage]] isVertical:NO]]];
|
||||
|
||||
[_standardHorizontalBar setFrame:CPRectMake(0.0, (CPRectGetHeight(frame) - CPRectGetHeight(barFrame)) / 2.0, CPRectGetWidth(_isVertical ? barFrame : frame), CPRectGetHeight(_isVertical ? frame : barFrame))];
|
||||
[_standardHorizontalBar setAutoresizingMask:_isVertical ? CPViewHeightSizable : CPViewWidthSizable];
|
||||
}
|
||||
|
||||
return _standardHorizontalBar;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns <code>YES</code> if the slider is vertical.
|
||||
*/
|
||||
- (BOOL)isVertical
|
||||
{
|
||||
var frame = [self frame];
|
||||
var theme = [self theme];
|
||||
|
||||
if (CPRectGetWidth(frame) == CPRectGetHeight(frame))
|
||||
return -1;
|
||||
if (!theme)
|
||||
return;
|
||||
|
||||
[self setKnobSize:[theme valueForKey:@"knob-size"]];
|
||||
[self setKnobColor:[theme valueForKey:@"knob-color"]];
|
||||
[self setHighlightedKnobColor:[theme valueForKey:@"knob-color-highlighted"]];
|
||||
|
||||
return CPRectGetWidth(frame) < CPRectGetHeight(frame);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's maximum value
|
||||
*/
|
||||
- (double)maxValue
|
||||
{
|
||||
return _maxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's minimum value
|
||||
*/
|
||||
- (double)minValue
|
||||
{
|
||||
return _minValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the slider's maximum value
|
||||
@param aMaxValue the new maximum value
|
||||
*/
|
||||
- (void)setMaxValue:(double)aMaxValue
|
||||
{
|
||||
_maxValue = aMaxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the slider's minimum value
|
||||
@param aMinValue the new minimum value
|
||||
*/
|
||||
- (void)setMinValue:(double)aMinValue
|
||||
{
|
||||
_minValue = aMinValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the slider's value
|
||||
@param aValue the new slider value
|
||||
@deprecated Use setFloatValue, setObjectValue, etc
|
||||
*/
|
||||
- (void)setValue:(double)aValue
|
||||
{
|
||||
[self setObjectValue:aValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's value
|
||||
@deprecated Use floatValue, objectValue, etc
|
||||
*/
|
||||
- (double)value
|
||||
{
|
||||
return [self floatValue];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)anObject
|
||||
{
|
||||
[super setObjectValue:anObject];
|
||||
[self setTrackWidth:[theme valueForKey:@"track-width"]];
|
||||
[self setHorizontalTrackColor:[theme valueForKey:@"horizontal-track-color"]];
|
||||
[self setVerticalTrackColor:[theme valueForKey:@"vertical-track-color"]];
|
||||
|
||||
if (_knob)
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the knob's position
|
||||
@ignore
|
||||
*/
|
||||
- (CGPoint)knobPosition
|
||||
- (CPDictionary)themedValues
|
||||
{
|
||||
if ([self isVertical])
|
||||
return CPPointMake(0.0, 0.0);
|
||||
else
|
||||
return CPPointMake(
|
||||
(([self floatValue] - _minValue) / (_maxValue - _minValue)) * (CPRectGetWidth([self frame]) - CPRectGetWidth([_knob frame])),
|
||||
(CPRectGetHeight([self frame]) - CPRectGetHeight([_knob frame])) / 2.0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (float)valueForKnobPosition:(CGPoint)aPoint
|
||||
{
|
||||
if ([self isVertical])
|
||||
return 0.0;
|
||||
else
|
||||
return MAX(MIN((aPoint.x) * (_maxValue - _minValue) / ( CPRectGetWidth([self frame]) - CPRectGetWidth([_knob frame]) ) + _minValue, _maxValue), _minValue);
|
||||
}
|
||||
|
||||
- (CGPoint)constrainKnobPosition:(CGPoint)aPoint
|
||||
{
|
||||
//FIXME
|
||||
aPoint.x -= _knobSize.width / 2.0;
|
||||
return CPPointMake(MAX(MIN(CPRectGetWidth([self bounds]) - _knobSize.width, aPoint.x), 0.0), (CPRectGetHeight([self bounds]) - CPRectGetHeight([_knob frame])) / 2.0);
|
||||
}
|
||||
|
||||
- (BOOL)tracksMouseOutsideOfFrame
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
[[self knob] setImage:[self pushedKnobImage]];
|
||||
var values = [super themedValues];
|
||||
|
||||
[_knob setFrameOrigin:[self constrainKnobPosition:aPoint]];
|
||||
[values setObject:_knobSize forKey:@"knob-size"];
|
||||
[values setObject:_knobColor forKey:@"knob-color"];
|
||||
[values setObject:_highlightedKnobColor forKey:@"knob-color-highlighted"];
|
||||
[values setObject:_trackWidth forKey:@"track-width"];
|
||||
[values setObject:_verticalTrackColor forKey:@"vertical-track-color"];
|
||||
[values setObject:_horizontalTrackColor forKey:@"horizontal-track-color"];
|
||||
|
||||
[super setObjectValue:[self valueForKnobPosition:[_knob frame].origin]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||
{
|
||||
[_knob setFrameOrigin:[self constrainKnobPosition:aPoint]];
|
||||
|
||||
[super setObjectValue:[self valueForKnobPosition:[_knob frame].origin]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[[self knob] setImage:[self knobImage]];
|
||||
|
||||
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
|
||||
[_target sliderDidFinish:self];
|
||||
return values;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
CPSliderMaxValueKey = "CPSliderMaxValueKey",
|
||||
CPSliderAltIncrValueKey = "CPSliderAltIncrValueKey",
|
||||
CPSliderIsVerticalKey = "CPSliderIsVerticalKey";
|
||||
CPSliderAltIncrValueKey = "CPSliderAltIncrValueKey";
|
||||
|
||||
@implementation CPSlider (CPCoding)
|
||||
|
||||
/*!
|
||||
Initializes the slider from the data in a coder.
|
||||
@param aCoder the coder from which to read the data
|
||||
@return the initialized slider
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
@@ -413,32 +441,37 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
_minValue = [aCoder decodeDoubleForKey:CPSliderMinValueKey];
|
||||
_maxValue = [aCoder decodeDoubleForKey:CPSliderMaxValueKey];
|
||||
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
|
||||
_isVertical = [aCoder decodeDoubleForKey:CPSliderIsVerticalKey];
|
||||
|
||||
_bar = [self bar];
|
||||
_knob = [self knob];
|
||||
_knobSize = [[self knobImage] size];
|
||||
_isVertical = [self isVertical];
|
||||
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
|
||||
[self addSubview:_bar];
|
||||
[self addSubview:_knob];
|
||||
[self setContinuous:YES];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes out the slider's instance information to a coder.
|
||||
@param aCoder the coder to which to write the data
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var subviews = _subviews;
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
var count = [_subviews count],
|
||||
subviews = nil;
|
||||
|
||||
if (count)
|
||||
{
|
||||
subviews = _subviews;
|
||||
|
||||
if (count === 2 && _trackView && _knobView)
|
||||
_subviews = [];
|
||||
else
|
||||
{
|
||||
if (_trackView)
|
||||
[_subviews removeObjectIdenticalTo:_trackView];
|
||||
if (_knobView)
|
||||
[_subviews removeObjectIdenticalTo:_knobView];
|
||||
}
|
||||
}
|
||||
|
||||
_subviews = [];
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
_subviews = subviews;
|
||||
@@ -446,7 +479,12 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
[aCoder encodeDouble:_minValue forKey:CPSliderMinValueKey];
|
||||
[aCoder encodeDouble:_maxValue forKey:CPSliderMaxValueKey];
|
||||
[aCoder encodeDouble:_altIncrementValue forKey:CPSliderAltIncrValueKey];
|
||||
[aCoder encodeBool:_isVertical forKey:CPSliderIsVerticalKey];
|
||||
|
||||
// NO!
|
||||
/* [aCoder encodeObject:_verticalTrackColor forKey:"1"];
|
||||
[aCoder encodeObject:_horizontalTrackColor forKey:"2"];
|
||||
[aCoder encodeObject:_knobColor forKey:"3"];
|
||||
[aCoder encodeObject:_highlightedKnobColor forKey:"4"];*/
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,286 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <AppKit/_CPCibCustomResource.j>
|
||||
@import <AppKit/_CPCibKeyedUnarchiver.j>
|
||||
|
||||
|
||||
var CPThemesByName = nil,
|
||||
CPThemeDefaultTheme = nil,
|
||||
|
||||
CPThemeViewClass = Nil,
|
||||
CPThemeWindowClass = Nil;
|
||||
|
||||
@implementation CPTheme : CPObject
|
||||
{
|
||||
CPString _name;
|
||||
Class _activeClass;
|
||||
JSObject _classTable;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self !== [CPTheme class])
|
||||
return;
|
||||
|
||||
CPThemesByName = {};
|
||||
|
||||
CPThemeViewClass = [CPView class];
|
||||
CPThemeWindowClass = [CPWindow class];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
defaultThemePath = [bundle objectForInfoDictionaryKey:@"Default Themes Path"],
|
||||
defaultThemeName = [bundle objectForInfoDictionaryKey:@"Default Theme Name"];
|
||||
|
||||
if (!defaultThemePath)
|
||||
return;
|
||||
|
||||
defaultThemePath = [bundle pathForResource:defaultThemePath];
|
||||
|
||||
var file = objj_files[defaultThemePath + "/Info.plist"];
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
// Oh boy are we tricky.
|
||||
var infoDictionary = CPPropertyListCreateFromData([CPData dataWithString:objj_files[defaultThemePath + "/Info.plist"].contents]);
|
||||
|
||||
themes = [infoDictionary objectForKey:@"CPBundleReplacedFiles"],
|
||||
|
||||
themeIndex = 0,
|
||||
themeCount = [themes count];
|
||||
|
||||
for (; themeIndex < themeCount; ++themeIndex)
|
||||
{
|
||||
var unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||
initForReadingWithData:[CPData dataWithString:objj_files[defaultThemePath + '/' + themes[themeIndex]].contents]
|
||||
bundle:file.bundle];
|
||||
|
||||
[unarchiver decodeObjectForKey:@"root"];
|
||||
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
|
||||
[self setDefaultTheme:[CPTheme themeNamed:defaultThemeName]];
|
||||
}
|
||||
|
||||
+ (void)setDefaultTheme:(CPTheme)aTheme
|
||||
{
|
||||
CPThemeDefaultTheme = aTheme;
|
||||
}
|
||||
|
||||
+ (CPTheme)defaultTheme
|
||||
{
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
+ (CPTheme)themeNamed:(CPString)aName
|
||||
{
|
||||
return CPThemesByName[aName];
|
||||
}
|
||||
|
||||
+ (void)loadThemesAtURL:(CPURL)aURL delegate:(id)aLoadDelegate
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_classTable = {};
|
||||
_classTable[[[self class] className]] = {};
|
||||
|
||||
CPThemesByName[_name] = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (void)setActiveClass:(Class)aClass
|
||||
{
|
||||
_activeClass = aClass;
|
||||
}
|
||||
|
||||
- (Class)activeClass
|
||||
{
|
||||
return _activeClass;
|
||||
}
|
||||
|
||||
- (id)valueForKey:(CPString)aKey
|
||||
{
|
||||
return [self valueForKey:aKey inClass:_activeClass];
|
||||
}
|
||||
|
||||
- (id)valueForKey:(CPString)aKey inClass:(CPClass)aClass
|
||||
{
|
||||
if (!aClass)
|
||||
throw "no!";
|
||||
|
||||
var className = [aClass className],
|
||||
table = _classTable[className];
|
||||
|
||||
if (!table)
|
||||
return nil;
|
||||
|
||||
var value = table[aKey];
|
||||
|
||||
if (!value)
|
||||
return nil;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)takeThemeFromObject:(id)anObject
|
||||
{
|
||||
var values = [anObject themedValues],
|
||||
key = nil,
|
||||
keys = [values keyEnumerator],
|
||||
objectClass = [anObject class];
|
||||
|
||||
while (key = [keys nextObject])
|
||||
[self addValue:[values objectForKey:key] forKey:key inClass:objectClass];
|
||||
}
|
||||
|
||||
- (void)setDefaultValue:(id)aValue forKey:(CPString)aKey
|
||||
{
|
||||
[self addValue:aValue forKey:aKey inClass:[self class]];
|
||||
}
|
||||
|
||||
- (void)addValue:(id)aValue forKey:(CPString)aKey inClass:(Class)aClass
|
||||
{
|
||||
if (!aValue)
|
||||
return;
|
||||
|
||||
var className = [aClass className],
|
||||
table = _classTable[className];
|
||||
|
||||
if (!table)
|
||||
{
|
||||
var classNames = [];
|
||||
|
||||
while (!table && (aClass !== CPThemeViewClass) && (aClass !== CPThemeWindowClass))
|
||||
{
|
||||
classNames.push(className);
|
||||
|
||||
aClass = [aClass superclass];
|
||||
className = [aClass className];
|
||||
table = _classTable[className];
|
||||
}
|
||||
|
||||
if (!table)
|
||||
table = _classTable[[[self class] className]];
|
||||
|
||||
var count = [classNames count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
className = classNames[count];
|
||||
|
||||
_classTable[className] = {};
|
||||
_classTable[className].prototype = table;
|
||||
|
||||
table = _classTable[className];
|
||||
}
|
||||
}
|
||||
|
||||
if (table[aKey] !== aValue)
|
||||
table[aKey] = aValue;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPThemeNameKey = @"CPThemeNameKey",
|
||||
CPThemeClassNamesArrayKey = @"CPThemeClassNamesArrayKey";
|
||||
|
||||
@implementation CPTheme (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
_name = [aCoder decodeObjectForKey:CPThemeNameKey];
|
||||
_classTable = {};
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (self)
|
||||
{
|
||||
var classNamesArray = [aCoder decodeObjectForKey:CPThemeClassNamesArrayKey],
|
||||
count = classNamesArray.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var className = classNamesArray[count],
|
||||
theClass = objj_getClass(className),
|
||||
values = [aCoder decodeObjectForKey:className],
|
||||
keys = [values allKeys],
|
||||
keyCount = keys.length;
|
||||
|
||||
while (keyCount--)
|
||||
{
|
||||
var key = keys[keyCount];
|
||||
|
||||
[self addValue:[values objectForKey:key] forKey:key inClass:theClass];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var classNamesArray = [];
|
||||
|
||||
for (var className in _classTable)
|
||||
{
|
||||
if (_classTable.hasOwnProperty(className))
|
||||
{
|
||||
var values = _classTable[className],
|
||||
valuesDictionary = [CPDictionary dictionary];
|
||||
|
||||
for (var key in values)
|
||||
if (key !== "prototype" && values.hasOwnProperty(key))
|
||||
[valuesDictionary setObject:values[key] forKey:key];
|
||||
|
||||
[aCoder encodeObject:valuesDictionary forKey:className];
|
||||
|
||||
classNamesArray.push(className);
|
||||
}
|
||||
}
|
||||
|
||||
[aCoder encodeObject:_name forKey:CPThemeNameKey];
|
||||
[aCoder encodeObject:classNamesArray forKey:CPThemeClassNamesArrayKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPThemeKeyedUnarchiver : CPKeyedUnarchiver
|
||||
{
|
||||
CPBundle _bundle;
|
||||
}
|
||||
|
||||
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle
|
||||
{
|
||||
self = [super initForReadingWithData:data];
|
||||
|
||||
if (self)
|
||||
_bundle = aBundle;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPBundle)bundle
|
||||
{
|
||||
return _bundle;
|
||||
}
|
||||
|
||||
@end
|
||||
+37
-1
@@ -29,8 +29,9 @@
|
||||
@import "CPColor.j"
|
||||
@import "CPDOMDisplayServer.j"
|
||||
@import "CPGeometry.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPGraphicsContext.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPTheme.j"
|
||||
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
@@ -167,6 +168,9 @@ var DOMElementPrototype = nil,
|
||||
BOOL _isInFullScreenMode;
|
||||
|
||||
_CPViewFullScreenModeState _fullScreenModeState;
|
||||
|
||||
// Theming Support
|
||||
CPTheme _theme;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -237,6 +241,8 @@ var DOMElementPrototype = nil,
|
||||
_DOMImageParts = [];
|
||||
_DOMImageSizes = [];
|
||||
#endif
|
||||
|
||||
[self setTheme:[CPTheme defaultTheme]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -1731,6 +1737,36 @@ setBoundsOrigin:
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPView (Theming)
|
||||
|
||||
- (void)setTheme:(CPTheme)aTheme
|
||||
{
|
||||
if (_theme === aTheme)
|
||||
return;
|
||||
|
||||
_theme = aTheme;
|
||||
|
||||
[_theme setActiveClass:[self class]];
|
||||
[self viewDidChangeTheme];
|
||||
[_theme setActiveClass:Nil];
|
||||
}
|
||||
|
||||
- (CPTheme)theme
|
||||
{
|
||||
return _theme;
|
||||
}
|
||||
|
||||
- (void)viewDidChangeTheme
|
||||
{
|
||||
}
|
||||
|
||||
- (CPDictionary)themedValues
|
||||
{
|
||||
return [CPDictionary dictionary];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
CPViewAutoresizesSubviewsKey = @"CPViewAutoresizesSubviews",
|
||||
CPViewBackgroundColorKey = @"CPViewBackgroundColor",
|
||||
|
||||
@@ -28,22 +28,33 @@
|
||||
|
||||
|
||||
var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
_CPCibCustomResourceResourceNameKey = @"_CPCibCustomResourceResourceNameKey";
|
||||
_CPCibCustomResourceResourceNameKey = @"_CPCibCustomResourceResourceNameKey",
|
||||
_CPCibCustomResourcePropertiesKey = @"_CPCibCustomResourcePropertiesKey";
|
||||
|
||||
@implementation _CPCibCustomResource : CPObject
|
||||
{
|
||||
CPString _className;
|
||||
CPString _resourceName;
|
||||
CPString _className;
|
||||
CPString _resourceName;
|
||||
CPDictionary _properties;
|
||||
}
|
||||
|
||||
- (CPString)filename
|
||||
+ (id)imageResourceWithName:(CPString)aResourceName size:(CGSize)aSize
|
||||
{
|
||||
return "";
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObject:aSize forKey:@"size"]];
|
||||
}
|
||||
|
||||
- (CGSize)size
|
||||
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
|
||||
{
|
||||
return CGSizeMakeZero();
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_className = aClassName;
|
||||
_resourceName = aResourceName;
|
||||
_properties = properties;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
@@ -54,6 +65,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
{
|
||||
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
|
||||
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
|
||||
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -63,15 +75,40 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
{
|
||||
[aCoder encodeObject:_className forKey:_CPCibCustomResourceClassNameKey];
|
||||
[aCoder encodeObject:_resourceName forKey:_CPCibCustomResourceResourceNameKey];
|
||||
[aCoder encodeObject:_properties forKey:_CPCibCustomResourcePropertiesKey];
|
||||
}
|
||||
|
||||
- (id)awakeAfterUsingCoder:(CPCoder)aCoder
|
||||
{
|
||||
if ([aCoder isKindOfClass:[_CPCibKeyedUnarchiver class]])
|
||||
if ([aCoder respondsToSelector:@selector(bundle)])
|
||||
if (_className === @"CPImage")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName]];
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:[_properties objectForKey:@"size"]];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCibCustomResource (CPImage)
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return [[CPBundle mainBundle] pathForResource:_resourceName];
|
||||
}
|
||||
|
||||
- (CGSize)size
|
||||
{
|
||||
return [_properties objectForKey:@"size"];
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isNinePartImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -4,6 +4,10 @@
|
||||
<dict>
|
||||
<key>CPBundleIdentifier</key>
|
||||
<string>com.280n.AppKit</string>
|
||||
<key>Default Themes Path</key>
|
||||
<string>Default.cptheme</string>
|
||||
<key>Default Theme Name</key>
|
||||
<string>Default</string>
|
||||
<key>CPBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CPBundleName</key>
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* AppController.j
|
||||
*
|
||||
* Created by __Me__ on __Date__.
|
||||
* Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <AppKit/_CPCibCustomResource.j>
|
||||
|
||||
|
||||
@implementation AppController : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
- (CPArray)themeNames
|
||||
{
|
||||
return ["Default"];
|
||||
}
|
||||
|
||||
- (void)viewsForDefaultTheme
|
||||
{
|
||||
var views = [],
|
||||
bundle = [CPBundle mainBundle];
|
||||
|
||||
// Horizontal Slider
|
||||
|
||||
var horizontalTrackColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[_CPCibCustomResource imageResourceWithName:"horizontal-track-left.png" size:CPSizeMake(2.0, 4.0)],
|
||||
[_CPCibCustomResource imageResourceWithName:"horizontal-track-center.png" size:CPSizeMake(1.0, 4.0)],
|
||||
[_CPCibCustomResource imageResourceWithName:"horizontal-track-right.png" size:CPSizeMake(2.0, 4.0)]
|
||||
]
|
||||
isVertical:NO]];
|
||||
|
||||
var horizontalSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 24.0)];
|
||||
|
||||
[horizontalSlider setTrackWidth:4.0];
|
||||
[horizontalSlider setHorizontalTrackColor:horizontalTrackColor];
|
||||
|
||||
var knobColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"knob.png" size:CPSizeMake(11.0, 11.0)]];
|
||||
knobHighlightedColor = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"knob-highlighted.png" size:CPSizeMake(12.0, 12.0)]];
|
||||
|
||||
[horizontalSlider setKnobSize:CGSizeMake(12.0, 12.0)];
|
||||
[horizontalSlider setKnobColor:knobColor];
|
||||
[horizontalSlider setHighlightedKnobColor:knobHighlightedColor];
|
||||
|
||||
views.push(horizontalSlider);
|
||||
|
||||
// Vertical Slider
|
||||
|
||||
var verticalTrackColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[_CPCibCustomResource imageResourceWithName:"vertical-track-top.png" size:CPSizeMake(4.0, 2.0)],
|
||||
[_CPCibCustomResource imageResourceWithName:"vertical-track-center.png" size:CPSizeMake(4.0, 1.0)],
|
||||
[_CPCibCustomResource imageResourceWithName:"vertical-track-bottom.png" size:CPSizeMake(4.0, 2.0)]
|
||||
]
|
||||
isVertical:YES]];
|
||||
|
||||
var verticalSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0.0, 0.0, 24.0, 50.0)];
|
||||
|
||||
[verticalSlider setTrackWidth:4];
|
||||
[verticalSlider setVerticalTrackColor:verticalTrackColor];
|
||||
|
||||
[verticalSlider setKnobSize:CGSizeMake(12.0, 12.0)];
|
||||
[verticalSlider setKnobColor:knobColor];
|
||||
[verticalSlider setHighlightedKnobColor:knobHighlightedColor];
|
||||
|
||||
views.push(verticalSlider);
|
||||
|
||||
return views;
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
|
||||
{
|
||||
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
|
||||
contentView = [theWindow contentView],
|
||||
bounds = [contentView bounds],
|
||||
themeNames = [self themeNames],
|
||||
index = 0,
|
||||
count = themeNames.length;
|
||||
|
||||
var tabView = [[CPTabView alloc] initWithFrame:bounds];
|
||||
|
||||
[tabView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[contentView addSubview:tabView];
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = [[CPTabViewItem alloc] initWithIdentifier:themeNames[index]],
|
||||
selectorName = "viewsFor" + themeNames[index] + "Theme",
|
||||
views = [self performSelector:selectorName],
|
||||
viewsCount = [views count],
|
||||
itemSize = CGSizeMake(0.0, 0.0);
|
||||
|
||||
while (viewsCount--)
|
||||
{
|
||||
var size = [views[viewsCount] frame].size;
|
||||
|
||||
if (size.width > itemSize.width)
|
||||
itemSize.width = size.width;
|
||||
|
||||
if (size.height > itemSize.height)
|
||||
itemSize.height = size.height;
|
||||
}
|
||||
|
||||
itemSize.height += 30;
|
||||
itemSize.width += 40;
|
||||
|
||||
var collectionView = [[CPCollectionView alloc] initWithFrame:CGRectMakeZero()],
|
||||
collectionViewItem = [[CPCollectionViewItem alloc] init];
|
||||
|
||||
[collectionViewItem setView:[[ThemedView alloc] init]];
|
||||
|
||||
[collectionView setItemPrototype:collectionViewItem];
|
||||
[collectionView setMinItemSize:itemSize];
|
||||
[collectionView setMaxItemSize:itemSize];
|
||||
[collectionView setVerticalMargin:5.0];
|
||||
[collectionView setContent:views];
|
||||
|
||||
[item setLabel:themeNames[index]];
|
||||
[item setView:collectionView];
|
||||
|
||||
[tabView addTabViewItem:item];
|
||||
}
|
||||
|
||||
[theWindow orderFront:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ThemedView : CPView
|
||||
{
|
||||
CPView _view;
|
||||
CPTextField _label;
|
||||
}
|
||||
|
||||
- (void)setRepresentedObject:(id)anObject
|
||||
{
|
||||
if (!_label)
|
||||
{
|
||||
_label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_label setAlignment:CPCenterTextAlignment];
|
||||
[_label setAutoresizingMask:CPViewMinYMargin | CPViewWidthSizable];
|
||||
[_label setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||
|
||||
[self addSubview:_label];
|
||||
}
|
||||
|
||||
[_label setStringValue:[anObject className]];
|
||||
[_label sizeToFit];
|
||||
|
||||
[_label setFrame:CGRectMake(0.0, CGRectGetHeight([self bounds]) - CGRectGetHeight([_label frame]),
|
||||
CGRectGetWidth([self bounds]), CGRectGetHeight([_label frame]))];
|
||||
|
||||
if (_view)
|
||||
[_view removeFromSuperview];
|
||||
|
||||
_view = anObject;
|
||||
|
||||
[_view setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
|
||||
[_view setFrameOrigin:CGPointMake((CGRectGetWidth([self bounds]) - CGRectGetWidth([_view frame])) / 2.0, (CGRectGetMinY([_label frame]) - CGRectGetHeight([_view frame])) / 2.0)];
|
||||
|
||||
[self addSubview:_view];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Default</string>
|
||||
<key>Targets</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Default.cptheme</string>
|
||||
<key>Type</key>
|
||||
<string>280N.theme</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>Configurations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Debug</string>
|
||||
<key>Flags</key>
|
||||
<string>-DDEBUG -g</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Release</string>
|
||||
<key>Flags</key>
|
||||
<string>-O</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
+1
@@ -0,0 +1 @@
|
||||
/Users/tolmasky/Development/Build/Release/AppKit
|
||||
@@ -0,0 +1 @@
|
||||
/Users/tolmasky/Development/Build/Debug/AppKit
|
||||
@@ -0,0 +1 @@
|
||||
/Users/tolmasky/Development/Build/Debug/Foundation
|
||||
@@ -0,0 +1 @@
|
||||
/Users/tolmasky/Development/Build/Debug/Objective-J
|
||||
@@ -0,0 +1 @@
|
||||
/Users/tolmasky/Development/Build/Release/Foundation
|
||||
@@ -0,0 +1 @@
|
||||
/Users/tolmasky/Development/Build/Release/Objective-J
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CPApplicationDelegateClass</key>
|
||||
<string>AppController</string>
|
||||
<key>CPBundleName</key>
|
||||
<string>Hello World</string>
|
||||
<key>CPPrincipalClass</key>
|
||||
<string>CPApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
|
||||
<!--
|
||||
//
|
||||
// index-debug.html
|
||||
//
|
||||
// Created by __Me__ on __Date__.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
-->
|
||||
<head>
|
||||
|
||||
<title>Hello World</title>
|
||||
|
||||
<script type = "text/javascript">
|
||||
OBJJ_MAIN_FILE = "main.j";
|
||||
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks", "SomethingElse"];
|
||||
</script>
|
||||
|
||||
<script src = "Frameworks/Debug/Objective-J/Objective-J.js" type = "text/javascript"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="position: absolute; left: 50%; top: 50%;">
|
||||
<center>
|
||||
<img src = "Frameworks/AppKit/Resources/CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif" style="left: -32px; position: relative; top: -32px;" />
|
||||
</center>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
|
||||
<!--
|
||||
//
|
||||
// index.html
|
||||
//
|
||||
// Created by __Me__ on __Date__.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
-->
|
||||
<head>
|
||||
|
||||
<title>Hello World</title>
|
||||
|
||||
<script type = "text/javascript">
|
||||
OBJJ_MAIN_FILE = "main.j";
|
||||
</script>
|
||||
|
||||
<script src = "Frameworks/Objective-J/Objective-J.js" type = "text/javascript"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="position: absolute; left: 50%; top: 50%;">
|
||||
<center>
|
||||
<img src = "Frameworks/AppKit/Resources/CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif" style="left: -32px; position: relative; top: -32px;" />
|
||||
</center>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* main.j
|
||||
*
|
||||
* Created by __Me__ on __Date__.
|
||||
* Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
*/
|
||||
|
||||
@import <Foundation/Foundation.j>
|
||||
@import <AppKit/AppKit.j>
|
||||
|
||||
@import "AppController.j"
|
||||
|
||||
|
||||
function main(args, namedArgs)
|
||||
{
|
||||
CPApplicationMain(args, namedArgs);
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
<import file = "../common.xml" />
|
||||
<import file = "${env.OBJJ_LIB}/steam.xml" />
|
||||
|
||||
<property name = "Theme" value = "Default" />
|
||||
|
||||
<target name = "clean" depends = "steam-uptodate">
|
||||
|
||||
@@ -26,6 +28,16 @@
|
||||
<arg line = "-f AppKit.steam -c ${Configuration} -t AppKit-Rhino" />
|
||||
</steam-build>
|
||||
|
||||
<steam-build>
|
||||
<arg line = "-f Themes/${Theme}/${Theme}.steam -c ${Configuration} -t ${Theme}.cptheme" />
|
||||
</steam-build>
|
||||
|
||||
<copy todir = "${Build}/${Configuration}/AppKit/Resources/${Theme}.cptheme" >
|
||||
<fileset dir = "${Build}/${Configuration}/${Theme}.cptheme" />
|
||||
</copy>
|
||||
|
||||
<steam-inline-bundle bundle = "${Build}/${Configuration}/AppKit" />
|
||||
|
||||
<copy file = "../LICENSE" todir = "${Build}/${Configuration}/AppKit" />
|
||||
|
||||
</target>
|
||||
|
||||
@@ -66,6 +66,12 @@ function objj_context()
|
||||
#define IS_FILE(aFragment) (aFragment.type & FRAGMENT_FILE)
|
||||
#define IS_LOCAL(aFragment) (aFragment.type & FRAGMENT_LOCAL)
|
||||
|
||||
objj_fragment.prototype.toMarkedString = function()
|
||||
{
|
||||
return IS_FILE(this) ? (IS_LOCAL(this) ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ';' + GET_PATH(this).length + ';' + GET_PATH(this) :
|
||||
MARKER_CODE + ';' + GET_CODE(this).length + ';' + GET_CODE(this);
|
||||
}
|
||||
|
||||
function fragment_create_code(aCode, aBundle, aFile)
|
||||
{
|
||||
var fragment = new objj_fragment();
|
||||
|
||||
+27
-1
@@ -545,6 +545,8 @@ OBJJUnrecognizedFormatException = "OBJJUnrecognizedFormatException";
|
||||
var STATIC_MAGIC_NUMBER = "@STATIC",
|
||||
MARKER_PATH = "p",
|
||||
MARKER_CODE = "c",
|
||||
MARKER_BUNDLE = "b",
|
||||
MARKER_TEXT = "t",
|
||||
MARKER_IMPORT_STD = 'I',
|
||||
MARKER_IMPORT_LOCAL = 'i';
|
||||
|
||||
@@ -569,7 +571,10 @@ function objj_decompile(aString, bundle)
|
||||
|
||||
switch (marker)
|
||||
{
|
||||
case MARKER_PATH: file = new objj_file();
|
||||
case MARKER_PATH: if (file && file.contents && file.path === file.bundle.path)
|
||||
file.bundle.info = CPPropertyListCreateWithData({string:file.contents});
|
||||
|
||||
file = new objj_file();
|
||||
file.path = DIRECTORY(bundle.path) + text;
|
||||
file.bundle = bundle;
|
||||
file.fragments = [];
|
||||
@@ -579,6 +584,24 @@ function objj_decompile(aString, bundle)
|
||||
objj_files[file.path] = file;
|
||||
|
||||
break;
|
||||
|
||||
case MARKER_BUNDLE: var bundlePath = DIRECTORY(bundle.path) + '/' + text;
|
||||
|
||||
file.bundle = objj_getBundleWithPath(bundlePath);
|
||||
|
||||
if (!file.bundle)
|
||||
{
|
||||
file.bundle = new objj_bundle();
|
||||
file.bundle.path = bundlePath;
|
||||
|
||||
objj_setBundleForPath(file.bundle, bundlePath);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MARKER_TEXT: file.contents = text;
|
||||
break;
|
||||
|
||||
case MARKER_CODE: file.fragments.push(fragment_create_code(text, bundle, file));
|
||||
break;
|
||||
case MARKER_IMPORT_STD: file.fragments.push(fragment_create_file(text, bundle, NO, file));
|
||||
@@ -588,5 +611,8 @@ function objj_decompile(aString, bundle)
|
||||
}
|
||||
}
|
||||
|
||||
if (file && file.contents && file.path === file.bundle.path)
|
||||
file.bundle.info = CPPropertyListCreateWithData({string:file.contents});
|
||||
|
||||
return files;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
|
||||
function readContentsOfFile(/*File*/ aFile)
|
||||
{
|
||||
var reader = new BufferedReader(new FileReader(aFile)),
|
||||
fileContents = "";
|
||||
|
||||
// Get contents of the file
|
||||
while (reader.ready())
|
||||
fileContents += reader.readLine() + '\n';
|
||||
|
||||
reader.close();
|
||||
|
||||
return fileContents;
|
||||
}
|
||||
|
||||
function writeContentsToFile(/*String*/ contents, /*File*/ aFile)
|
||||
{
|
||||
var writer = new BufferedWriter(new FileWriter(aFile));
|
||||
|
||||
writer.write(contents);
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
function readPlist(/*File*/ aFile)
|
||||
{
|
||||
var fileContents = readFile(aFile);
|
||||
|
||||
var data = new objj_data();
|
||||
data.string = fileContents;
|
||||
|
||||
return new CPPropertyListCreateFromData(data);
|
||||
}
|
||||
|
||||
function readBundle(/*File*/ aFile, /*Boolean*/ shouldDecompile)
|
||||
{
|
||||
var bundlePath = typeof aFile === "string" ? new File(aFile).getCanonicalPath() : aFile.getCanonicalPath(),
|
||||
infoPath = bundlePath + "/Info.plist";
|
||||
|
||||
//err
|
||||
var bundle = new objj_bundle();
|
||||
|
||||
bundle.path = infoPath;
|
||||
bundle.info = readPlist(infoPath);
|
||||
bundle._staticFilePaths = dictionary_getValue(bundle.info, "CPBundleReplacedFiles");
|
||||
|
||||
if (bundle._staticFilePaths.length)
|
||||
{
|
||||
bundle._staticContentPath = staticContentPath = bundlePath + '/' + dictionary_getValue(bundle.info, "CPBundleExecutable");
|
||||
|
||||
//err
|
||||
|
||||
bundle._staticContent = readFile(staticContentPath);
|
||||
|
||||
if (shouldDecompile)
|
||||
bundle.files = objj_decompile(bundle._staticContent, bundle);
|
||||
}
|
||||
else
|
||||
bundle._staticContent = "";
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
function importFiles(files, aCallback)
|
||||
{
|
||||
|
||||
if (files.length === 0)
|
||||
aCallback();
|
||||
else
|
||||
{
|
||||
var file = files.shift();
|
||||
|
||||
if (typeof file === "string")
|
||||
file = new File(file);
|
||||
|
||||
objj_import(file.getCanonicalPath(), YES, function() { importFiles(files, aCallback) });
|
||||
}
|
||||
return;
|
||||
|
||||
var context = new objj_context();
|
||||
|
||||
if (aCallback)
|
||||
context.didCompleteCallback = aCallback;
|
||||
|
||||
var count = files.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var file = files[count];
|
||||
|
||||
if (typeof file === "string")
|
||||
file = new File(file);
|
||||
|
||||
context.pushFragment(fragment_create_file(file, new objj_bundle(""), YES, NULL));
|
||||
}
|
||||
|
||||
context.evaluate();
|
||||
}
|
||||
|
||||
function loadFrameworks(frameworkPaths, aCallback)
|
||||
{
|
||||
if (frameworkPaths.length === 0)
|
||||
return aCallback();
|
||||
|
||||
var frameworkPath = frameworkPaths.shift(),
|
||||
|
||||
infoPlist = new File(frameworkPath + "/Info.plist");
|
||||
|
||||
if (!infoPlist.exists())
|
||||
{
|
||||
java.lang.System.out.println("'" + frameworkPath + "' is not a framework or could not be found.");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
var infoDictionary = readPlist(new File(frameworkPath + "/Info.plist"));
|
||||
|
||||
if (dictionary_getValue(infoDictionary, "CPBundlePackageType") !== "FMWK")
|
||||
{
|
||||
java.lang.System.out.println("'" + frameworkPath + "' is not a framework .");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
var files = dictionary_getValue(infoDictionary, "CPBundleReplacedFiles"),
|
||||
index = 0,
|
||||
count = files.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
files[index] = String(frameworkPath + '/' + files[index]);
|
||||
|
||||
importFiles(files, function() { loadFrameworks(frameworkPaths, aCallback) });
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
|
||||
function readFile(/*File*/ aFile)
|
||||
{
|
||||
var reader = new BufferedReader(new FileReader(aFile)),
|
||||
fileContents = "";
|
||||
|
||||
// Get contents of the file
|
||||
while (reader.ready())
|
||||
fileContents += reader.readLine() + '\n';
|
||||
|
||||
reader.close();
|
||||
|
||||
return fileContents;
|
||||
}
|
||||
|
||||
function writeContentsToFile(/*String*/ contents, /*File*/ aFile)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function readPlist(/*File*/ aFile)
|
||||
{
|
||||
var fileContents = readFile(aFile);
|
||||
|
||||
var data = new objj_data();
|
||||
data.string = fileContents;
|
||||
|
||||
return new CPPropertyListCreateFromData(data);
|
||||
}
|
||||
|
||||
function importFiles(files, aCallback)
|
||||
{
|
||||
|
||||
if (files.length === 0)
|
||||
aCallback();
|
||||
else
|
||||
{
|
||||
var file = files.shift();
|
||||
|
||||
if (typeof file === "string")
|
||||
file = new File(file);
|
||||
|
||||
objj_import(file.getCanonicalPath(), YES, function() { importFiles(files, aCallback) });
|
||||
}
|
||||
return;
|
||||
|
||||
var context = new objj_context();
|
||||
|
||||
if (aCallback)
|
||||
context.didCompleteCallback = aCallback;
|
||||
|
||||
var count = files.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var file = files[count];
|
||||
|
||||
if (typeof file === "string")
|
||||
file = new File(file);
|
||||
|
||||
context.pushFragment(fragment_create_file(file, new objj_bundle(""), YES, NULL));
|
||||
}
|
||||
|
||||
context.evaluate();
|
||||
}
|
||||
|
||||
function loadFrameworks(frameworkPaths, aCallback)
|
||||
{
|
||||
if (frameworkPaths.length === 0)
|
||||
return aCallback();
|
||||
|
||||
var frameworkPath = frameworkPaths.shift(),
|
||||
|
||||
infoPlist = new File(frameworkPath + "/Info.plist");
|
||||
|
||||
if (!infoPlist.exists())
|
||||
{
|
||||
java.lang.System.out.println("'" + frameworkPath + "' is not a framework or could not be found.");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
var infoDictionary = readPlist(new File(frameworkPath + "/Info.plist"));
|
||||
|
||||
if (dictionary_getValue(infoDictionary, "CPBundlePackageType") !== "FMWK")
|
||||
{
|
||||
java.lang.System.out.println("'" + frameworkPath + "' is not a framework .");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
var files = dictionary_getValue(infoDictionary, "CPBundleReplacedFiles"),
|
||||
index = 0,
|
||||
count = files.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
files[index] = String(frameworkPath + '/' + files[index]);
|
||||
|
||||
importFiles(files, function() { loadFrameworks(frameworkPaths, aCallback) });
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
|
||||
importClass(java.io.FileOutputStream);
|
||||
importClass(java.io.BufferedWriter);
|
||||
importClass(java.io.OutputStreamWriter);
|
||||
|
||||
function Target(dictionary)
|
||||
{
|
||||
this._name = dictionary_getValue(dictionary, "Name");
|
||||
|
||||
var flagsString = dictionary_getValue(dictionary, "Flags");
|
||||
|
||||
this._flags = flagsString ? flagsString.split(/\s+/) : [];
|
||||
|
||||
this._type = dictionary_getValue(dictionary, "Type");
|
||||
|
||||
if (!this._type)
|
||||
this._type = "280N.application";
|
||||
|
||||
this._exclusions = [];
|
||||
|
||||
var exclusions = dictionary_getValue(dictionary, "Excluded");
|
||||
|
||||
if (exclusions)
|
||||
{
|
||||
var index = 0,
|
||||
count = exclusions.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var file = new File(exclusions[index]).getCanonicalFile();
|
||||
|
||||
if (file.isDirectory())
|
||||
{
|
||||
var files = getFiles(file);
|
||||
|
||||
if (files.length)
|
||||
this._exclusions = this._exclusions.concat(files);
|
||||
}
|
||||
else
|
||||
this._exclusions.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Target.prototype.name = function()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
Target.prototype.exclusions = function()
|
||||
{
|
||||
return this._exclusions;
|
||||
}
|
||||
|
||||
Target.prototype.flags = function()
|
||||
{
|
||||
return this._flags;
|
||||
}
|
||||
|
||||
Target.prototype.type = function()
|
||||
{
|
||||
return this._type;
|
||||
}
|
||||
|
||||
function Configuration(dictionary)
|
||||
{
|
||||
this._name = dictionary_getValue(dictionary, "Name");
|
||||
|
||||
var flagsString = dictionary_getValue(dictionary, "Flags");
|
||||
|
||||
this._flags = flagsString ? flagsString.split(/\s+/) : [];
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Configuration.prototype.name = function()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
Configuration.prototype.flags = function()
|
||||
{
|
||||
return this._flags;
|
||||
}
|
||||
|
||||
function Project(/*String*/ aFilePath, /*String*/ aBuildPath)
|
||||
{
|
||||
this._file = new File(aFilePath).getCanonicalFile();
|
||||
this._root = this._file.getParentFile();
|
||||
|
||||
// Read the project file (its just a plist).
|
||||
this._properties = readPlist(this._file);
|
||||
|
||||
this._name = dictionary_getValue(this._properties, "Name");
|
||||
|
||||
// Read existing Info.plist if it exists.
|
||||
var infoPlist = new File(this._root.getAbsolutePath() + "/Info.plist");
|
||||
|
||||
if (infoPlist.exists())
|
||||
this._infoDictionary = readPlist(new File(this._root.getAbsolutePath() + "/Info.plist"));
|
||||
else
|
||||
this._infoDictionary = new objj_dictionary();
|
||||
|
||||
this.buildPath = aBuildPath;
|
||||
|
||||
// Covert target dictionaries to target objects.
|
||||
var targetDictionaries = dictionary_getValue(this._properties, "Targets");
|
||||
|
||||
this._targets = [];
|
||||
|
||||
for (index = 0, count = targetDictionaries.length; index < count; ++index)
|
||||
this._targets.push(new Target(targetDictionaries[index]));
|
||||
|
||||
this.setActiveTarget(this._targets[0]);
|
||||
|
||||
// Covert target dictionaries to target objects.
|
||||
var configurationDictionaries = dictionary_getValue(this._properties, "Configurations");
|
||||
|
||||
this._configurations = [];
|
||||
|
||||
for (index = 0, count = configurationDictionaries.length; index < count; ++index)
|
||||
this._configurations.push(new Configuration(configurationDictionaries[index]));
|
||||
|
||||
this.setActiveConfiguration(this._configurations[0]);
|
||||
|
||||
// Grab the Resources Directory (if it exists)
|
||||
this._resources = new File(this._root.getAbsolutePath() + "/Resources/").getCanonicalFile();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Project.prototype.name = function()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
Project.prototype.targetWithName = function(/*String*/ aName)
|
||||
{
|
||||
var targets = this._targets,
|
||||
index = 0,
|
||||
count = targets.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var target = targets[index];
|
||||
|
||||
if (target.name() == aName)
|
||||
return target;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Project.prototype.configurationWithName = function(/*String*/ aName)
|
||||
{
|
||||
var configurations = this._configurations,
|
||||
index = 0,
|
||||
count = configurations.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var configuration = configurations[index];
|
||||
|
||||
if (configuration.name() == aName)
|
||||
return configuration;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Project.prototype.setActiveTarget = function(/*Target*/ aTarget)
|
||||
{
|
||||
this._activeTarget = aTarget;
|
||||
|
||||
this._buildProducts = null;
|
||||
this._buildIntermediates = null;
|
||||
this._buildObjects = null;
|
||||
}
|
||||
|
||||
Project.prototype.activeTarget = function()
|
||||
{
|
||||
return this._activeTarget;
|
||||
}
|
||||
|
||||
Project.prototype.setActiveConfiguration = function(/*Configuration*/ aConfiguration)
|
||||
{
|
||||
this._activeConfiguration = aConfiguration;
|
||||
|
||||
this._buildProducts = null;
|
||||
this._buildIntermediates = null;
|
||||
this._buildObjects = null;
|
||||
}
|
||||
|
||||
Project.prototype.activeConfiguration = function()
|
||||
{
|
||||
return this._activeConfiguration;
|
||||
}
|
||||
|
||||
Project.prototype.buildProducts = function()
|
||||
{
|
||||
if (!this._buildProducts)
|
||||
{
|
||||
this._buildProducts = new File(this.buildPath + '/' + this._activeConfiguration.name() + '/' + this._activeTarget.name()).getCanonicalFile();
|
||||
this._buildProducts.mkdirs();
|
||||
}
|
||||
|
||||
return this._buildProducts;
|
||||
}
|
||||
|
||||
Project.prototype.buildIntermediates = function()
|
||||
{
|
||||
if (!this._buildIntermediates)
|
||||
{
|
||||
this._buildIntermediates = new File(this.buildPath + '/' + this._activeTarget.name() + ".build/" + this._activeConfiguration.name()).getCanonicalFile();
|
||||
this._buildIntermediates.mkdirs();
|
||||
}
|
||||
|
||||
return this._buildIntermediates;
|
||||
}
|
||||
|
||||
Project.prototype.buildObjects = function()
|
||||
{
|
||||
if (!this._buildObjects)
|
||||
{
|
||||
this._buildObjects = new File(this.buildIntermediates().getAbsolutePath() + '/' + this._activeTarget.name()).getCanonicalFile();
|
||||
this._buildObjects.mkdirs();
|
||||
}
|
||||
|
||||
return this._buildObjects;
|
||||
}
|
||||
|
||||
Project.prototype.activeFlags = function()
|
||||
{
|
||||
return this.activeTarget().flags().concat(this.activeConfiguration().flags());
|
||||
}
|
||||
|
||||
Project.prototype.buildTheme = function()
|
||||
{
|
||||
var project = this;
|
||||
|
||||
// FIXME: This should be stubbed out. It is also in objj.js
|
||||
var OBJJ_LIB = OBJJ_HOME + "/lib/";
|
||||
|
||||
var defaultFrameworks = OBJJ_LIB + "/Frameworks-Rhino";
|
||||
|
||||
OBJJ_INCLUDE_PATHS = [defaultFrameworks];
|
||||
|
||||
var OBJJ_INCLUDE_PATHS_STRING = getenv("OBJJ_INCLUDE_PATHS");
|
||||
|
||||
if (OBJJ_INCLUDE_PATHS_STRING)
|
||||
{
|
||||
OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS_STRING.split(":");
|
||||
OBJJ_INCLUDE_PATHS.push(defaultFrameworks);
|
||||
}
|
||||
|
||||
// Load ALL of Foundation and AppKit, be nice to people.
|
||||
loadFrameworks([OBJJ_LIB + "/Frameworks-Rhino/Foundation", OBJJ_LIB + "/Frameworks-Rhino/AppKit"], function()
|
||||
{
|
||||
// Get .j files
|
||||
var jFiles = getFiles(project._root, "j", project.activeTarget().exclusions().concat("Frameworks/"));
|
||||
|
||||
// Load 'em
|
||||
importFiles(jFiles, function()
|
||||
{
|
||||
// Grab the application delegate.
|
||||
var applicationDelegateClassName = dictionary_getValue(project._infoDictionary, "CPApplicationDelegateClass"),
|
||||
applicationDelegate = objj_msgSend(objj_msgSend(objj_getClass(applicationDelegateClassName), "alloc"), "init"),
|
||||
|
||||
// Grab all the themes we plan to make.
|
||||
themeNames = objj_msgSend(applicationDelegate, "themeNames"),
|
||||
|
||||
themeIndex = 0,
|
||||
themeCount = themeNames.length,
|
||||
|
||||
replacedFiles = [],
|
||||
|
||||
staticContent = "";
|
||||
|
||||
for (; themeIndex < themeCount; ++themeIndex)
|
||||
{
|
||||
themeName = themeNames[themeIndex];
|
||||
|
||||
java.lang.System.out.println("Building " + themeName + " Theme.");
|
||||
|
||||
var views = objj_msgSend(applicationDelegate, "viewsFor" + themeName + "Theme"),
|
||||
viewIndex = 0,
|
||||
viewCount = views.length,
|
||||
theme = objj_msgSend(objj_msgSend(CPTheme, "alloc"), "initWithName:", themeName);
|
||||
|
||||
if (!viewCount)
|
||||
java.lang.System.out.println("There are no themed views in the " + themeName + " Theme.");
|
||||
|
||||
// Loop through each "themed" view, and take it's themed properties.
|
||||
for (; viewIndex < viewCount; ++viewIndex)
|
||||
{
|
||||
var view = views[viewIndex];
|
||||
|
||||
java.lang.System.out.println(" Recording theme for " + objj_msgSend(views[viewIndex], "className") + ".");
|
||||
|
||||
objj_msgSend(theme, "takeThemeFromObject:", view);
|
||||
}
|
||||
|
||||
// Archive our theme.
|
||||
var filePath = themeName + ".keyedtheme";
|
||||
fileContents = objj_msgSend(objj_msgSend(CPKeyedArchiver, "archivedDataWithRootObject:", theme), "string");
|
||||
|
||||
replacedFiles.push(filePath);
|
||||
|
||||
staticContent += MARKER_PATH + ';' + filePath.length + ';' + filePath + MARKER_TEXT + ';' + fileContents.length + ';' + fileContents;
|
||||
}
|
||||
|
||||
staticContent = "@STATIC;1.0;" + staticContent;
|
||||
|
||||
var staticContentName = getFileNameWithoutExtension(project.activeTarget().name());
|
||||
|
||||
dictionary_setValue(project._infoDictionary, "CPBundleReplacedFiles", replacedFiles);
|
||||
dictionary_setValue(project._infoDictionary, "CPBundleExecutable", staticContentName);
|
||||
|
||||
var writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(project.buildProducts().getCanonicalPath() + "/Info.plist"), "UTF-8"));
|
||||
|
||||
writer.write(CPPropertyListCreate280NorthData(project._infoDictionary).string);
|
||||
|
||||
writer.close();
|
||||
|
||||
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(project.buildProducts().getCanonicalPath() + "/" + staticContentName), "UTF-8"));
|
||||
|
||||
writer.write(staticContent);
|
||||
|
||||
writer.close();
|
||||
});
|
||||
});
|
||||
|
||||
serviceTimeouts();
|
||||
|
||||
this.copyResources();
|
||||
}
|
||||
|
||||
Project.prototype.build = function()
|
||||
{
|
||||
java.lang.System.out.println("Building Target \"" + this.activeTarget().name() +
|
||||
"\" of Project \"" + this.name() +
|
||||
"\" with Configuration \"" + this.activeConfiguration().name() + "\".");
|
||||
|
||||
if (this.activeTarget().type() === "280N.theme")
|
||||
return this.buildTheme();
|
||||
|
||||
var jFiles = getFiles(this._root, "j", this._activeTarget.exclusions()),
|
||||
replacedFiles = [];
|
||||
hasModifiedJFiles = false;
|
||||
shouldObjjPreprocess = true,
|
||||
shouldGzip = this._gzip,
|
||||
objjcComponents = ["sh", OBJJ_HOME + "/bin/objjc"];
|
||||
|
||||
objjcComponents = objjcComponents.concat(this.activeFlags());
|
||||
|
||||
if (!shouldObjjPreprocess)
|
||||
objjcComponents.push("-E");
|
||||
|
||||
var buildObjects = this.buildObjects(),
|
||||
buildProducts = this.buildProducts();
|
||||
|
||||
for (index = 0, count = jFiles.length; index < count; ++index)
|
||||
{
|
||||
var file = jFiles[index],
|
||||
builtFile = new File(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o');
|
||||
|
||||
replacedFiles.push(file.getName() + "");
|
||||
|
||||
if (builtFile.exists() && file.lastModified() < builtFile.lastModified())
|
||||
continue;
|
||||
else
|
||||
hasModifiedJFiles = true;
|
||||
|
||||
objjcComponents.push(file.getAbsolutePath());
|
||||
|
||||
objjcComponents.push("-o");
|
||||
objjcComponents.push(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o');
|
||||
}
|
||||
|
||||
exec(objjcComponents, true);
|
||||
|
||||
var oFiles = getFiles(buildObjects, 'o'),
|
||||
sjFile = new File(buildProducts.getCanonicalPath() + '/' + this._activeTarget.name() + ".sj");
|
||||
|
||||
if (hasModifiedJFiles)
|
||||
{
|
||||
// concatenate sjheader.txt and individual .o
|
||||
exec(["sh", "-c", "cat '" + OBJJ_HOME + "/lib/sjheader.txt' '" + oFiles.join("' '") + "' > '" + sjFile.getCanonicalPath() + "'"], true);
|
||||
}
|
||||
|
||||
if (shouldGzip)
|
||||
{
|
||||
// gzip and copy .htaccess file
|
||||
exec(["sh", "-c", "gzip -c '" + sjFile.getCanonicalPath() + "' > '" + sjFile.getCanonicalPath() + ".gz'"], true);
|
||||
exec(["cp", OBJJ_HOME + "/lib/htaccess", sjFile.getParentFile().getCanonicalPath() + "/.htaccess"], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove gzip and .htaccess file if present
|
||||
exec(["rm", "-f", sjFile.getParentFile().getCanonicalPath() + "/.htaccess", sjFile.getCanonicalPath() + ".gz"], true);
|
||||
}
|
||||
|
||||
dictionary_setValue(this._infoDictionary, "CPBundleExecutable", this._activeTarget.name() + ".sj");
|
||||
dictionary_setValue(this._infoDictionary, "CPBundleReplacedFiles", replacedFiles);
|
||||
|
||||
this.writeInfoPlist();
|
||||
|
||||
this.copyResources();
|
||||
|
||||
// FIXME: This should be, if this is an app...
|
||||
if (dictionary_getValue(this._infoDictionary, "CPBundlePackageType") == "280N")
|
||||
this.copyIndexFile();
|
||||
|
||||
}
|
||||
|
||||
Project.prototype.clean = function()
|
||||
{
|
||||
java.lang.System.out.println("Cleaning Target \"" + this.activeTarget().name() +
|
||||
"\" of Project \"" + this.name() +
|
||||
"\" with Configuration \"" + this.activeConfiguration().name() + "\".");
|
||||
|
||||
exec(["rm", "-rf", this.buildIntermediates().getAbsolutePath()], true);
|
||||
exec(["rm", "-rf", this.buildProducts().getAbsolutePath()], true);
|
||||
}
|
||||
|
||||
Project.prototype.copyIndexFile = function()
|
||||
{
|
||||
var indexFile = new File(this._root.getAbsolutePath() + "/index.html").getCanonicalFile();
|
||||
|
||||
rsync(indexFile, this.buildProducts());
|
||||
}
|
||||
|
||||
Project.prototype.writeInfoPlist = function()
|
||||
{
|
||||
var writer = new BufferedWriter(new FileWriter(this.buildProducts().getAbsolutePath() + '/' + "Info.plist"));
|
||||
|
||||
writer.write(CPPropertyListCreateXMLData(this._infoDictionary).string);
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
Project.prototype.copyResources = function()
|
||||
{
|
||||
rsync(this._resources, this.buildProducts());
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
function build()
|
||||
{
|
||||
var index = 0,
|
||||
count = arguments.length,
|
||||
|
||||
actions = [],
|
||||
|
||||
targetName = null,
|
||||
configurationName = null,
|
||||
|
||||
buildPath = null,
|
||||
projectFilePath = null,
|
||||
|
||||
gzip = false;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
switch (arguments[index])
|
||||
{
|
||||
case "-f": if (index + 1 == count)
|
||||
throw "-f needs project file.";
|
||||
|
||||
projectFilePath = arguments[++index];
|
||||
break;
|
||||
|
||||
case "-t": if (index + 1 == count)
|
||||
throw "-t needs a target";
|
||||
|
||||
targetName = arguments[++index];
|
||||
break;
|
||||
|
||||
case "-c": if (index + 1 == count)
|
||||
throw "-c needs configuration";
|
||||
|
||||
configurationName = arguments[++index];
|
||||
break;
|
||||
|
||||
case "-b": if (index + 1 == count)
|
||||
throw "-b needs a build location";
|
||||
|
||||
buildPath = arguments[++index];
|
||||
break;
|
||||
|
||||
case "--gzip": gzip = true;
|
||||
break;
|
||||
|
||||
case "clean":
|
||||
case "build": actions.push(arguments[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no project file was specified, look for one.
|
||||
if (!projectFilePath)
|
||||
{
|
||||
var candidates = getFiles(new File('.'), "steam");
|
||||
|
||||
if (candidates.length < 1)
|
||||
throw "No project file specified or found.";
|
||||
|
||||
projectFilePath = candidates[0];
|
||||
}
|
||||
|
||||
// Construct the Build Directory
|
||||
if (!buildPath)
|
||||
{
|
||||
buildPath = System.getenv("STEAM_BUILD");
|
||||
|
||||
if (!buildPath)
|
||||
buildPath = "Build";
|
||||
}
|
||||
|
||||
var project = new Project(projectFilePath, buildPath);
|
||||
|
||||
project._gzip = gzip;
|
||||
|
||||
if (targetName)
|
||||
{
|
||||
var target = project.targetWithName(targetName);
|
||||
|
||||
if (!target)
|
||||
throw "Target \"" + targetName + "\" not found in project.";
|
||||
|
||||
project.setActiveTarget(target);
|
||||
}
|
||||
|
||||
if (configurationName)
|
||||
{
|
||||
var configuration = project.configurationWithName(configurationName);
|
||||
|
||||
if (!configuration)
|
||||
throw "Configuration \"" + configurationName + "\" not found in project.";
|
||||
|
||||
project.setActiveConfiguration(configuration);
|
||||
}
|
||||
|
||||
if (!actions.length)
|
||||
actions.push("build");
|
||||
|
||||
for (index = 0, count = actions.length; index < count; ++index)
|
||||
project[actions[index]]();
|
||||
}
|
||||
@@ -24,20 +24,22 @@
|
||||
|
||||
<copy file = "${basedir}/htaccess" tofile = "${Build.steam.lib}/htaccess" />
|
||||
|
||||
<concat destfile = "${Build.Intermediate}/steam.js">
|
||||
<preprocess file = "${basedir}/main.js" output = "${Build.Intermediate}/steam-preprocessed.js" />
|
||||
|
||||
<concat destfile = "${Build.Intermediate}/steam-flattened.js">
|
||||
<filelist>
|
||||
<file name="${basedir}/../Utilities/bridge.js" />
|
||||
<file name="${basedir}/../Utilities/regex-bridge.js" />
|
||||
<file name="${Build}/Objective-J.build/\${Configuration}/Rhino/Objective-J.js" />
|
||||
<file name="${basedir}/steam.js" />
|
||||
<file name="${Build.Intermediate}/steam-preprocessed.js" />
|
||||
</filelist>
|
||||
</concat>
|
||||
</concat>
|
||||
|
||||
<jsc>
|
||||
<arguments>
|
||||
<arg line = "-o steam.class" />
|
||||
<arg value = "-nosource" />
|
||||
<arg value = "${Build.Intermediate}/steam.js" />
|
||||
<arg value = "${Build.Intermediate}/steam-flattened.js" />
|
||||
</arguments>
|
||||
</jsc>
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
function createFrameworks()
|
||||
{
|
||||
return create(Array.concat.apply(arguments, ["-f"]));
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
function create()
|
||||
{
|
||||
if (arguments.length < 1)
|
||||
printUsage("create");
|
||||
|
||||
var link = false,
|
||||
index = 0,
|
||||
count = arguments.length,
|
||||
|
||||
destination = NULL,
|
||||
justFrameworks = false;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var argument = arguments[index];
|
||||
|
||||
switch (arguments[index])
|
||||
{
|
||||
case "-l": link = true;
|
||||
break;
|
||||
case "-f": justFrameworks = true;
|
||||
break;
|
||||
default: destination = argument;
|
||||
}
|
||||
}
|
||||
|
||||
var sourceNewApplication = new File(OBJJ_HOME + "/lib/NewApplication"),
|
||||
destinationNewApplication = new File(destination),
|
||||
sourceFrameworks = new File(OBJJ_HOME + "/lib/Frameworks"),
|
||||
sourceDebugFrameworks = new File(OBJJ_HOME + "/lib/Frameworks-Debug"),
|
||||
destinationFrameworks = new File(destination + "/Frameworks"),
|
||||
destinationDebugFrameworks = new File(destination + "/Frameworks/Debug");
|
||||
|
||||
System.out.println(sourceNewApplication.getCanonicalPath() + "," + destinationNewApplication.getCanonicalPath() + "," + sourceFrameworks.getCanonicalPath() + "," + destinationFrameworks.getCanonicalPath());
|
||||
|
||||
if (justFrameworks || !destinationNewApplication.exists())
|
||||
{
|
||||
if (!justFrameworks)
|
||||
exec(["cp", "-vR", sourceNewApplication.getCanonicalPath(), destinationNewApplication.getCanonicalPath()], true);
|
||||
|
||||
if (!link)
|
||||
{
|
||||
exec(["cp", "-vR", sourceFrameworks.getCanonicalPath(), destinationFrameworks.getCanonicalPath()], true);
|
||||
exec(["cp", "-vR", sourceDebugFrameworks.getCanonicalPath(), destinationDebugFrameworks.getCanonicalPath()], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var STEAM_BUILD = System.getenv("STEAM_BUILD");
|
||||
|
||||
// Release Frameworks
|
||||
new File(destinationFrameworks).mkdir();
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Release/Objective-J").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Objective-J").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Release/Foundation").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Foundation").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Release/AppKit").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/AppKit").getCanonicalPath()], true);
|
||||
|
||||
// Debug Frameworks
|
||||
new File(destinationDebugFrameworks).mkdir();
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/Objective-J").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Debug/Objective-J").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/Foundation").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Debug/Foundation").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/AppKit").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Debug/AppKit").getCanonicalPath()], true);
|
||||
}
|
||||
}
|
||||
else
|
||||
System.out.println("Directory already exists");
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
function inlineBundle()
|
||||
{
|
||||
var index = 0,
|
||||
count = arguments.length,
|
||||
bundlePath = NULL;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var argument = arguments[index];
|
||||
|
||||
switch (arguments[index])
|
||||
{
|
||||
case "-d": directoryPath = arguments[++index];
|
||||
break;
|
||||
|
||||
default: bundlePath = argument;
|
||||
}
|
||||
}
|
||||
|
||||
var bundleFile = new File(bundlePath).getCanonicalFile(),
|
||||
bundlePath = String(bundleFile.getCanonicalPath()),
|
||||
inlinedBundle = readBundle(bundleFile, true),
|
||||
inlinedFiles = [],
|
||||
replacedFiles = [],
|
||||
staticContent = "";
|
||||
|
||||
// Find all internal bundles.
|
||||
var bundleCandidates = getFiles(bundleFile, "plist"),
|
||||
bundleCandidatesCount = bundleCandidates.length;
|
||||
|
||||
while (bundleCandidatesCount--)
|
||||
{
|
||||
var bundleCandidate = bundleCandidates[bundleCandidatesCount];
|
||||
|
||||
// We only care about Info.plists, specifically the ones that aren't us.
|
||||
if (String(bundleCandidate.getName()) !== "Info.plist" || String(bundleCandidate.getCanonicalPath()) === inlinedBundle.path)
|
||||
continue;
|
||||
|
||||
var infoDictionary = readPlist(bundleCandidate);
|
||||
|
||||
// At least one of these two has to be present for this to be a real deal bundle.
|
||||
if (!dictionary_getValue(infoDictionary, "CPBundleIdentifier") && !dictionary_getValue(infoDictionary, "CPBundleName"))
|
||||
continue;
|
||||
|
||||
java.lang.System.out.println(" Examining " + pathRelativeTo(bundleCandidate.getCanonicalPath(), bundlePath));
|
||||
|
||||
dictionary_removeValue(infoDictionary, "CPBundleExecutable");
|
||||
|
||||
var bundle = readBundle(bundleCandidate.getParentFile(), true);
|
||||
|
||||
bundle.path = pathRelativeTo(bundle.path, bundlePath);
|
||||
|
||||
// We want to inline the info plist too.
|
||||
var inlinedFiles = [makeOBJJPlistFile(infoDictionary, bundleCandidate, bundle)].concat(bundle.files),
|
||||
index = 0,
|
||||
count = inlinedFiles.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var file = inlinedFiles[index];
|
||||
|
||||
file.path = pathRelativeTo(String(file.path), bundlePath);
|
||||
|
||||
java.lang.System.out.println(" Inlining " + file.path);
|
||||
|
||||
replacedFiles.push(file.path);
|
||||
staticContent += fileToMarkedString(inlinedFiles[index], true);
|
||||
}
|
||||
}
|
||||
|
||||
var index = 0,
|
||||
existingStaticFiles = inlinedBundle.files,
|
||||
count = existingStaticFiles.length,
|
||||
topLevelContent = "@STATIC;1.0;";
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var file = existingStaticFiles[index];
|
||||
|
||||
// If this isn't actually part of our bundle, drop it!
|
||||
if (file.bundle !== inlinedBundle)
|
||||
continue;
|
||||
|
||||
file.path = pathRelativeTo(String(file.path), bundlePath);
|
||||
|
||||
replacedFiles.push(file.path);
|
||||
topLevelContent += fileToMarkedString(file, false);
|
||||
}
|
||||
|
||||
dictionary_setValue(inlinedBundle.info, "CPBundleReplacedFiles", replacedFiles);
|
||||
|
||||
writeContentsToFile(CPPropertyListCreateXMLData(inlinedBundle.info).string, inlinedBundle.path);
|
||||
writeContentsToFile(topLevelContent + staticContent, inlinedBundle._staticContentPath);
|
||||
}
|
||||
|
||||
function fileToMarkedString(anOBJJFile, encodeBundle)
|
||||
{
|
||||
var markedString = "";
|
||||
|
||||
markedString += MARKER_PATH + ';' + anOBJJFile.path.length + ';' + anOBJJFile.path;
|
||||
|
||||
if (encodeBundle)
|
||||
markedString += MARKER_BUNDLE + ';' + anOBJJFile.bundle.path.length + ';' + anOBJJFile.bundle.path;
|
||||
|
||||
var fragments = anOBJJFile.fragments;
|
||||
|
||||
if (fragments && fragments.length > 0)
|
||||
{
|
||||
var fragmentIndex = 0,
|
||||
fragmentCount = fragments.length;
|
||||
|
||||
for (; fragmentIndex < fragmentCount; ++fragmentIndex)
|
||||
markedString += fragments[fragmentIndex].toMarkedString();
|
||||
}
|
||||
|
||||
else
|
||||
markedString += MARKER_TEXT + ';' + anOBJJFile.contents.length + ';' + anOBJJFile.contents;
|
||||
|
||||
return markedString;
|
||||
}
|
||||
|
||||
function makeOBJJPlistFile(aDictionary, aFile, aBundle)
|
||||
{
|
||||
var file = new objj_file();
|
||||
|
||||
file.path = typeof aFile === "string" ? aFile : aFile.getCanonicalPath();
|
||||
file.bundle = aBundle;
|
||||
file.contents = CPPropertyListCreate280NorthData(aDictionary).string;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
function pathRelativeTo(target, relativeTo)
|
||||
{
|
||||
var components = [],
|
||||
targetParts = target.split("/"),
|
||||
relativeParts = relativeTo ? relativeTo.split("/") : [];
|
||||
|
||||
var i = 0;
|
||||
while (i < targetParts.length)
|
||||
{
|
||||
if (targetParts[i] != relativeParts[i])
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
for (var j = i; j < relativeParts.length; j++)
|
||||
components.push("..");
|
||||
|
||||
for (var j = i; j < targetParts.length; j++)
|
||||
components.push(targetParts[j]);
|
||||
|
||||
var result = components.join("/");
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
|
||||
importPackage(java.lang);
|
||||
importPackage(java.util);
|
||||
|
||||
importClass(java.io.File);
|
||||
importClass(java.io.BufferedReader);
|
||||
importClass(java.io.FileReader);
|
||||
importClass(java.io.BufferedWriter);
|
||||
importClass(java.io.FileWriter);
|
||||
importClass(java.io.SequenceInputStream);
|
||||
|
||||
#include "../Utilities/bundle.js"
|
||||
|
||||
#include "Project.js"
|
||||
|
||||
function main()
|
||||
{
|
||||
if (arguments.length < 1)
|
||||
printUsage();
|
||||
|
||||
var command = Array.prototype.shift.apply(arguments);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "create": create.apply(create, arguments);
|
||||
break;
|
||||
|
||||
case "create-frameworks": createFrameworks.apply(createFrameworks, arguments);
|
||||
break;
|
||||
|
||||
|
||||
case "inline-bundle": inlineBundle.apply(inlineBundle, arguments);
|
||||
break;
|
||||
|
||||
case "build": build.apply(build, arguments);
|
||||
break;
|
||||
|
||||
case "help": printUsage(arguments[1]);
|
||||
break;
|
||||
|
||||
case "version":
|
||||
case "--version": printVersion();
|
||||
break;
|
||||
|
||||
default : printUsage(command);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function fileArrayContainsFile(/*Array*/ files, /*File*/ aFile)
|
||||
{
|
||||
var index = 0,
|
||||
count = files.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
if (files[index].equals(aFile))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getFiles(/*File*/ sourceDirectory, /*nil|String|Array<String>*/ extensions, /*Array*/ exclusions)
|
||||
{
|
||||
var matches = [],
|
||||
files = sourceDirectory.listFiles(),
|
||||
hasMultipleExtensions = typeof extensions !== "string";
|
||||
|
||||
if (files)
|
||||
{
|
||||
var index = 0,
|
||||
count = files.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var file = files[index].getCanonicalFile(),
|
||||
name = String(file.getName()),
|
||||
isValidExtension = !extensions;
|
||||
|
||||
if (exclusions && fileArrayContainsFile(exclusions, file))
|
||||
continue;
|
||||
|
||||
if (!isValidExtension)
|
||||
if (hasMultipleExtensions)
|
||||
{
|
||||
var extensionCount = extensions.length;
|
||||
|
||||
while (extensionCount-- && !isValidExtension)
|
||||
{
|
||||
var extension = extensions[extensionCount];
|
||||
|
||||
if (name.substring(name.length - extension.length - 1) === ("." + extension))
|
||||
isValidExtension = true;
|
||||
}
|
||||
}
|
||||
else if (name.substring(name.length - extensions.length - 1) === ("." + extensions))
|
||||
isValidExtension = true;
|
||||
|
||||
if (isValidExtension)
|
||||
matches.push(file);
|
||||
|
||||
if (file.isDirectory())
|
||||
matches = matches.concat(getFiles(file, extensions, exclusions));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
function exec(/*Array*/ command, /*Boolean*/ showOutput)
|
||||
{
|
||||
var line = "",
|
||||
output = "",
|
||||
|
||||
process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command));
|
||||
reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream()));
|
||||
|
||||
while (line = reader.readLine())
|
||||
{
|
||||
if (showOutput)
|
||||
System.out.println(line);
|
||||
|
||||
output += line + '\n';
|
||||
}
|
||||
|
||||
reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream()));
|
||||
|
||||
while (line = reader.readLine())
|
||||
System.out.println(line);
|
||||
|
||||
try
|
||||
{
|
||||
if (process.waitFor() != 0)
|
||||
System.err.println("exit value = " + process.exitValue());
|
||||
}
|
||||
catch (anException)
|
||||
{
|
||||
System.err.println(anException);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function rsync(srcFile, dstFile)
|
||||
{
|
||||
var src, dst;
|
||||
|
||||
if (String(java.lang.System.getenv("OS")).indexOf("Windows") < 0)
|
||||
{
|
||||
src = srcFile.getAbsolutePath();
|
||||
dst = dstFile.getAbsolutePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
src = exec(["cygpath", "-u", srcFile.getAbsolutePath() + '/']);
|
||||
dst = exec(["cygpath", "-u", dstFile.getAbsolutePath() + "/Resources"]);
|
||||
}
|
||||
|
||||
if (srcFile.exists())
|
||||
exec(["rsync", "-avz", src, dst]);
|
||||
}
|
||||
|
||||
function getFileName(aPath)
|
||||
{
|
||||
var index = aPath.lastIndexOf('/');
|
||||
|
||||
if (index == -1)
|
||||
return aPath;
|
||||
|
||||
return aPath.substr(index + 1);
|
||||
}
|
||||
|
||||
function getFileNameWithoutExtension(aFileOrFileName)
|
||||
{
|
||||
var name = typeof aFileOrFileName === "string" ? aFileOrFileName : aFileOrFileName.getName(),
|
||||
index = name.lastIndexOf('.');
|
||||
|
||||
if (index == -1 || index == 0)
|
||||
return name;
|
||||
|
||||
return name.substr(0, index);
|
||||
}
|
||||
|
||||
function getFileExtension(aPath)
|
||||
{
|
||||
var slash = aPath.lastIndexOf('/'),
|
||||
period = aPath.lastIndexOf('.');
|
||||
|
||||
if (period < slash || (period == slash + 1))
|
||||
return "";
|
||||
|
||||
return aPath.substr(period + 1);
|
||||
}
|
||||
|
||||
main.apply(main, arguments);
|
||||
|
||||
#include "build.js"
|
||||
#include "create.js"
|
||||
#include "create-frameworks.js"
|
||||
#include "inline-bundle.js"
|
||||
#include "usage.js"
|
||||
#include "version.js"
|
||||
@@ -1,732 +0,0 @@
|
||||
|
||||
importPackage(java.lang);
|
||||
importPackage(java.util);
|
||||
|
||||
importClass(java.io.File);
|
||||
importClass(java.io.BufferedReader);
|
||||
importClass(java.io.FileReader);
|
||||
importClass(java.io.BufferedWriter);
|
||||
importClass(java.io.FileWriter);
|
||||
importClass(java.io.SequenceInputStream);
|
||||
|
||||
function Target(dictionary)
|
||||
{
|
||||
this._name = dictionary_getValue(dictionary, "Name");
|
||||
|
||||
var flagsString = dictionary_getValue(dictionary, "Flags");
|
||||
|
||||
this._flags = flagsString ? flagsString.split(/\s+/) : [];
|
||||
|
||||
this._exclusions = [];
|
||||
|
||||
var exclusions = dictionary_getValue(dictionary, "Excluded");
|
||||
|
||||
if (exclusions)
|
||||
{
|
||||
var index = 0,
|
||||
count = exclusions.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var file = new File(exclusions[index]).getCanonicalFile();
|
||||
|
||||
if (file.isDirectory())
|
||||
{
|
||||
var files = getFiles(file);
|
||||
|
||||
if (files.length)
|
||||
this._exclusions = this._exclusions.concat(files);
|
||||
}
|
||||
else
|
||||
this._exclusions.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Target.prototype.name = function()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
Target.prototype.exclusions = function()
|
||||
{
|
||||
return this._exclusions;
|
||||
}
|
||||
|
||||
Target.prototype.flags = function()
|
||||
{
|
||||
return this._flags;
|
||||
}
|
||||
|
||||
function Configuration(dictionary)
|
||||
{
|
||||
this._name = dictionary_getValue(dictionary, "Name");
|
||||
|
||||
var flagsString = dictionary_getValue(dictionary, "Flags");
|
||||
|
||||
this._flags = flagsString ? flagsString.split(/\s+/) : [];
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Configuration.prototype.name = function()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
Configuration.prototype.flags = function()
|
||||
{
|
||||
return this._flags;
|
||||
}
|
||||
|
||||
function Project(/*String*/ aFilePath, /*String*/ aBuildPath)
|
||||
{
|
||||
this._file = new File(aFilePath).getCanonicalFile();
|
||||
this._root = this._file.getParentFile();
|
||||
|
||||
// Read the project file (its just a plist).
|
||||
this._properties = readPlist(this._file);
|
||||
|
||||
this._name = dictionary_getValue(this._properties, "Name");
|
||||
|
||||
// Read existing Info.plist if it exists.
|
||||
var infoPlist = new File(this._root.getAbsolutePath() + "/Info.plist");
|
||||
|
||||
if (infoPlist.exists())
|
||||
this._infoDictionary = readPlist(new File(this._root.getAbsolutePath() + "/Info.plist"));
|
||||
else
|
||||
this._infoDictionary = new objj_dictionary();
|
||||
|
||||
this.buildPath = aBuildPath;
|
||||
|
||||
// Covert target dictionaries to target objects.
|
||||
var targetDictionaries = dictionary_getValue(this._properties, "Targets");
|
||||
|
||||
this._targets = [];
|
||||
|
||||
for (index = 0, count = targetDictionaries.length; index < count; ++index)
|
||||
this._targets.push(new Target(targetDictionaries[index]));
|
||||
|
||||
this.setActiveTarget(this._targets[0]);
|
||||
|
||||
// Covert target dictionaries to target objects.
|
||||
var configurationDictionaries = dictionary_getValue(this._properties, "Configurations");
|
||||
|
||||
this._configurations = [];
|
||||
|
||||
for (index = 0, count = configurationDictionaries.length; index < count; ++index)
|
||||
this._configurations.push(new Configuration(configurationDictionaries[index]));
|
||||
|
||||
this.setActiveConfiguration(this._configurations[0]);
|
||||
|
||||
// Grab the Resources Directory (if it exists)
|
||||
this._resources = new File(this._root.getAbsolutePath() + "/Resources/").getCanonicalFile();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Project.prototype.name = function()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
Project.prototype.targetWithName = function(/*String*/ aName)
|
||||
{
|
||||
var targets = this._targets,
|
||||
index = 0,
|
||||
count = targets.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var target = targets[index];
|
||||
|
||||
if (target.name() == aName)
|
||||
return target;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Project.prototype.configurationWithName = function(/*String*/ aName)
|
||||
{
|
||||
var configurations = this._configurations,
|
||||
index = 0,
|
||||
count = configurations.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var configuration = configurations[index];
|
||||
|
||||
if (configuration.name() == aName)
|
||||
return configuration;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Project.prototype.setActiveTarget = function(/*Target*/ aTarget)
|
||||
{
|
||||
this._activeTarget = aTarget;
|
||||
|
||||
this._buildProducts = null;
|
||||
this._buildIntermediates = null;
|
||||
this._buildObjects = null;
|
||||
}
|
||||
|
||||
Project.prototype.activeTarget = function()
|
||||
{
|
||||
return this._activeTarget;
|
||||
}
|
||||
|
||||
Project.prototype.setActiveConfiguration = function(/*Configuration*/ aConfiguration)
|
||||
{
|
||||
this._activeConfiguration = aConfiguration;
|
||||
|
||||
this._buildProducts = null;
|
||||
this._buildIntermediates = null;
|
||||
this._buildObjects = null;
|
||||
}
|
||||
|
||||
Project.prototype.activeConfiguration = function()
|
||||
{
|
||||
return this._activeConfiguration;
|
||||
}
|
||||
|
||||
Project.prototype.buildProducts = function()
|
||||
{
|
||||
if (!this._buildProducts)
|
||||
{
|
||||
this._buildProducts = new File(this.buildPath + '/' + this._activeConfiguration.name() + '/' + this._activeTarget.name()).getCanonicalFile();
|
||||
this._buildProducts.mkdirs();
|
||||
}
|
||||
|
||||
return this._buildProducts;
|
||||
}
|
||||
|
||||
Project.prototype.buildIntermediates = function()
|
||||
{
|
||||
if (!this._buildIntermediates)
|
||||
{
|
||||
this._buildIntermediates = new File(this.buildPath + '/' + this._activeTarget.name() + ".build/" + this._activeConfiguration.name()).getCanonicalFile();
|
||||
this._buildIntermediates.mkdirs();
|
||||
}
|
||||
|
||||
return this._buildIntermediates;
|
||||
}
|
||||
|
||||
Project.prototype.buildObjects = function()
|
||||
{
|
||||
if (!this._buildObjects)
|
||||
{
|
||||
this._buildObjects = new File(this.buildIntermediates().getAbsolutePath() + '/' + this._activeTarget.name()).getCanonicalFile();
|
||||
this._buildObjects.mkdirs();
|
||||
}
|
||||
|
||||
return this._buildObjects;
|
||||
}
|
||||
|
||||
Project.prototype.activeFlags = function()
|
||||
{
|
||||
return this.activeTarget().flags().concat(this.activeConfiguration().flags());
|
||||
}
|
||||
|
||||
Project.prototype.build = function()
|
||||
{
|
||||
java.lang.System.out.println("Building Target \"" + this.activeTarget().name() +
|
||||
"\" of Project \"" + this.name() +
|
||||
"\" with Configuration \"" + this.activeConfiguration().name() + "\".");
|
||||
|
||||
var jFiles = getFiles(this._root, "j", this._activeTarget.exclusions()),
|
||||
replacedFiles = [];
|
||||
hasModifiedJFiles = false;
|
||||
shouldObjjPreprocess = true,
|
||||
shouldGzip = this._gzip,
|
||||
objjcComponents = ["sh", OBJJ_HOME + "/bin/objjc"];
|
||||
|
||||
objjcComponents = objjcComponents.concat(this.activeFlags());
|
||||
|
||||
if (!shouldObjjPreprocess)
|
||||
objjcComponents.push("-E");
|
||||
|
||||
var buildObjects = this.buildObjects(),
|
||||
buildProducts = this.buildProducts();
|
||||
|
||||
for (index = 0, count = jFiles.length; index < count; ++index)
|
||||
{
|
||||
var file = jFiles[index],
|
||||
builtFile = new File(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o');
|
||||
|
||||
replacedFiles.push(file.getName() + "");
|
||||
|
||||
if (builtFile.exists() && file.lastModified() < builtFile.lastModified())
|
||||
continue;
|
||||
else
|
||||
hasModifiedJFiles = true;
|
||||
|
||||
objjcComponents.push(file.getAbsolutePath());
|
||||
|
||||
objjcComponents.push("-o");
|
||||
objjcComponents.push(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o');
|
||||
}
|
||||
|
||||
exec(objjcComponents, true);
|
||||
|
||||
var oFiles = getFiles(buildObjects, 'o'),
|
||||
sjFile = new File(buildProducts.getCanonicalPath() + '/' + this._activeTarget.name() + ".sj");
|
||||
|
||||
if (hasModifiedJFiles)
|
||||
{
|
||||
// concatenate sjheader.txt and individual .o
|
||||
exec(["sh", "-c", "cat '" + OBJJ_HOME + "/lib/sjheader.txt' '" + oFiles.join("' '") + "' > '" + sjFile.getCanonicalPath() + "'"], true);
|
||||
}
|
||||
|
||||
if (shouldGzip)
|
||||
{
|
||||
// gzip and copy .htaccess file
|
||||
exec(["sh", "-c", "gzip -c '" + sjFile.getCanonicalPath() + "' > '" + sjFile.getCanonicalPath() + ".gz'"], true);
|
||||
exec(["cp", OBJJ_HOME + "/lib/htaccess", sjFile.getParentFile().getCanonicalPath() + "/.htaccess"], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove gzip and .htaccess file if present
|
||||
exec(["rm", "-f", sjFile.getParentFile().getCanonicalPath() + "/.htaccess", sjFile.getCanonicalPath() + ".gz"], true);
|
||||
}
|
||||
|
||||
dictionary_setValue(this._infoDictionary, "CPBundleExecutable", this._activeTarget.name() + ".sj");
|
||||
dictionary_setValue(this._infoDictionary, "CPBundleReplacedFiles", replacedFiles);
|
||||
|
||||
this.writeInfoPlist();
|
||||
|
||||
this.copyResources();
|
||||
|
||||
// FIXME: This should be, if this is an app...
|
||||
if (dictionary_getValue(this._infoDictionary, "CPBundlePackageType") == "280N")
|
||||
this.copyIndexFile();
|
||||
|
||||
}
|
||||
|
||||
Project.prototype.clean = function()
|
||||
{
|
||||
java.lang.System.out.println("Cleaning Target \"" + this.activeTarget().name() +
|
||||
"\" of Project \"" + this.name() +
|
||||
"\" with Configuration \"" + this.activeConfiguration().name() + "\".");
|
||||
|
||||
exec(["rm", "-rf", this.buildIntermediates().getAbsolutePath()], true);
|
||||
exec(["rm", "-rf", this.buildProducts().getAbsolutePath()], true);
|
||||
}
|
||||
|
||||
Project.prototype.copyIndexFile = function()
|
||||
{
|
||||
var indexFile = new File(this._root.getAbsolutePath() + "/index.html").getCanonicalFile();
|
||||
|
||||
rsync(indexFile, this.buildProducts());
|
||||
}
|
||||
|
||||
Project.prototype.writeInfoPlist = function()
|
||||
{
|
||||
var writer = new BufferedWriter(new FileWriter(this.buildProducts().getAbsolutePath() + '/' + "Info.plist"));
|
||||
|
||||
writer.write(CPPropertyListCreateXMLData(this._infoDictionary).string);
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
Project.prototype.copyResources = function()
|
||||
{
|
||||
rsync(this._resources, this.buildProducts());
|
||||
}
|
||||
|
||||
function printUsage(command)
|
||||
{
|
||||
var usage = "usage: steam COMMAND [ARGS]\n\n"+
|
||||
"The most commonly used steam commands are:\n"+
|
||||
"\tbuild Build a project\n"+
|
||||
"\tcreate Create a new project\n\n"+
|
||||
"See 'steam help COMMAND' for more information on a specific command.";
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "--help":
|
||||
case undefined: java.lang.System.out.println(usage);
|
||||
break;
|
||||
|
||||
case "create": java.lang.System.out.println("Creates a new Cappuccino project.\n\nusage: steam create PROJECT_NAME [-l]\n\n"+
|
||||
"\t-l Link Frameworks to $STEAM_BUILD/Release, instead of installing default Frameworks");
|
||||
break;
|
||||
|
||||
default: java.lang.System.out.println("steam: '" + command + "' is not a steam command. See 'steam --help'.");
|
||||
}
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
function main()
|
||||
{
|
||||
if (arguments.length < 1)
|
||||
printUsage();
|
||||
|
||||
var command = Array.prototype.shift.apply(arguments);
|
||||
switch (command)
|
||||
{
|
||||
case "create": mainCreate.apply(mainCreate, arguments);
|
||||
break;
|
||||
case "build":
|
||||
mainBuild.apply(mainBuild, arguments);
|
||||
break;
|
||||
|
||||
case "help": printUsage(arguments[1]);
|
||||
break;
|
||||
|
||||
case "version":
|
||||
case "--version": printVersion();
|
||||
break;
|
||||
|
||||
default : printUsage(command);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function printVersion()
|
||||
{
|
||||
java.lang.System.out.println("steam version 0.6");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
|
||||
function mainCreate()
|
||||
{
|
||||
if (arguments.length < 1)
|
||||
printUsage("create");
|
||||
|
||||
var link = false,
|
||||
index = 0,
|
||||
count = arguments.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var argument = arguments[index];
|
||||
|
||||
switch (arguments[index])
|
||||
{
|
||||
case "-l": link = true;
|
||||
break;
|
||||
default: destination = argument;
|
||||
}
|
||||
}
|
||||
|
||||
var sourceNewApplication = new File(OBJJ_HOME + "/lib/NewApplication"),
|
||||
destinationNewApplication = new File(destination),
|
||||
sourceFrameworks = new File(OBJJ_HOME + "/lib/Frameworks"),
|
||||
sourceDebugFrameworks = new File(OBJJ_HOME + "/lib/Frameworks-Debug"),
|
||||
destinationFrameworks = new File(destination + "/Frameworks"),
|
||||
destinationDebugFrameworks = new File(destination + "/Frameworks/Debug");
|
||||
|
||||
System.out.println(sourceNewApplication.getCanonicalPath() + "," + destinationNewApplication.getCanonicalPath() + "," + sourceFrameworks.getCanonicalPath() + "," + destinationFrameworks.getCanonicalPath());
|
||||
|
||||
if (!destinationNewApplication.exists())
|
||||
{
|
||||
exec(["cp", "-vR", sourceNewApplication.getCanonicalPath(), destinationNewApplication.getCanonicalPath()], true);
|
||||
|
||||
if (!link)
|
||||
{
|
||||
exec(["cp", "-vR", sourceFrameworks.getCanonicalPath(), destinationFrameworks.getCanonicalPath()], true);
|
||||
exec(["cp", "-vR", sourceDebugFrameworks.getCanonicalPath(), destinationDebugFrameworks.getCanonicalPath()], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var STEAM_BUILD = System.getenv("STEAM_BUILD");
|
||||
|
||||
// Release Frameworks
|
||||
new File(destinationFrameworks).mkdir();
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Release/Objective-J").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Objective-J").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Release/Foundation").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Foundation").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Release/AppKit").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/AppKit").getCanonicalPath()], true);
|
||||
|
||||
// Debug Frameworks
|
||||
new File(destinationDebugFrameworks).mkdir();
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/Objective-J").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Debug/Objective-J").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/Foundation").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Debug/Foundation").getCanonicalPath()], true);
|
||||
|
||||
exec(["ln", "-s", new File(STEAM_BUILD + "/Debug/AppKit").getCanonicalPath(),
|
||||
new File(destination + "/Frameworks/Debug/AppKit").getCanonicalPath()], true);
|
||||
}
|
||||
}
|
||||
else
|
||||
System.out.println("Directory already exists");
|
||||
}
|
||||
|
||||
function mainBuild()
|
||||
{
|
||||
var index = 0,
|
||||
count = arguments.length,
|
||||
|
||||
actions = [],
|
||||
|
||||
targetName = null,
|
||||
configurationName = null,
|
||||
|
||||
buildPath = null,
|
||||
projectFilePath = null,
|
||||
|
||||
gzip = false;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
switch (arguments[index])
|
||||
{
|
||||
case "-f": if (index + 1 == count)
|
||||
throw "-f needs project file.";
|
||||
|
||||
projectFilePath = arguments[++index];
|
||||
break;
|
||||
|
||||
case "-t": if (index + 1 == count)
|
||||
throw "-t needs a target";
|
||||
|
||||
targetName = arguments[++index];
|
||||
break;
|
||||
|
||||
case "-c": if (index + 1 == count)
|
||||
throw "-c needs configuration";
|
||||
|
||||
configurationName = arguments[++index];
|
||||
break;
|
||||
|
||||
case "-b": if (index + 1 == count)
|
||||
throw "-b needs a build location";
|
||||
|
||||
buildPath = arguments[++index];
|
||||
break;
|
||||
|
||||
case "--gzip": gzip = true;
|
||||
break;
|
||||
|
||||
case "clean":
|
||||
case "build": actions.push(arguments[index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no project file was specified, look for one.
|
||||
if (!projectFilePath)
|
||||
{
|
||||
var candidates = getFiles(new File('.'), "steam");
|
||||
|
||||
if (candidates.length < 1)
|
||||
throw "No project file specified or found.";
|
||||
|
||||
projectFilePath = candidates[0];
|
||||
}
|
||||
|
||||
// Construct the Build Directory
|
||||
if (!buildPath)
|
||||
{
|
||||
buildPath = System.getenv("STEAM_BUILD");
|
||||
|
||||
if (!buildPath)
|
||||
buildPath = "Build";
|
||||
}
|
||||
|
||||
var project = new Project(projectFilePath, buildPath);
|
||||
|
||||
project._gzip = gzip;
|
||||
|
||||
if (targetName)
|
||||
{
|
||||
var target = project.targetWithName(targetName);
|
||||
|
||||
if (!target)
|
||||
throw "Target \"" + targetName + "\" not found in project.";
|
||||
|
||||
project.setActiveTarget(target);
|
||||
}
|
||||
|
||||
if (configurationName)
|
||||
{
|
||||
var configuration = project.configurationWithName(configurationName);
|
||||
|
||||
if (!configuration)
|
||||
throw "Configuration \"" + configurationName + "\" not found in project.";
|
||||
|
||||
project.setActiveConfiguration(configuration);
|
||||
}
|
||||
|
||||
if (!actions.length)
|
||||
actions.push("build");
|
||||
|
||||
for (index = 0, count = actions.length; index < count; ++index)
|
||||
project[actions[index]]();
|
||||
}
|
||||
|
||||
function fileArrayContainsFile(/*Array*/ files, /*File*/ aFile)
|
||||
{
|
||||
var index = 0,
|
||||
count = files.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
if (files[index].equals(aFile))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getFiles(/*File*/ sourceDirectory, /*nil|String|Array<String>*/ extensions, /*Array*/ exclusions)
|
||||
{
|
||||
var matches = [],
|
||||
files = sourceDirectory.listFiles(),
|
||||
hasMultipleExtensions = typeof extensions !== "string";
|
||||
|
||||
if (files)
|
||||
{
|
||||
var index = 0,
|
||||
count = files.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var file = files[index].getCanonicalFile(),
|
||||
name = String(file.getName()),
|
||||
isValidExtension = !extensions;
|
||||
|
||||
if (exclusions && fileArrayContainsFile(exclusions, file))
|
||||
continue;
|
||||
|
||||
if (!isValidExtension)
|
||||
if (hasMultipleExtensions)
|
||||
{
|
||||
var extensionCount = extensions.length;
|
||||
|
||||
while (extensionCount-- && !isValidExtension)
|
||||
{
|
||||
var extension = extensions[extensionCount];
|
||||
|
||||
if (name.substring(name.length - extension.length - 1) === ("." + extension))
|
||||
isValidExtension = true;
|
||||
}
|
||||
}
|
||||
else if (name.substring(name.length - extensions.length - 1) === ("." + extensions))
|
||||
isValidExtension = true;
|
||||
|
||||
if (isValidExtension)
|
||||
matches.push(file);
|
||||
|
||||
if (file.isDirectory())
|
||||
matches = matches.concat(getFiles(file, extensions, exclusions));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
function readPlist(/*File*/ aFile)
|
||||
{
|
||||
var reader = new BufferedReader(new FileReader(aFile)),
|
||||
fileContents = "";
|
||||
|
||||
// Get contents of the file
|
||||
while (reader.ready())
|
||||
fileContents += reader.readLine() + '\n';
|
||||
|
||||
reader.close();
|
||||
|
||||
var data = new objj_data();
|
||||
data.string = fileContents;
|
||||
|
||||
return new CPPropertyListCreateFromData(data);
|
||||
}
|
||||
|
||||
function exec(/*Array*/ command, /*Boolean*/ showOutput)
|
||||
{
|
||||
var line = "",
|
||||
output = "",
|
||||
|
||||
process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command));
|
||||
reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream()));
|
||||
|
||||
while (line = reader.readLine())
|
||||
{
|
||||
if (showOutput)
|
||||
System.out.println(line);
|
||||
|
||||
output += line + '\n';
|
||||
}
|
||||
|
||||
reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream()));
|
||||
|
||||
while (line = reader.readLine())
|
||||
System.out.println(line);
|
||||
|
||||
try
|
||||
{
|
||||
if (process.waitFor() != 0)
|
||||
System.err.println("exit value = " + process.exitValue());
|
||||
}
|
||||
catch (anException)
|
||||
{
|
||||
System.err.println(anException);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function rsync(srcFile, dstFile)
|
||||
{
|
||||
var src, dst;
|
||||
|
||||
if (String(java.lang.System.getenv("OS")).indexOf("Windows") < 0)
|
||||
{
|
||||
src = srcFile.getAbsolutePath();
|
||||
dst = dstFile.getAbsolutePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
src = exec(["cygpath", "-u", srcFile.getAbsolutePath() + '/']);
|
||||
dst = exec(["cygpath", "-u", dstFile.getAbsolutePath() + "/Resources"]);
|
||||
}
|
||||
|
||||
if (srcFile.exists())
|
||||
exec(["rsync", "-avz", src, dst]);
|
||||
}
|
||||
|
||||
function getFileName(aPath)
|
||||
{
|
||||
var index = aPath.lastIndexOf('/');
|
||||
|
||||
if (index == -1)
|
||||
return aPath;
|
||||
|
||||
return aPath.substr(index + 1);
|
||||
}
|
||||
|
||||
function getFileNameWithoutExtension(aFile)
|
||||
{
|
||||
var name = aFile.getName(),
|
||||
index = name.lastIndexOf('.');
|
||||
|
||||
if (index == -1 || index == 0)
|
||||
return name;
|
||||
|
||||
return name.substr(0, index);
|
||||
}
|
||||
|
||||
function getFileExtension(aPath)
|
||||
{
|
||||
var slash = aPath.lastIndexOf('/'),
|
||||
period = aPath.lastIndexOf('.');
|
||||
|
||||
if (period < slash || (period == slash + 1))
|
||||
return "";
|
||||
|
||||
return aPath.substr(period + 1);
|
||||
}
|
||||
|
||||
main.apply(main, arguments);
|
||||
@@ -15,4 +15,23 @@
|
||||
|
||||
</macrodef>
|
||||
|
||||
<macrodef name = "steam-inline-bundle">
|
||||
|
||||
<attribute name = "bundle" />
|
||||
|
||||
<element name = "arguments" optional = "true" implicit = "true"/>
|
||||
|
||||
<sequential>
|
||||
<exec executable = "steam">
|
||||
|
||||
<arg value = "inline-bundle" />
|
||||
<arg value = "@{bundle}" />
|
||||
|
||||
<arguments/>
|
||||
|
||||
</exec>
|
||||
</sequential>
|
||||
|
||||
</macrodef>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,22 @@
|
||||
function printUsage(command)
|
||||
{
|
||||
var usage = "usage: steam COMMAND [ARGS]\n\n"+
|
||||
"The most commonly used steam commands are:\n"+
|
||||
"\tbuild Build a project\n"+
|
||||
"\tcreate Create a new project\n\n"+
|
||||
"See 'steam help COMMAND' for more information on a specific command.";
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case "--help":
|
||||
case undefined: java.lang.System.out.println(usage);
|
||||
break;
|
||||
|
||||
case "create": java.lang.System.out.println("Creates a new Cappuccino project.\n\nusage: steam create PROJECT_NAME [-l]\n\n"+
|
||||
"\t-l Link Frameworks to $STEAM_BUILD/Release, instead of installing default Frameworks");
|
||||
break;
|
||||
|
||||
default: java.lang.System.out.println("steam: '" + command + "' is not a steam command. See 'steam --help'.");
|
||||
}
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
function printVersion()
|
||||
{
|
||||
java.lang.System.out.println("steam version 0.6");
|
||||
java.lang.System.exit(1);
|
||||
}
|
||||
Reference in new issue
Block a user