diff -r beab48f963d5 -r d8b98aa486a6 project_files/HedgewarsMobile/Classes/MNEValueTrackingSlider.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/MNEValueTrackingSlider.m Sun Feb 12 18:50:22 2012 +0100 @@ -0,0 +1,200 @@ +// +// MNEValueTrackingSlider +// +// Copyright 2011 Michael Neuwert +// "You can use the code in your own project and modify it as you like." +// http://blog.neuwert-media.com/2011/04/customized-uislider-with-visual-value-tracking/ +// + + +#import "MNEValueTrackingSlider.h" + +#pragma mark - +#pragma mark Private UIView subclass rendering the popup showing slider value +@interface SliderValuePopupView : UIView +@property (nonatomic, retain) UIFont *font; +@property (nonatomic, copy) NSString *text; +@property (nonatomic) float arrowOffset; +@end + +@implementation SliderValuePopupView + +@synthesize font = _font; +@synthesize text = _text; +@synthesize arrowOffset = _arrowOffset; + +-(id) initWithFrame:(CGRect) frame { + self = [super initWithFrame:frame]; + if (self) { + self.font = [UIFont boldSystemFontOfSize:18]; + } + return self; +} + +-(void) dealloc { + self.text = nil; + self.font = nil; + [super dealloc]; +} + +-(void) drawRect:(CGRect) rect { + // Create the path for the rounded rectangle + CGRect roundedRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, floorf(self.bounds.size.height * 0.8)); + UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:6.0]; + roundedRectPath.lineWidth = 2.0f; + + // Create the arrow path + UIBezierPath *arrowPath = [UIBezierPath bezierPath]; + /* + // Make sure the arrow offset is nice + if (-self.arrowOffset + 1 > CGRectGetMidX(self.bounds) / 2) + self.arrowOffset = -CGRectGetMidX(self.bounds) / 2 + 1; + if (self.arrowOffset > CGRectGetMidX(self.bounds) / 2) + self.arrowOffset = CGRectGetMidX(self.bounds) / 2 -1; + */ + + CGFloat midX = CGRectGetMidX(self.bounds) + self.arrowOffset; + CGPoint p0 = CGPointMake(midX, CGRectGetMaxY(self.bounds)); + [arrowPath moveToPoint:p0]; + [arrowPath addLineToPoint:CGPointMake((midX - 10.0), CGRectGetMaxY(roundedRect))]; + [arrowPath addLineToPoint:CGPointMake((midX + 10.0), CGRectGetMaxY(roundedRect))]; + [arrowPath closePath]; + + // Attach the arrow path to the rounded rect + [roundedRectPath appendPath:arrowPath]; + + // Color various sections + [[UIColor blackColor] setFill]; + [roundedRectPath fill]; + [[UIColor whiteColor] setStroke]; + [roundedRectPath stroke]; + [[UIColor whiteColor] setFill]; + [arrowPath fill]; + + // Draw the text + if (self.text) { + [[UIColor lightYellowColor] set]; + CGSize s = [_text sizeWithFont:self.font]; + CGFloat yOffset = (roundedRect.size.height - s.height) / 2; + CGRect textRect = CGRectMake(roundedRect.origin.x, yOffset, roundedRect.size.width, s.height); + + [_text drawInRect:textRect + withFont:self.font + lineBreakMode:UILineBreakModeWordWrap + alignment:UITextAlignmentCenter]; + } +} + +@end + +#pragma mark - +#pragma mark MNEValueTrackingSlider implementations +@implementation MNEValueTrackingSlider + +@synthesize thumbRect, textValue; + +#pragma Private methods + +-(void) _constructSlider { + valuePopupView = [[SliderValuePopupView alloc] initWithFrame:CGRectZero]; + valuePopupView.backgroundColor = [UIColor clearColor]; + valuePopupView.alpha = 0.0; + [self addSubview:valuePopupView]; +} + +-(void) _fadePopupViewInAndOut:(BOOL)aFadeIn { + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:0.25]; + if (aFadeIn) { + valuePopupView.alpha = 1.0; + } else { + valuePopupView.alpha = 0.0; + } + [UIView commitAnimations]; +} + +-(void) _positionAndUpdatePopupView { + CGRect _thumbRect = self.thumbRect; + CGRect popupRect = CGRectOffset(_thumbRect, 0, -floorf(_thumbRect.size.height * 1.5)); + // (-100, -15) determines the size of the the rect + popupRect = CGRectInset(popupRect, -100, -15); + + // this prevents drawing the popup outside the slider view + if (popupRect.origin.x < -self.frame.origin.x+5) + popupRect.origin.x = -self.frame.origin.x+5; + else if (popupRect.origin.x > self.superview.frame.size.width - popupRect.size.width - self.frame.origin.x - 5) + popupRect.origin.x = self.superview.frame.size.width - popupRect.size.width - self.frame.origin.x - 5; + //else if (CGRectGetMaxX(popupRect) > CGRectGetMaxX(self.superview.bounds)) + // popupRect.origin.x = CGRectGetMaxX(self.superview.bounds) - CGRectGetWidth(popupRect) - 1.0; + + valuePopupView.arrowOffset = CGRectGetMidX(_thumbRect) - CGRectGetMidX(popupRect); + + valuePopupView.frame = popupRect; + valuePopupView.text = self.textValue; + [valuePopupView setNeedsDisplay]; +} + +#pragma mark Memory management + +-(id) initWithFrame:(CGRect) frame { + self = [super initWithFrame:frame]; + if (self) { + [self _constructSlider]; + } + return self; +} + +-(id) initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + if (self) { + [self _constructSlider]; + } + return self; +} + +-(void) dealloc { + [valuePopupView release]; + [textValue release]; + [super dealloc]; +} + +#pragma mark - +#pragma mark UIControl touch event tracking +-(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { + // Fade in and update the popup view + CGPoint touchPoint = [touch locationInView:self]; + // Check if the knob is touched. Only in this case show the popup-view + if(CGRectContainsPoint(CGRectInset(self.thumbRect, -14.0, -12.0), touchPoint)) { + [self _positionAndUpdatePopupView]; + [self _fadePopupViewInAndOut:YES]; + } + return [super beginTrackingWithTouch:touch withEvent:event]; +} + +-(BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { + // Update the popup view as slider knob is being moved + [self _positionAndUpdatePopupView]; + return [super continueTrackingWithTouch:touch withEvent:event]; +} + +-(void) cancelTrackingWithEvent:(UIEvent *)event { + [super cancelTrackingWithEvent:event]; +} + +-(void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { + // Fade out the popoup view + [self _fadePopupViewInAndOut:NO]; + [super endTrackingWithTouch:touch withEvent:event]; +} + +#pragma mark - +#pragma mark Custom property accessors +-(CGRect) thumbRect { + CGRect trackRect = [self trackRectForBounds:self.bounds]; + CGRect thumbR = [self thumbRectForBounds:self.bounds + trackRect:trackRect + value:self.value]; + return thumbR; +} + +@end