Classes/LevelMeter.m
/* |
<codex> |
*/ |
#import "LevelMeter.h" |
int _cmp_levelThresholds(const void * a, const void * b) |
{ |
if (((LevelMeterColorThreshold *)a)->maxValue > ((LevelMeterColorThreshold *)b)->maxValue) return 1; |
if (((LevelMeterColorThreshold *)a)->maxValue < ((LevelMeterColorThreshold *)b)->maxValue) return -1; |
return 0; |
} |
@implementation LevelMeter |
@synthesize vertical = _vertical; |
@synthesize bgColor = _bgColor; |
@synthesize borderColor = _borderColor; |
@synthesize variableLightIntensity = _variableLightIntensity; |
- (void)_performInit |
{ |
_level = 0.; |
_numLights = 0; |
_numColorThresholds = 3; |
_variableLightIntensity = YES; |
_bgColor = [[UIColor alloc] initWithRed:0. green:0. blue:0. alpha:0.6]; |
_borderColor = [[UIColor alloc] initWithRed:0. green:0. blue:0. alpha:1.]; |
_colorThresholds = malloc(3 * sizeof(LevelMeterColorThreshold)); |
_colorThresholds[0].maxValue = 0.25; |
_colorThresholds[0].color = [[UIColor alloc] initWithRed:0. green:1. blue:0. alpha:1.]; |
_colorThresholds[1].maxValue = 0.8; |
_colorThresholds[1].color = [[UIColor alloc] initWithRed:1. green:1. blue:0. alpha:1.]; |
_colorThresholds[2].maxValue = 1.; |
_colorThresholds[2].color = [[UIColor alloc] initWithRed:1. green:0. blue:0. alpha:1.]; |
_vertical = ([self frame].size.width < [self frame].size.height) ? YES : NO; |
} |
- (id)initWithFrame:(CGRect)frame |
{ |
if (self = [super initWithFrame:frame]) { |
[self _performInit]; |
} |
return self; |
} |
- (id)initWithCoder:(NSCoder *)coder |
{ |
if (self = [super initWithCoder:coder]) { |
[self _performInit]; |
} |
return self; |
} |
- (void)drawRect:(CGRect)rect |
{ |
CGColorSpaceRef cs = NULL; |
CGContextRef cxt = NULL; |
CGRect bds; |
cxt = UIGraphicsGetCurrentContext(); |
cs = CGColorSpaceCreateDeviceRGB(); |
if (_vertical) |
{ |
CGContextTranslateCTM(cxt, 0., [self bounds].size.height); |
CGContextScaleCTM(cxt, 1., -1.); |
bds = [self bounds]; |
} else { |
CGContextTranslateCTM(cxt, 0., [self bounds].size.height); |
CGContextRotateCTM(cxt, -M_PI_2); |
bds = CGRectMake(0., 0., [self bounds].size.height, [self bounds].size.width); |
} |
CGContextSetFillColorSpace(cxt, cs); |
CGContextSetStrokeColorSpace(cxt, cs); |
if (_numLights == 0) |
{ |
int i; |
CGFloat currentTop = 0.; |
if (_bgColor) |
{ |
[_bgColor set]; |
CGContextFillRect(cxt, bds); |
} |
for (i=0; i<_numColorThresholds; i++) |
{ |
LevelMeterColorThreshold thisThresh = _colorThresholds[i]; |
CGFloat val = MIN(thisThresh.maxValue, _level); |
CGRect rect = CGRectMake( |
0, |
(bds.size.height) * currentTop, |
bds.size.width, |
(bds.size.height) * (val - currentTop) |
); |
[thisThresh.color set]; |
CGContextFillRect(cxt, rect); |
if (_level < thisThresh.maxValue) break; |
currentTop = val; |
} |
if (_borderColor) |
{ |
[_borderColor set]; |
CGContextStrokeRect(cxt, CGRectInset(bds, .5, .5)); |
} |
} else { |
int light_i; |
CGFloat lightMinVal = 0.; |
CGFloat insetAmount, lightVSpace; |
lightVSpace = bds.size.height / (CGFloat)_numLights; |
if (lightVSpace < 4.) insetAmount = 0.; |
else if (lightVSpace < 8.) insetAmount = 0.5; |
else insetAmount = 1.; |
int peakLight = -1; |
if (_peakLevel > 0.) |
{ |
peakLight = _peakLevel * _numLights; |
if (peakLight >= _numLights) peakLight = _numLights - 1; |
} |
for (light_i=0; light_i<_numLights; light_i++) |
{ |
CGFloat lightMaxVal = (CGFloat)(light_i + 1) / (CGFloat)_numLights; |
CGFloat lightIntensity; |
CGRect lightRect; |
UIColor *lightColor; |
if (light_i == peakLight) |
{ |
lightIntensity = 1.; |
} else { |
lightIntensity = (_level - lightMinVal) / (lightMaxVal - lightMinVal); |
lightIntensity = LEVELMETER_CLAMP(0., lightIntensity, 1.); |
if ((!_variableLightIntensity) && (lightIntensity > 0.)) lightIntensity = 1.; |
} |
lightColor = _colorThresholds[0].color; |
int color_i; |
for (color_i=0; color_i<(_numColorThresholds-1); color_i++) |
{ |
LevelMeterColorThreshold thisThresh = _colorThresholds[color_i]; |
LevelMeterColorThreshold nextThresh = _colorThresholds[color_i + 1]; |
if (thisThresh.maxValue <= lightMaxVal) lightColor = nextThresh.color; |
} |
lightRect = CGRectMake( |
0., |
bds.size.height * ((CGFloat)(light_i) / (CGFloat)_numLights), |
bds.size.width, |
bds.size.height * (1. / (CGFloat)_numLights) |
); |
lightRect = CGRectInset(lightRect, insetAmount, insetAmount); |
if (_bgColor) |
{ |
[_bgColor set]; |
CGContextFillRect(cxt, lightRect); |
} |
if (lightIntensity == 1.) |
{ |
[lightColor set]; |
CGContextFillRect(cxt, lightRect); |
} else if (lightIntensity > 0.) { |
CGColorRef clr = CGColorCreateCopyWithAlpha([lightColor CGColor], lightIntensity); |
CGContextSetFillColorWithColor(cxt, clr); |
CGContextFillRect(cxt, lightRect); |
CGColorRelease(clr); |
} |
if (_borderColor) |
{ |
[_borderColor set]; |
CGContextStrokeRect(cxt, CGRectInset(lightRect, 0.5, 0.5)); |
} |
lightMinVal = lightMaxVal; |
} |
} |
CGColorSpaceRelease(cs); |
} |
- (void)dealloc { |
int i; |
for (i=0; i<_numColorThresholds; i++) [_colorThresholds[i].color release]; |
free(_colorThresholds); |
[_bgColor release]; |
[_borderColor release]; |
[super dealloc]; |
} |
- (CGFloat)level { return _level; } |
- (void)setLevel:(CGFloat)v { _level = v; } |
- (CGFloat)peakLevel { return _peakLevel; } |
- (void)setPeakLevel:(CGFloat)v { _peakLevel = v; } |
- (NSUInteger)numLights { return _numLights; } |
- (void)setNumLights:(NSUInteger)v { _numLights = v; } |
- (LevelMeterColorThreshold *)colorThresholds:(NSUInteger *)count |
{ |
*count = _numColorThresholds; |
return _colorThresholds; |
} |
- (void)setColorThresholds:(LevelMeterColorThreshold *)thresholds count:(NSUInteger)count |
{ |
int i; |
for (i=0; i<_numColorThresholds; i++) [_colorThresholds[i].color release]; |
_colorThresholds = realloc(_colorThresholds, sizeof(LevelMeterColorThreshold) * count); |
for (i=0; i<count; i++) |
{ |
_colorThresholds[i].maxValue = thresholds[i].maxValue; |
_colorThresholds[i].color = [thresholds[i].color copy]; |
} |
qsort(_colorThresholds, count, sizeof(LevelMeterColorThreshold), _cmp_levelThresholds); |
_numColorThresholds = count; |
} |
@end |
Copyright © 2014 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2014-02-12