project_files/HedgewarsMobile/Classes/MNEValueTrackingSlider.m
author Wuzzy <almikes@aol.com>
Sat, 30 Sep 2017 23:52:08 +0200
changeset 12627 07fdda8c13a2
parent 11554 893722a2a1f9
child 12877 00215a7ec5f5
permissions -rwxr-xr-x
TrophyRace: Fix game never eliminating any hogs after a hog skipped or ran out of time Warning: This commit _might_ invalidate past records, but I'm not sure if this is actually the case. Note that only the eliminiation part of the script is touched, not the actual race logic. Even if records are actually broken by this, I and sheepluva have decided that it's more imporant to fix this very, VERY stupid and old bug than to preserve records.

//
// MNEValueTrackingSlider
//
// Copyright 2012 Michael Neuwert
// "You can use the code in your own project and modify it as you like."
// http://blog.neuwert-media.com/2012/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:NSTextAlignmentCenter];
    }
}

@end

#pragma mark -
#pragma mark MNEValueTrackingSlider implementations
@implementation MNEValueTrackingSlider

@synthesize thumbRect, textValue;

#pragma mark 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