SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
iOS/GBSlider.m
1 #import "GBSlider.h"
2 #import <objc/runtime.h>
3
4 #if !__has_include(<UIKit/UISliderTrackConfiguration.h>)
5 /* Building with older SDKs */
6 API_AVAILABLE(ios(19.0))
7 @interface UISliderTrackConfiguration : NSObject
8 @property (nonatomic, readwrite) bool allowsTickValuesOnly;
9 @property (nonatomic, readwrite) float neutralValue;
10 + (instancetype)configurationWithNumberOfTicks:(NSInteger)ticks;
11 @end
12
13 @interface UISlider (configuration)
14 @property(nonatomic, copy) UISliderTrackConfiguration *trackConfiguration API_AVAILABLE(ios(19.0));
15 @end
16 #endif
17
18 static inline void temperature_tint(double temperature, double *r, double *g, double *b)
19 {
20 if (temperature >= 0) {
21 *r = 1;
22 *g = pow(1 - temperature, 0.375);
23 if (temperature >= 0.75) {
24 *b = 0;
25 }
26 else {
27 *b = sqrt(0.75 - temperature) / sqrt(0.75);
28 }
29 }
30 else {
31 *b = 1;
32 double squared = pow(temperature, 2);
33 *g = 0.125 * squared + 0.3 * temperature + 1.0;
34 *r = 0.21875 * squared + 0.5 * temperature + 1.0;
35 }
36 }
37
38 @implementation GBSlider
39 {
40 GBSliderStyle _style;
41 }
42
43 - (instancetype)initWithFrame:(CGRect)frame
44 {
45 self = [super initWithFrame:frame];
46 [self addTarget:self action:@selector(valueChanged) forControlEvents:UIControlEventValueChanged];
47 self.style = GBSliderStyleTemperature;
48 return self;
49 }
50
51 - (void)updateTint
52 {
53 if (_style == GBSliderStyleTemperature) {
54 double r, g, b;
55 temperature_tint(self.value, &r, &g, &b);
56 self.thumbTintColor = [UIColor colorWithRed:r green:g blue:b alpha:1.0];
57 }
58 if (_style == GBSliderStyleHue) {
59 double hue = (self.value - self.minimumValue) / (self.maximumValue - self.minimumValue);
60 double r = 0, g = 0, b =0 ;
61 double t = fmod(hue * 6, 1);
62 switch ((int)(hue * 6) % 6) {
63 case 0:
64 r = 1;
65 g = t;
66 break;
67 case 1:
68 r = 1 - t;
69 g = 1;
70 break;
71 case 2:
72 g = 1;
73 b = t;
74 break;
75 case 3:
76 g = 1 - t;
77 b = 1;
78 break;
79 case 4:
80 b = 1;
81 r = t;
82 break;
83 case 5:
84 b = 1 - t;
85 r = 1;
86 break;
87 }
88 self.thumbTintColor = [UIColor colorWithRed:r green:g blue:b alpha:1.0];
89 }
90 }
91
92 - (void)setValue:(float)value
93 {
94 [super setValue:value];
95 [self updateTint];
96 }
97
98 - (void)valueChanged
99 {
100 if (fabsf(self.value) < 0.05 && self.value != 0 && _style != GBSliderStyleHue) {
101 self.value = 0;
102 }
103 [self updateTint];
104 }
105
106 -(UIImage *)maximumTrackImageForState:(UIControlState)state
107 {
108 return [[UIImage alloc] init];
109 }
110
111
112 -(UIImage *)minimumTrackImageForState:(UIControlState)state
113 {
114 return [[UIImage alloc] init];
115 }
116
117 - (void)drawRect:(CGRect)rect
118 {
119 bool solarium = false;
120 if (@available(iOS 19.0, *)) {
121 solarium = true;
122 }
123 CGSize size = self.bounds.size;
124 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(2, round(size.height / 2 - 1.5), size.width - 4, 3) cornerRadius:4];
125 if (_style != GBSliderStyleHue) {
126 [path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(round(size.width / 2 - 1.5), 12, 3, size.height - 24) cornerRadius:4]];
127 }
128 if (_style == GBSliderStyleTicks) {
129 [path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 12, 3, size.height - 24) cornerRadius:4]];
130 [path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(size.width - 3, 12, 3, size.height - 24) cornerRadius:4]];
131 }
132 if (_style == GBSliderStyleHue) {
133 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(3, round(size.height / 2 - 1.5) + 1 - solarium, size.width - 6, solarium? 2 : 1) cornerRadius:8];
134 CGContextRef context = UIGraphicsGetCurrentContext();
135 CGContextSaveGState(context);
136 [path addClip];
137
138 CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
139 CGColorRef colors[] = {
140 UIColor.redColor.CGColor,
141 UIColor.yellowColor.CGColor,
142 UIColor.greenColor.CGColor,
143 UIColor.cyanColor.CGColor,
144 UIColor.blueColor.CGColor,
145 UIColor.magentaColor.CGColor,
146 UIColor.redColor.CGColor,
147 };
148 CFArrayRef colorsArray = CFArrayCreate(NULL, (const void **)colors, 7, &kCFTypeArrayCallBacks);
149 CGGradientRef gradient = CGGradientCreateWithColors(colorspace, colorsArray, NULL);
150 unsigned spacing = solarium? 16 : 3;
151 CGContextDrawLinearGradient(context,
152 gradient,
153 (CGPoint){spacing, 0},
154 (CGPoint){size.width - spacing, 0},
155 kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
156 CFRelease(gradient);
157 CFRelease(colorsArray);
158 CFRelease(colorspace);
159 CGContextRestoreGState(context);
160
161 }
162 [[UIColor colorWithRed:120 / 255.0
163 green:120 / 255.0
164 blue:130 / 255.0
165 alpha:70 / 255.0] set];
166 if (!solarium) {
167 [path fill];
168 }
169
170 [super drawRect:rect];
171 }
172
173 - (void)setStyle:(GBSliderStyle)style
174 {
175 _style = style;
176 if (@available(iOS 19.0, *)) {
177 switch (_style) {
178 case GBSliderStyleTemperature:
179 case GBSliderStyleTicks: {
180 UISliderTrackConfiguration *conf = [objc_getClass("UISliderTrackConfiguration") configurationWithNumberOfTicks:3];
181 conf.allowsTickValuesOnly = false;
182 conf.neutralValue = 0.5;
183 self.trackConfiguration = conf;
184 self.maximumTrackTintColor = nil;
185 self.minimumTrackTintColor = nil;
186 break;
187 }
188 case GBSliderStyleHue: {
189 UISliderTrackConfiguration *conf = [objc_getClass("UISliderTrackConfiguration") configurationWithNumberOfTicks:0];
190 conf.allowsTickValuesOnly = false;
191 self.trackConfiguration = conf;
192 self.minimumTrackTintColor = [UIColor clearColor];
193 break;
194 }
195 }
196 }
197 }
198
199 - (GBSliderStyle)style
200 {
201 return _style;
202 }
203
204 - (void)setFrame:(CGRect)frame
205 {
206 [super setFrame:frame];
207 [self setNeedsDisplay];
208 }
209
210 @end
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.