git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

commit 447cdf2672f32f72ee086a741db3fee722d5ad6f
parent 062d44e0653110c1237534d5ded1954a539eafdb
Author: Lior Halphon <LIJI32@gmail.com>
Date:   Sat, 21 Sep 2024 21:53:24 +0300

Allow editing existing palettes

Diffstat:
AiOS/GBColorWell.h7+++++++
AiOS/GBColorWell.m75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AiOS/GBPaletteEditor.h7+++++++
AiOS/GBPaletteEditor.m349+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MiOS/GBPalettePicker.m23+++++++++++++++++++++++
MiOS/GBSettingsViewController.m4++--
AiOS/GBSlider.h11+++++++++++
AiOS/GBSlider.m153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DiOS/GBTemperatureSlider.h5-----
DiOS/GBTemperatureSlider.m80-------------------------------------------------------------------------------
10 files changed, 627 insertions(+), 87 deletions(-)

diff --git a/iOS/GBColorWell.h b/iOS/GBColorWell.h @@ -0,0 +1,7 @@ +#import <UIKit/UIKit.h> + +API_AVAILABLE(ios(14.0)) +@interface GBColorWell : UIColorWell + +@end + diff --git a/iOS/GBColorWell.m b/iOS/GBColorWell.m @@ -0,0 +1,75 @@ +#import "GBColorWell.h" + +@implementation GBColorWell +{ + UIView *_proxyView; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + self.opaque = false; + [self addTarget:self action:@selector(setNeedsDisplay) forControlEvents:UIControlEventValueChanged]; + return self; +} + +- (void)drawRect:(CGRect)rect +{ + if (self.enabled) { + [[UIColor systemFillColor] set]; + } + else { + [[UIColor quaternarySystemFillColor] set]; + } + rect = self.bounds; + [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:6] fill]; + + rect.size.width -= 6; + rect.size.height -= 6; + rect.origin.x += 3; + rect.origin.y += 3; + + if (!self.enabled) { + rect.size.width -= 2; + rect.size.height -= 2; + rect.origin.x += 1; + rect.origin.y += 1; + } + + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, (CGSize){0, 0}, 2, [UIColor colorWithWhite:0 alpha:self.enabled? 0.25 : 0.125].CGColor); + [self.selectedColor set]; + [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:3] fill]; + CGContextRestoreGState(context); +} + +- (void)addSubview:(UIView *)view +{ + if (!_proxyView) { + _proxyView = [[UIView alloc] initWithFrame:self.bounds]; + [super addSubview:_proxyView]; + _proxyView.layer.mask = [CALayer layer]; + } + [_proxyView addSubview:view]; +} + +- (void)setSelectedColor:(UIColor *)selectedColor +{ + [super setSelectedColor:selectedColor]; + [self setNeedsDisplay]; +} + +- (UIColor *)selectedColor +{ + UIColor *orig = [super selectedColor]; + CGFloat red, green, blue; + [orig getRed:&red green:&green blue:&blue alpha:nil]; + red = MIN(MAX(red, 0), 1); + green = MIN(MAX(green, 0), 1); + blue = MIN(MAX(blue, 0), 1); + return [UIColor colorWithRed:red green:green blue:blue alpha:1.0]; +} + +@end diff --git a/iOS/GBPaletteEditor.h b/iOS/GBPaletteEditor.h @@ -0,0 +1,7 @@ +#import <UIKit/UIKit.h> + +API_AVAILABLE(ios(14.0)) +@interface GBPaletteEditor : UITableViewController +- (instancetype)initForPalette:(NSString *)name; +@end + diff --git a/iOS/GBPaletteEditor.m b/iOS/GBPaletteEditor.m @@ -0,0 +1,349 @@ +#import "GBPaletteEditor.h" +#import "GBColorWell.h" +#import "GBSlider.h" + +static double blend(double from, double to, double position) +{ + return from * (1 - position) + to * position; +} + +@implementation GBPaletteEditor +{ + bool _displayingManual; + NSString *_paletteName; + bool _isCurrent; + + UITableViewCell *_nameCell; + UITextField *_nameField; + + UITableViewCell *_colorsCell; + UIColorWell *_colorWells[5]; + + UITableViewCell *_disabledLCDCell; + UISwitch *_disabledLCDSwitch; + + UITableViewCell *_manualCell; + UISwitch *_manualSwitch; + + UITableViewCell *_brightnessCell; + GBSlider *_brightnessSlider; + + UITableViewCell *_hueCell; + GBSlider *_hueSlider; + + UITableViewCell *_hueStrengthCell; + UISlider *_hueStrengthSlider; +} + + +- (instancetype)initForPalette:(NSString *)name +{ + self = [self initWithStyle:UITableViewStyleInsetGrouped]; + _paletteName = name; + _isCurrent = [[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"] isEqual:name]; + return self; +} + +- (UITableViewCell *)sliderCellWithSlider:(UISlider *)slider +{ + UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + CGRect rect = cell.contentView.bounds; + rect.size.width -= 24; + rect.size.height -= 24; + rect.origin.x += 12; + rect.origin.y += 12; + slider.frame = rect; + slider.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [cell.contentView addSubview:slider]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + [slider addTarget:self action:@selector(updateAutoColors) forControlEvents:UIControlEventValueChanged]; + return cell; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *theme = [defaults dictionaryForKey:@"GBThemes"][_paletteName]; + + { + _nameCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + CGRect frame = _nameCell.contentView.bounds; + frame.size.width -= - 32; + frame.origin.x += 16; + _nameField = [[UITextField alloc] initWithFrame:frame]; + _nameField.font = _nameCell.textLabel.font; + _nameField.text = _paletteName; + _nameField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [_nameCell.contentView addSubview:_nameField]; + _nameCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + { + static const unsigned wellSize = 36; + _colorsCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + CGRect frame = _nameCell.contentView.bounds; + UIView *view = [[UIView alloc] initWithFrame:CGRectMake((frame.size.width - wellSize * 5) / 2, + (frame.size.height - wellSize) / 2, + wellSize * 5, + wellSize)]; + NSArray *titles = @[ + @"Darkest Color", + @"Dark Midtone", + @"Light Midtone", + @"Lightest Color", + @"Display Off Color", + ]; + for (unsigned i = 0; i < 5; i++) { + _colorWells[i] = [[GBColorWell alloc] initWithFrame:CGRectMake(i * wellSize, 0, wellSize, wellSize)]; + _colorWells[i].supportsAlpha = false; + _colorWells[i].title = titles[i]; + _colorWells[i].selectedColor = [UIColor colorWithRed:(([theme[@"Colors"][i] unsignedIntValue] >> 0) & 0xFF) / 255.0 + green:(([theme[@"Colors"][i] unsignedIntValue] >> 8) & 0xFF) / 255.0 + blue:(([theme[@"Colors"][i] unsignedIntValue] >> 16) & 0xFF) / 255.0 + alpha:1.0]; + [_colorWells[i] addTarget:self action:@selector(updateToggles) forControlEvents:UIControlEventValueChanged]; + + [view addSubview:_colorWells[i]]; + } + view.autoresizingMask = + UIViewAutoresizingFlexibleLeftMargin | + UIViewAutoresizingFlexibleRightMargin | + UIViewAutoresizingFlexibleTopMargin | + UIViewAutoresizingFlexibleBottomMargin; + [_colorsCell.contentView addSubview:view]; + _colorsCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + { + _disabledLCDCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + _disabledLCDSwitch = [[UISwitch alloc] init]; + _disabledLCDCell.accessoryView = _disabledLCDSwitch; + if ([theme[@"DisabledLCDColor"] boolValue]) { + _disabledLCDSwitch.on = true; + } + + [_disabledLCDSwitch addTarget:self action:@selector(updateToggles) forControlEvents:UIControlEventValueChanged]; + _disabledLCDCell.selectionStyle = UITableViewCellSelectionStyleNone; + _disabledLCDCell.textLabel.text = @"Distinct Disabled LCD Color"; + } + + { + _manualCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + _manualSwitch = [[UISwitch alloc] init]; + _manualCell.accessoryView = _manualSwitch; + if ([theme[@"Manual"] boolValue]) { + _manualSwitch.on = true; + } + + [_manualSwitch addTarget:self action:@selector(updateToggles) forControlEvents:UIControlEventValueChanged]; + _manualCell.selectionStyle = UITableViewCellSelectionStyleNone; + _manualCell.textLabel.text = @"Manual Mode"; + } + + { + _brightnessSlider = [[GBSlider alloc] init]; + _brightnessSlider.minimumValue = -1; + _brightnessSlider.maximumValue = 1; + _brightnessSlider.continuous = true; + _brightnessSlider.style = GBSliderStyleTicks; + _brightnessSlider.value = [theme[@"BrightnessBias"] doubleValue]; + _brightnessCell = [self sliderCellWithSlider:_brightnessSlider]; + } + + { + _hueSlider = [[GBSlider alloc] init]; + _hueSlider.minimumValue = 0; + _hueSlider.maximumValue = 360; + _hueSlider.continuous = true; + _hueSlider.style = GBSliderStyleHue; + _hueSlider.value = [theme[@"HueBias"] doubleValue] * 360; + _hueCell = [self sliderCellWithSlider:_hueSlider]; + } + + { + _hueStrengthSlider = [[UISlider alloc] init]; + _hueStrengthSlider.minimumValue = 0; + _hueStrengthSlider.maximumValue = 1; + _hueStrengthSlider.continuous = true; + _hueStrengthSlider.value = [theme[@"HueBiasStrength"] doubleValue]; + _hueStrengthCell = [self sliderCellWithSlider:_hueStrengthSlider]; + } + + [self updateToggles]; + self.title = [NSString stringWithFormat:@"Editing %@", _paletteName]; +} + +- (UIColor *)autoColorAtPositon:(double)position +{ + + UIColor *first = _colorWells[0].selectedColor; + UIColor *second = _colorWells[4].selectedColor; + + CGFloat firstRed, firstGreen, firstBlue; + CGFloat secondRed, secondGreen, secondBlue; + [first getRed:&firstRed green:&firstGreen blue:&firstBlue alpha:NULL]; + [second getRed:&secondRed green:&secondGreen blue:&secondBlue alpha:NULL]; + + + double brightness = 1 / pow(4, _brightnessSlider.value); + position = pow(position, brightness); + UIColor *hue = _hueSlider.thumbTintColor; + double bias = _hueStrengthSlider.value; + + CGFloat red, green, blue; + [hue getRed:&red green:&green blue:&blue alpha:NULL]; + red = 1 / pow(4, (red * 2 - 1) * bias); + green = 1 / pow(4, (green * 2 - 1) * bias); + blue = 1 / pow(4, (blue * 2 - 1) * bias); + UIColor *ret = [UIColor colorWithRed:blend(firstRed, secondRed, pow(position, red)) + green:blend(firstGreen, secondGreen, pow(position, green)) + blue:blend(firstBlue, secondBlue, pow(position, blue)) + alpha:1.0]; + return ret; +} + +- (void)updateAutoColors +{ + if (_disabledLCDSwitch.on) { + _colorWells[1].selectedColor = [self autoColorAtPositon:8 / 25.0]; + _colorWells[2].selectedColor = [self autoColorAtPositon:16 / 25.0]; + _colorWells[3].selectedColor = [self autoColorAtPositon:24 / 25.0]; + } + else { + _colorWells[1].selectedColor = [self autoColorAtPositon:1 / 3.0]; + _colorWells[2].selectedColor = [self autoColorAtPositon:2 / 3.0]; + _colorWells[3].selectedColor = _colorWells[4].selectedColor; + } +} +- (void)updateToggles +{ + if (_manualSwitch.on) { + _colorWells[1].enabled = true; + _colorWells[2].enabled = true; + _colorWells[3].enabled = true; + if (!(_colorWells[4].enabled = _disabledLCDSwitch.on)) { + _colorWells[4].selectedColor = _colorWells[3].selectedColor; + } + if (!_displayingManual) { + [self.tableView deleteSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)] + withRowAnimation:UITableViewRowAnimationFade]; + } + } + else { + _colorWells[1].enabled = false; + _colorWells[2].enabled = false; + _colorWells[3].enabled = false; + _colorWells[4].enabled = true; + if (_displayingManual) { + [self.tableView insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)] + withRowAnimation:UITableViewRowAnimationFade]; + } + [self updateAutoColors]; + } +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + _displayingManual = _manualSwitch.on; + return _displayingManual? 2 : 5; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + switch (section) { + case 0: return 1; // Name + case 1: return 3; // Colors + case 2: return 1; // Brightness Bias + case 3: return 2; // Hue Bias + default: return 0; + }; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + switch (section) { + case 0: return @"Palette Name"; + case 2: return @"Brightness Bias"; + case 3: return @"Hue Bias"; + } + return nil; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + switch (indexPath.section) { + case 0: return _nameCell; + case 1: { + switch (indexPath.row) { + case 0: return _colorsCell; + case 1: return _disabledLCDCell; + case 2: return _manualCell; + } + return nil; + } + case 2: return _brightnessCell; + case 3: return indexPath.row == 0? _hueCell : _hueStrengthCell; + } + return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.section == 2) return 63; + return [super tableView:tableView heightForRowAtIndexPath:indexPath]; +} + +- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + return nil; +} + +- (NSNumber *)encodeWell:(unsigned)index +{ + CGFloat r, g, b; + [_colorWells[index].selectedColor getRed:&r green:&g blue:&b alpha:NULL]; + return @((((unsigned)round(r * 255) << 0) | + ((unsigned)round(g * 255) << 8) | + ((unsigned)round(b * 255) << 16) | + 0xFF000000)); +} + +- (void)viewWillDisappear:(BOOL)animated +{ + NSMutableDictionary *themes = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBThemes"].mutableCopy; + [themes removeObjectForKey:_paletteName]; + _paletteName = _nameField.text; + unsigned i = 2; + NSArray *builtins = @[ + @"Greyscale", + @"Lime (Game Boy)", + @"Olive (Pocket)", + @"Teal (Light)", + ]; + + while (themes[_paletteName] || [builtins containsObject:_paletteName]) { + _paletteName = [NSString stringWithFormat:@"%@ %d", _nameField.text, i++]; + } + + themes[_paletteName] = @{ + @"BrightnessBias": @(_brightnessSlider.value), + @"Colors": @[[self encodeWell:0], + [self encodeWell:1], + [self encodeWell:2], + [self encodeWell:3], + [self encodeWell:4]], + @"DisabledLCDColor": _disabledLCDSwitch.on? @YES : @NO, + @"HueBias": @(_hueSlider.value / 360.0), + @"HueBiasStrength": @(_hueStrengthSlider.value), + @"Manual": _manualSwitch.on? @YES : @NO, + }; + + [[NSUserDefaults standardUserDefaults] setObject:themes forKey:@"GBThemes"]; + if (_isCurrent) { + [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"GBCurrentTheme"]; // Force a reload + [[NSUserDefaults standardUserDefaults] setObject:_paletteName forKey:@"GBCurrentTheme"]; + } +} + +@end diff --git a/iOS/GBPalettePicker.m b/iOS/GBPalettePicker.m @@ -1,4 +1,5 @@ #import "GBPalettePicker.h" +#import "GBPaletteEditor.h" #import <CoreServices/CoreServices.h> /* TODO: Unify with Cocoa? */ @@ -419,6 +420,23 @@ contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath deleteAction.attributes = UIMenuElementAttributesDestructive; return [UIMenu menuWithTitle:nil children:@[ + [UIAction actionWithTitle:@"Edit" + image:[UIImage systemImageNamed:@"paintbrush"] + identifier:nil + handler:^(__kindof UIAction *action) { + if (@available(iOS 14.0, *)) { + [self.navigationController pushViewController:[[GBPaletteEditor alloc] initForPalette:[self.tableView cellForRowAtIndexPath:indexPath].textLabel.text] + animated:true]; + } + else { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Palette Editor Unavailable" + message:@"The palette editor requires iOS 14 or newer." + preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:true completion:nil]; + return; + } + }], [UIAction actionWithTitle:@"Share" image:[UIImage systemImageNamed:@"square.and.arrow.up"] identifier:nil @@ -456,4 +474,9 @@ contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath } } +- (void)viewWillAppear:(BOOL)animated +{ + [self.tableView reloadData]; +} + @end diff --git a/iOS/GBSettingsViewController.m b/iOS/GBSettingsViewController.m @@ -1,5 +1,5 @@ #import "GBSettingsViewController.h" -#import "GBTemperatureSlider.h" +#import "GBSlider.h" #import "GBViewBase.h" #import "GBThemesViewController.h" #import "GBPalettePicker.h" @@ -764,7 +764,7 @@ static id ValueForItem(NSDictionary *item) rect.size.height -= 24; rect.origin.x += 12; rect.origin.y += 12; - UISlider *slider = [item[@"type"] == typeLightTemp? [GBTemperatureSlider alloc] : [UISlider alloc] initWithFrame:rect]; + UISlider *slider = [item[@"type"] == typeLightTemp? [GBSlider alloc] : [UISlider alloc] initWithFrame:rect]; slider.continuous = true; slider.minimumValue = [item[@"min"] floatValue]; slider.maximumValue = [item[@"max"] floatValue]; diff --git a/iOS/GBSlider.h b/iOS/GBSlider.h @@ -0,0 +1,11 @@ +#import <UIKit/UIKit.h> + +typedef enum { + GBSliderStyleTemperature, + GBSliderStyleHue, + GBSliderStyleTicks, +} GBSliderStyle; + +@interface GBSlider : UISlider +@property GBSliderStyle style; +@end diff --git a/iOS/GBSlider.m b/iOS/GBSlider.m @@ -0,0 +1,153 @@ +#import "GBSlider.h" + +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 + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + [self addTarget:self action:@selector(valueChanged) forControlEvents:UIControlEventValueChanged]; + 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 +{ + 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, size.width - 6, 1) cornerRadius:4]; + 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); + CGContextDrawLinearGradient(context, + gradient, + (CGPoint){3, 0}, + (CGPoint){size.width - 3, 0}, + 0); + 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]; + [path fill]; + + [super drawRect:rect]; +} + +- (void)setFrame:(CGRect)frame +{ + [super setFrame:frame]; + [self setNeedsDisplay]; +} + +@end diff --git a/iOS/GBTemperatureSlider.h b/iOS/GBTemperatureSlider.h @@ -1,5 +0,0 @@ -#import <UIKit/UIKit.h> - -@interface GBTemperatureSlider : UISlider - -@end diff --git a/iOS/GBTemperatureSlider.m b/iOS/GBTemperatureSlider.m @@ -1,80 +0,0 @@ -#import "GBTemperatureSlider.h" - -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 GBTemperatureSlider - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - [self addTarget:self action:@selector(valueChanged) forControlEvents:UIControlEventValueChanged]; - return self; -} - -- (void)updateTint -{ - double r, g, b; - temperature_tint(self.value, &r, &g, &b); - 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) { - self.value = 0; - } - else { - [self updateTint]; - } -} - --(UIImage *)maximumTrackImageForState:(UIControlState)state -{ - return [[UIImage alloc] init]; -} - - --(UIImage *)minimumTrackImageForState:(UIControlState)state -{ - return [[UIImage alloc] init]; -} - -- (void)drawRect:(CGRect)rect -{ - CGSize size = self.bounds.size; - UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(2, round(size.height / 2 - 1.5), size.width - 4, 3) cornerRadius:4]; - [path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(round(size.width / 2 - 1.5), 12, 3, size.height - 24) cornerRadius:4]]; - [[UIColor colorWithRed:120 / 255.0 - green:120 / 255.0 - blue:130 / 255.0 - alpha:70 / 255.0] set]; - [path fill]; - - [super drawRect:rect]; -} - -@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.