diff --git a/AppKit/AppKit.steam b/AppKit/AppKit.steam
index 134c9b59f..58d524005 100644
--- a/AppKit/AppKit.steam
+++ b/AppKit/AppKit.steam
@@ -15,6 +15,7 @@
CPTableColumn.j
CPTableView.j
+ Themes
CoreGraphics/CGContextCanvas.j
CoreGraphics/CGContextVML.j
@@ -29,6 +30,7 @@
CPOutlineView.j
CPTableColumn.j
CPTableView.j
+ Themes
CoreGraphics/CGContextCanvas.j
CoreGraphics/CGContextVML.j
diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j
index 97cb4364b..c26071173 100644
--- a/AppKit/CPColor.j
+++ b/AppKit/CPColor.j
@@ -324,7 +324,7 @@ var _hueComponent = 0,
if (self)
{
_patternImage = anImage;
- _cssString = "url(\"" + _patternImage._filename + "\")";
+ _cssString = "url(\"" + [_patternImage filename] + "\")";
}
return self;
diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j
index 23fbf5b1e..87c1c0fb6 100644
--- a/AppKit/CPControl.j
+++ b/AppKit/CPControl.j
@@ -393,7 +393,7 @@ var CPControlBlackColor = [CPColor blackColor];
if ((_sendActionOn & (1 << type)) && isWithinFrame)
[self sendAction:_action to:_target];
- _trackingWasInFrame = isWithinFrame;
+ _trackingWasWithinFrame = isWithinFrame;
_previousTrackingLocation = currentLocation;
}
diff --git a/AppKit/CPImage.j b/AppKit/CPImage.j
index 34ff42ee7..5bf02cfd6 100644
--- a/AppKit/CPImage.j
+++ b/AppKit/CPImage.j
@@ -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;
diff --git a/AppKit/CPSlider.j b/AppKit/CPSlider.j
index 22e64bbec..1d05b0f17 100644
--- a/AppKit/CPSlider.j
+++ b/AppKit/CPSlider.j
@@ -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
+
+#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 float, which can be retrieved by the method floatValue and set by the method setFloatValue:.
-*/
@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 ALTs key.
-*/
-- (double)altIncrementValue
+- (CPColor)highlightedKnobColor
{
- return _altIncrementValue;
+ return _highlightedKnobColor;
}
-/*!
- Sets the value the slider will be incremented if the user holds the ALT 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 YES 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
diff --git a/AppKit/CPTheme.j b/AppKit/CPTheme.j
new file mode 100644
index 000000000..89c85aa3c
--- /dev/null
+++ b/AppKit/CPTheme.j
@@ -0,0 +1,286 @@
+
+@import
+@import
+@import
+
+
+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
diff --git a/AppKit/CPView.j b/AppKit/CPView.j
index 86257d3fc..d8a672bba 100644
--- a/AppKit/CPView.j
+++ b/AppKit/CPView.j
@@ -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",
diff --git a/AppKit/Cib/_CPCibCustomResource.j b/AppKit/Cib/_CPCibCustomResource.j
index db87d1660..ec34cc349 100644
--- a/AppKit/Cib/_CPCibCustomResource.j
+++ b/AppKit/Cib/_CPCibCustomResource.j
@@ -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
diff --git a/AppKit/Info.plist b/AppKit/Info.plist
index ed261efba..c06c96b61 100644
--- a/AppKit/Info.plist
+++ b/AppKit/Info.plist
@@ -4,6 +4,10 @@
CPBundleIdentifier
com.280n.AppKit
+ Default Themes Path
+ Default.cptheme
+ Default Theme Name
+ Default
CPBundleInfoDictionaryVersion
6.0
CPBundleName
diff --git a/AppKit/Themes/Default/AppController.j b/AppKit/Themes/Default/AppController.j
new file mode 100644
index 000000000..518cc25e4
--- /dev/null
+++ b/AppKit/Themes/Default/AppController.j
@@ -0,0 +1,169 @@
+/*
+ * AppController.j
+ *
+ * Created by __Me__ on __Date__.
+ * Copyright 2008 __MyCompanyName__. All rights reserved.
+ */
+
+@import
+@import
+
+
+@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
diff --git a/AppKit/Themes/Default/Default.steam b/AppKit/Themes/Default/Default.steam
new file mode 100644
index 000000000..367779c42
--- /dev/null
+++ b/AppKit/Themes/Default/Default.steam
@@ -0,0 +1,32 @@
+
+
+
+
+ Name
+ Default
+ Targets
+
+
+ Name
+ Default.cptheme
+ Type
+ 280N.theme
+
+
+ Configurations
+
+
+ Name
+ Debug
+ Flags
+ -DDEBUG -g
+
+
+ Name
+ Release
+ Flags
+ -O
+
+
+
+
diff --git a/AppKit/Themes/Default/Frameworks/AppKit b/AppKit/Themes/Default/Frameworks/AppKit
new file mode 120000
index 000000000..6f3e209f0
--- /dev/null
+++ b/AppKit/Themes/Default/Frameworks/AppKit
@@ -0,0 +1 @@
+/Users/tolmasky/Development/Build/Release/AppKit
\ No newline at end of file
diff --git a/AppKit/Themes/Default/Frameworks/Debug/AppKit b/AppKit/Themes/Default/Frameworks/Debug/AppKit
new file mode 120000
index 000000000..e1a0507cb
--- /dev/null
+++ b/AppKit/Themes/Default/Frameworks/Debug/AppKit
@@ -0,0 +1 @@
+/Users/tolmasky/Development/Build/Debug/AppKit
\ No newline at end of file
diff --git a/AppKit/Themes/Default/Frameworks/Debug/Foundation b/AppKit/Themes/Default/Frameworks/Debug/Foundation
new file mode 120000
index 000000000..cba870cf2
--- /dev/null
+++ b/AppKit/Themes/Default/Frameworks/Debug/Foundation
@@ -0,0 +1 @@
+/Users/tolmasky/Development/Build/Debug/Foundation
\ No newline at end of file
diff --git a/AppKit/Themes/Default/Frameworks/Debug/Objective-J b/AppKit/Themes/Default/Frameworks/Debug/Objective-J
new file mode 120000
index 000000000..99c1e032c
--- /dev/null
+++ b/AppKit/Themes/Default/Frameworks/Debug/Objective-J
@@ -0,0 +1 @@
+/Users/tolmasky/Development/Build/Debug/Objective-J
\ No newline at end of file
diff --git a/AppKit/Themes/Default/Frameworks/Foundation b/AppKit/Themes/Default/Frameworks/Foundation
new file mode 120000
index 000000000..b73c674fc
--- /dev/null
+++ b/AppKit/Themes/Default/Frameworks/Foundation
@@ -0,0 +1 @@
+/Users/tolmasky/Development/Build/Release/Foundation
\ No newline at end of file
diff --git a/AppKit/Themes/Default/Frameworks/Objective-J b/AppKit/Themes/Default/Frameworks/Objective-J
new file mode 120000
index 000000000..8674fc325
--- /dev/null
+++ b/AppKit/Themes/Default/Frameworks/Objective-J
@@ -0,0 +1 @@
+/Users/tolmasky/Development/Build/Release/Objective-J
\ No newline at end of file
diff --git a/AppKit/Themes/Default/Info.plist b/AppKit/Themes/Default/Info.plist
new file mode 100644
index 000000000..92ab8b53d
--- /dev/null
+++ b/AppKit/Themes/Default/Info.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ CPApplicationDelegateClass
+ AppController
+ CPBundleName
+ Hello World
+ CPPrincipalClass
+ CPApplication
+
+
diff --git a/AppKit/Resources/CPSlider/CPSliderTrackHorizontalCenter.png b/AppKit/Themes/Default/Resources/horizontal-track-center.png
similarity index 100%
rename from AppKit/Resources/CPSlider/CPSliderTrackHorizontalCenter.png
rename to AppKit/Themes/Default/Resources/horizontal-track-center.png
diff --git a/AppKit/Resources/CPSlider/CPSliderTrackHorizontalLeft.png b/AppKit/Themes/Default/Resources/horizontal-track-left.png
similarity index 100%
rename from AppKit/Resources/CPSlider/CPSliderTrackHorizontalLeft.png
rename to AppKit/Themes/Default/Resources/horizontal-track-left.png
diff --git a/AppKit/Resources/CPSlider/CPSliderTrackHorizontalRight.png b/AppKit/Themes/Default/Resources/horizontal-track-right.png
similarity index 100%
rename from AppKit/Resources/CPSlider/CPSliderTrackHorizontalRight.png
rename to AppKit/Themes/Default/Resources/horizontal-track-right.png
diff --git a/AppKit/Themes/Default/Resources/knob-highlighted.png b/AppKit/Themes/Default/Resources/knob-highlighted.png
new file mode 100644
index 000000000..ea566de80
Binary files /dev/null and b/AppKit/Themes/Default/Resources/knob-highlighted.png differ
diff --git a/AppKit/Themes/Default/Resources/knob.png b/AppKit/Themes/Default/Resources/knob.png
new file mode 100644
index 000000000..3591e46e3
Binary files /dev/null and b/AppKit/Themes/Default/Resources/knob.png differ
diff --git a/AppKit/Resources/CPSlider/CPSliderKnobRegularPushed.png b/AppKit/Themes/Default/Resources/vertical-track-bottom.png
similarity index 87%
rename from AppKit/Resources/CPSlider/CPSliderKnobRegularPushed.png
rename to AppKit/Themes/Default/Resources/vertical-track-bottom.png
index b6612ec3a..573fe87dd 100644
Binary files a/AppKit/Resources/CPSlider/CPSliderKnobRegularPushed.png and b/AppKit/Themes/Default/Resources/vertical-track-bottom.png differ
diff --git a/AppKit/Resources/CPSlider/CPSliderKnobRegular.png b/AppKit/Themes/Default/Resources/vertical-track-center.png
similarity index 86%
rename from AppKit/Resources/CPSlider/CPSliderKnobRegular.png
rename to AppKit/Themes/Default/Resources/vertical-track-center.png
index f2c3923d4..05441be1a 100644
Binary files a/AppKit/Resources/CPSlider/CPSliderKnobRegular.png and b/AppKit/Themes/Default/Resources/vertical-track-center.png differ
diff --git a/AppKit/Themes/Default/Resources/vertical-track-top.png b/AppKit/Themes/Default/Resources/vertical-track-top.png
new file mode 100644
index 000000000..a1878ed98
Binary files /dev/null and b/AppKit/Themes/Default/Resources/vertical-track-top.png differ
diff --git a/AppKit/Themes/Default/index-debug.html b/AppKit/Themes/Default/index-debug.html
new file mode 100644
index 000000000..392b37a8f
--- /dev/null
+++ b/AppKit/Themes/Default/index-debug.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AppKit/Themes/Default/index.html b/AppKit/Themes/Default/index.html
new file mode 100644
index 000000000..fbcf5a9bc
--- /dev/null
+++ b/AppKit/Themes/Default/index.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Hello World
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AppKit/Themes/Default/main.j b/AppKit/Themes/Default/main.j
new file mode 100644
index 000000000..b82bd4e3c
--- /dev/null
+++ b/AppKit/Themes/Default/main.j
@@ -0,0 +1,17 @@
+/*
+ * main.j
+ *
+ * Created by __Me__ on __Date__.
+ * Copyright 2008 __MyCompanyName__. All rights reserved.
+ */
+
+@import
+@import
+
+@import "AppController.j"
+
+
+function main(args, namedArgs)
+{
+ CPApplicationMain(args, namedArgs);
+}
diff --git a/AppKit/build.xml b/AppKit/build.xml
index 1ae3709ad..327bc4b87 100644
--- a/AppKit/build.xml
+++ b/AppKit/build.xml
@@ -3,6 +3,8 @@
+
+
@@ -26,6 +28,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Objective-J/evaluate.js b/Objective-J/evaluate.js
index 1886003be..72fd1ddf1 100644
--- a/Objective-J/evaluate.js
+++ b/Objective-J/evaluate.js
@@ -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();
diff --git a/Objective-J/file.js b/Objective-J/file.js
index 4d72810be..8c2e2d6cb 100644
--- a/Objective-J/file.js
+++ b/Objective-J/file.js
@@ -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;
}
diff --git a/Tools/Utilities/bundle.js b/Tools/Utilities/bundle.js
new file mode 100644
index 000000000..2e3a3d3ec
--- /dev/null
+++ b/Tools/Utilities/bundle.js
@@ -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) });
+}
diff --git a/Tools/Utilities/file.js b/Tools/Utilities/file.js
new file mode 100644
index 000000000..c8461a7ab
--- /dev/null
+++ b/Tools/Utilities/file.js
@@ -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) });
+}
diff --git a/Tools/steam/Project.js b/Tools/steam/Project.js
new file mode 100644
index 000000000..2543ce460
--- /dev/null
+++ b/Tools/steam/Project.js
@@ -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());
+}
diff --git a/Tools/steam/build.js b/Tools/steam/build.js
new file mode 100644
index 000000000..959d22a0b
--- /dev/null
+++ b/Tools/steam/build.js
@@ -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]]();
+}
diff --git a/Tools/steam/build.xml b/Tools/steam/build.xml
index 65da0fe1a..40493bd64 100644
--- a/Tools/steam/build.xml
+++ b/Tools/steam/build.xml
@@ -24,20 +24,22 @@
-
+
+
+
-
+
-
+
-
+
diff --git a/Tools/steam/create-frameworks.js b/Tools/steam/create-frameworks.js
new file mode 100644
index 000000000..3d91f1b04
--- /dev/null
+++ b/Tools/steam/create-frameworks.js
@@ -0,0 +1,4 @@
+function createFrameworks()
+{
+ return create(Array.concat.apply(arguments, ["-f"]));
+}
\ No newline at end of file
diff --git a/Tools/steam/create.js b/Tools/steam/create.js
new file mode 100644
index 000000000..d95fc069a
--- /dev/null
+++ b/Tools/steam/create.js
@@ -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");
+}
diff --git a/Tools/steam/inline-bundle.js b/Tools/steam/inline-bundle.js
new file mode 100644
index 000000000..2e2dc8643
--- /dev/null
+++ b/Tools/steam/inline-bundle.js
@@ -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;
+}
\ No newline at end of file
diff --git a/Tools/steam/main.js b/Tools/steam/main.js
new file mode 100644
index 000000000..211989dc8
--- /dev/null
+++ b/Tools/steam/main.js
@@ -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*/ 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"
diff --git a/Tools/steam/steam.js b/Tools/steam/steam.js
deleted file mode 100644
index bcbbd352d..000000000
--- a/Tools/steam/steam.js
+++ /dev/null
@@ -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*/ 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);
diff --git a/Tools/steam/steam.xml b/Tools/steam/steam.xml
index 9db95a440..8b5e0a9f6 100644
--- a/Tools/steam/steam.xml
+++ b/Tools/steam/steam.xml
@@ -15,4 +15,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tools/steam/usage.js b/Tools/steam/usage.js
new file mode 100644
index 000000000..389fadc53
--- /dev/null
+++ b/Tools/steam/usage.js
@@ -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);
+}
diff --git a/Tools/steam/version.js b/Tools/steam/version.js
new file mode 100644
index 000000000..c22171a3f
--- /dev/null
+++ b/Tools/steam/version.js
@@ -0,0 +1,5 @@
+function printVersion()
+{
+ java.lang.System.out.println("steam version 0.6");
+ java.lang.System.exit(1);
+}
\ No newline at end of file