mirror of https://github.com/LIJI32/SameBoy.git
349 lines
13 KiB
Objective-C
349 lines
13 KiB
Objective-C
#import "GBPaletteEditor.h"
|
|
#import "GBColorWell.h"
|
|
#import "GBSlider.h"
|
|
#import "GBPalettePicker.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;
|
|
}
|
|
[self save];
|
|
}
|
|
- (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];
|
|
}
|
|
[self save];
|
|
}
|
|
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)save
|
|
{
|
|
NSMutableDictionary *themes = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBThemes"].mutableCopy;
|
|
[themes removeObjectForKey:_paletteName];
|
|
if (![_paletteName isEqual:_nameField.text]) {
|
|
_paletteName = [GBPalettePicker makeUnique:_nameField.text];
|
|
}
|
|
|
|
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"];
|
|
}
|
|
}
|
|
- (void)viewWillDisappear:(BOOL)animated
|
|
{
|
|
[super viewWillDisappear:animated];
|
|
[self save];
|
|
}
|
|
|
|
@end
|