mirror of https://github.com/LIJI32/SameBoy.git
211 lines
6.4 KiB
Objective-C
211 lines
6.4 KiB
Objective-C
#import "GBSlider.h"
|
|
#import <objc/runtime.h>
|
|
|
|
#if !__has_include(<UIKit/UISliderTrackConfiguration.h>)
|
|
/* Building with older SDKs */
|
|
API_AVAILABLE(ios(19.0))
|
|
@interface UISliderTrackConfiguration : NSObject
|
|
@property (nonatomic, readwrite) bool allowsTickValuesOnly;
|
|
@property (nonatomic, readwrite) float neutralValue;
|
|
+ (instancetype)configurationWithNumberOfTicks:(NSInteger)ticks;
|
|
@end
|
|
|
|
@interface UISlider (configuration)
|
|
@property(nonatomic, copy, nullable) UISliderTrackConfiguration *trackConfiguration API_AVAILABLE(ios(19.0));
|
|
@end
|
|
#endif
|
|
|
|
static inline void temperature_tint(double temperature, double *r, double *g, double *b)
|
|
{
|
|
if (temperature >= 0) {
|
|
*r = 1;
|
|
*g = pow(1 - temperature, 0.375);
|
|
if (temperature >= 0.75) {
|
|
*b = 0;
|
|
}
|
|
else {
|
|
*b = sqrt(0.75 - temperature) / sqrt(0.75);
|
|
}
|
|
}
|
|
else {
|
|
*b = 1;
|
|
double squared = pow(temperature, 2);
|
|
*g = 0.125 * squared + 0.3 * temperature + 1.0;
|
|
*r = 0.21875 * squared + 0.5 * temperature + 1.0;
|
|
}
|
|
}
|
|
|
|
@implementation GBSlider
|
|
{
|
|
GBSliderStyle _style;
|
|
}
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
self = [super initWithFrame:frame];
|
|
[self addTarget:self action:@selector(valueChanged) forControlEvents:UIControlEventValueChanged];
|
|
self.style = GBSliderStyleTemperature;
|
|
return self;
|
|
}
|
|
|
|
- (void)updateTint
|
|
{
|
|
if (_style == GBSliderStyleTemperature) {
|
|
double r, g, b;
|
|
temperature_tint(self.value, &r, &g, &b);
|
|
self.thumbTintColor = [UIColor colorWithRed:r green:g blue:b alpha:1.0];
|
|
}
|
|
if (_style == GBSliderStyleHue) {
|
|
double hue = (self.value - self.minimumValue) / (self.maximumValue - self.minimumValue);
|
|
double r = 0, g = 0, b =0 ;
|
|
double t = fmod(hue * 6, 1);
|
|
switch ((int)(hue * 6) % 6) {
|
|
case 0:
|
|
r = 1;
|
|
g = t;
|
|
break;
|
|
case 1:
|
|
r = 1 - t;
|
|
g = 1;
|
|
break;
|
|
case 2:
|
|
g = 1;
|
|
b = t;
|
|
break;
|
|
case 3:
|
|
g = 1 - t;
|
|
b = 1;
|
|
break;
|
|
case 4:
|
|
b = 1;
|
|
r = t;
|
|
break;
|
|
case 5:
|
|
b = 1 - t;
|
|
r = 1;
|
|
break;
|
|
}
|
|
self.thumbTintColor = [UIColor colorWithRed:r green:g blue:b alpha:1.0];
|
|
}
|
|
}
|
|
|
|
- (void)setValue:(float)value
|
|
{
|
|
[super setValue:value];
|
|
[self updateTint];
|
|
}
|
|
|
|
- (void)valueChanged
|
|
{
|
|
if (fabsf(self.value) < 0.05 && self.value != 0 && _style != GBSliderStyleHue) {
|
|
self.value = 0;
|
|
}
|
|
[self updateTint];
|
|
}
|
|
|
|
-(UIImage *)maximumTrackImageForState:(UIControlState)state
|
|
{
|
|
return [[UIImage alloc] init];
|
|
}
|
|
|
|
|
|
-(UIImage *)minimumTrackImageForState:(UIControlState)state
|
|
{
|
|
return [[UIImage alloc] init];
|
|
}
|
|
|
|
- (void)drawRect:(CGRect)rect
|
|
{
|
|
bool solarium = false;
|
|
if (@available(iOS 19.0, *)) {
|
|
solarium = true;
|
|
}
|
|
CGSize size = self.bounds.size;
|
|
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(2, round(size.height / 2 - 1.5), size.width - 4, 3) cornerRadius:4];
|
|
if (_style != GBSliderStyleHue) {
|
|
[path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(round(size.width / 2 - 1.5), 12, 3, size.height - 24) cornerRadius:4]];
|
|
}
|
|
if (_style == GBSliderStyleTicks) {
|
|
[path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 12, 3, size.height - 24) cornerRadius:4]];
|
|
[path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(size.width - 3, 12, 3, size.height - 24) cornerRadius:4]];
|
|
}
|
|
if (_style == GBSliderStyleHue) {
|
|
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(3, round(size.height / 2 - 1.5) + 1 - solarium, size.width - 6, solarium? 2 : 1) cornerRadius:8];
|
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
CGContextSaveGState(context);
|
|
[path addClip];
|
|
|
|
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
|
CGColorRef colors[] = {
|
|
UIColor.redColor.CGColor,
|
|
UIColor.yellowColor.CGColor,
|
|
UIColor.greenColor.CGColor,
|
|
UIColor.cyanColor.CGColor,
|
|
UIColor.blueColor.CGColor,
|
|
UIColor.magentaColor.CGColor,
|
|
UIColor.redColor.CGColor,
|
|
};
|
|
CFArrayRef colorsArray = CFArrayCreate(NULL, (const void **)colors, 7, &kCFTypeArrayCallBacks);
|
|
CGGradientRef gradient = CGGradientCreateWithColors(colorspace, colorsArray, NULL);
|
|
unsigned spacing = solarium? 16 : 3;
|
|
CGContextDrawLinearGradient(context,
|
|
gradient,
|
|
(CGPoint){spacing, 0},
|
|
(CGPoint){size.width - spacing, 0},
|
|
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
|
CFRelease(gradient);
|
|
CFRelease(colorsArray);
|
|
CFRelease(colorspace);
|
|
CGContextRestoreGState(context);
|
|
|
|
}
|
|
[[UIColor colorWithRed:120 / 255.0
|
|
green:120 / 255.0
|
|
blue:130 / 255.0
|
|
alpha:70 / 255.0] set];
|
|
if (!solarium) {
|
|
[path fill];
|
|
}
|
|
|
|
[super drawRect:rect];
|
|
}
|
|
|
|
- (void)setStyle:(GBSliderStyle)style
|
|
{
|
|
_style = style;
|
|
if (@available(iOS 19.0, *)) {
|
|
switch (_style) {
|
|
case GBSliderStyleTemperature:
|
|
case GBSliderStyleTicks: {
|
|
UISliderTrackConfiguration *conf = [objc_getClass("UISliderTrackConfiguration") configurationWithNumberOfTicks:3];
|
|
conf.allowsTickValuesOnly = false;
|
|
conf.neutralValue = 0.5;
|
|
self.trackConfiguration = conf;
|
|
self.maximumTrackTintColor = nil;
|
|
self.minimumTrackTintColor = nil;
|
|
break;
|
|
}
|
|
case GBSliderStyleHue: {
|
|
UISliderTrackConfiguration *conf = [objc_getClass("UISliderTrackConfiguration") configurationWithNumberOfTicks:0];
|
|
conf.allowsTickValuesOnly = false;
|
|
self.trackConfiguration = conf;
|
|
self.minimumTrackTintColor = [UIColor clearColor];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (GBSliderStyle)style
|
|
{
|
|
return _style;
|
|
}
|
|
|
|
- (void)setFrame:(CGRect)frame
|
|
{
|
|
[super setFrame:frame];
|
|
[self setNeedsDisplay];
|
|
}
|
|
|
|
@end
|