diff --git a/Cocoa/Document.m b/Cocoa/Document.m index 2a77259..c757ce1 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -10,6 +10,7 @@ #include "GBCheatWindowController.h" #include "GBTerminalTextFieldCell.h" #include "BigSurToolbar.h" +#import "GBPaletteEditorController.h" /* Todo: The general Objective-C coding style conflicts with SameBoy's. This file needs a cleanup. */ /* Todo: Split into category files! This is so messy!!! */ @@ -256,23 +257,7 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on) - (void) updatePalette { - switch ([[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"]) { - case 1: - GB_set_palette(&gb, &GB_PALETTE_DMG); - break; - - case 2: - GB_set_palette(&gb, &GB_PALETTE_MGB); - break; - - case 3: - GB_set_palette(&gb, &GB_PALETTE_GBL); - break; - - default: - GB_set_palette(&gb, &GB_PALETTE_GREY); - break; - } + GB_set_palette(&gb, [GBPaletteEditorController userPalette]); } - (void) updateBorderMode @@ -1952,7 +1937,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) { bool shouldResume = running; [self stop]; - NSSavePanel * savePanel = [NSSavePanel savePanel]; + NSSavePanel *savePanel = [NSSavePanel savePanel]; [savePanel setAllowedFileTypes:@[@"png"]]; [savePanel beginSheetModalForWindow:self.printerFeedWindow completionHandler:^(NSInteger result) { if (result == NSModalResponseOK) { diff --git a/Cocoa/GBHueSliderCell.h b/Cocoa/GBHueSliderCell.h new file mode 100644 index 0000000..f293124 --- /dev/null +++ b/Cocoa/GBHueSliderCell.h @@ -0,0 +1,9 @@ +#import + +@interface NSSlider (GBHueSlider) +-(NSColor *)colorValue; +@end + +@interface GBHueSliderCell : NSSliderCell +-(NSColor *)colorValue; +@end diff --git a/Cocoa/GBHueSliderCell.m b/Cocoa/GBHueSliderCell.m new file mode 100644 index 0000000..7f0bd82 --- /dev/null +++ b/Cocoa/GBHueSliderCell.m @@ -0,0 +1,113 @@ +#import "GBHueSliderCell.h" + +@interface NSSliderCell(privateAPI) +- (double)_normalizedDoubleValue; +@end + +@implementation GBHueSliderCell +{ + bool _drawingTrack; +} + +-(NSColor *)colorValue +{ + double hue = self.doubleValue / 360.0; + 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; + b = 0; + 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; + } + return [NSColor colorWithRed:r green:g blue:b alpha:1.0]; +} + +-(void)drawKnob:(NSRect)knobRect +{ + [super drawKnob:knobRect]; + NSRect peekRect = knobRect; + peekRect.size.width /= 2; + peekRect.size.height /= 2; + peekRect.origin.x += peekRect.size.width / 2; + peekRect.origin.y += peekRect.size.height / 2; + NSColor *color = self.colorValue; + if (!self.enabled) { + color = [color colorWithAlphaComponent:0.5]; + } + [color setFill]; + NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:peekRect]; + [path fill]; + [[NSColor colorWithWhite:0 alpha:0.25] setStroke]; + [path setLineWidth:0.5]; + [path stroke]; +} + +-(double)_normalizedDoubleValue +{ + if (_drawingTrack) return 0; + return [super _normalizedDoubleValue]; +} + +-(void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped +{ + if (!self.enabled) { + [super drawBarInside:rect flipped:flipped]; + return; + } + + _drawingTrack = true; + [super drawBarInside:rect flipped:flipped]; + _drawingTrack = false; + + NSGradient *gradient = [[NSGradient alloc] initWithColors:@[ + [NSColor redColor], + [NSColor yellowColor], + [NSColor greenColor], + [NSColor cyanColor], + [NSColor blueColor], + [NSColor magentaColor], + [NSColor redColor], + ]]; + + rect.origin.y += rect.size.height / 2 - 0.5; + rect.size.height = 1; + rect.size.width -= 2; + rect.origin.x += 1; + [[NSColor redColor] set]; + NSRectFill(rect); + + rect.size.width -= self.knobThickness + 2; + rect.origin.x += self.knobThickness / 2 - 1; + + [gradient drawInRect:rect angle:0]; +} + +@end + +@implementation NSSlider (GBHueSlider) +- (NSColor *)colorValue +{ + return ((GBHueSliderCell *)self.cell).colorValue; +} +@end diff --git a/Cocoa/GBPaletteEditorController.h b/Cocoa/GBPaletteEditorController.h new file mode 100644 index 0000000..fd362ec --- /dev/null +++ b/Cocoa/GBPaletteEditorController.h @@ -0,0 +1,18 @@ +#import +#import + +@interface GBPaletteEditorController : NSObject +@property (weak) IBOutlet NSColorWell *colorWell0; +@property (weak) IBOutlet NSColorWell *colorWell1; +@property (weak) IBOutlet NSColorWell *colorWell2; +@property (weak) IBOutlet NSColorWell *colorWell3; +@property (weak) IBOutlet NSColorWell *colorWell4; +@property (weak) IBOutlet NSButton *disableLCDColorCheckbox; +@property (weak) IBOutlet NSButton *manualModeCheckbox; +@property (weak) IBOutlet NSSlider *brightnessSlider; +@property (weak) IBOutlet NSSlider *hueSlider; +@property (weak) IBOutlet NSSlider *hueStrengthSlider; +@property (weak) IBOutlet NSTableView *themesList; +@property (weak) IBOutlet NSMenu *menu; ++ (const GB_palette_t *)userPalette; +@end diff --git a/Cocoa/GBPaletteEditorController.m b/Cocoa/GBPaletteEditorController.m new file mode 100644 index 0000000..5df4aef --- /dev/null +++ b/Cocoa/GBPaletteEditorController.m @@ -0,0 +1,378 @@ +#import "GBPaletteEditorController.h" +#import "GBHueSliderCell.h" +#import + +#define MAGIC 'SBPL' + +typedef struct __attribute__ ((packed)) { + uint32_t magic; + bool manual:1; + bool disabled_lcd_color:1; + unsigned padding:6; + struct GB_color_s colors[5]; + int32_t brightness_bias; + uint32_t hue_bias; + uint32_t hue_bias_strength; +} theme_t; + +static double blend(double from, double to, double position) +{ + return from * (1 - position) + to * position; +} + +@implementation NSColor (GBColor) + +- (struct GB_color_s)gbColor +{ + NSColor *sRGB = [self colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]; + return (struct GB_color_s){round(sRGB.redComponent * 255), round(sRGB.greenComponent * 255), round(sRGB.blueComponent * 255)}; +} + +- (uint32_t)intValue +{ + struct GB_color_s color = self.gbColor; + return (color.r << 0) | (color.g << 8) | (color.b << 16) | 0xFF000000; +} + +@end + +@implementation GBPaletteEditorController + +- (NSArray *)colorWells +{ + return @[_colorWell0, _colorWell1, _colorWell2, _colorWell3, _colorWell4]; +} + +- (void)updateEnabledControls +{ + if (self.manualModeCheckbox.state) { + _brightnessSlider.enabled = false; + _hueSlider.enabled = false; + _hueStrengthSlider.enabled = false; + _colorWell1.enabled = true; + _colorWell2.enabled = true; + _colorWell3.enabled = true; + if (!(_colorWell4.enabled = self.disableLCDColorCheckbox.state)) { + _colorWell4.color = _colorWell3.color; + } + } + else { + _colorWell1.enabled = false; + _colorWell2.enabled = false; + _colorWell3.enabled = false; + _colorWell4.enabled = true; + _brightnessSlider.enabled = true; + _hueSlider.enabled = true; + _hueStrengthSlider.enabled = true; + [self updateAutoColors]; + } +} + +- (NSColor *)autoColorAtPositon:(double)position +{ + NSColor *first = [_colorWell0.color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]; + NSColor *second = [_colorWell4.color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]; + double brightness = 1 / pow(4, (_brightnessSlider.doubleValue - 128) / 128.0); + position = pow(position, brightness); + NSColor *hue = _hueSlider.colorValue; + double bias = _hueStrengthSlider.doubleValue / 256.0; + double red = 1 / pow(4, (hue.redComponent * 2 - 1) * bias); + double green = 1 / pow(4, (hue.greenComponent * 2 - 1) * bias); + double blue = 1 / pow(4, (hue.blueComponent * 2 - 1) * bias); + NSColor *ret = [NSColor colorWithRed:blend(first.redComponent, second.redComponent, pow(position, red)) + green:blend(first.greenComponent, second.greenComponent, pow(position, green)) + blue:blend(first.blueComponent, second.blueComponent, pow(position, blue)) + alpha:1.0]; + return ret; +} + +- (IBAction)updateAutoColors:(id)sender +{ + if (!self.manualModeCheckbox.state) { + [self updateAutoColors]; + } + else { + [self savePalette:sender]; + } +} + +- (void)updateAutoColors +{ + if (_disableLCDColorCheckbox.state) { + _colorWell1.color = [self autoColorAtPositon:8 / 25.0]; + _colorWell2.color = [self autoColorAtPositon:16 / 25.0]; + _colorWell3.color = [self autoColorAtPositon:24 / 25.0]; + } + else { + _colorWell1.color = [self autoColorAtPositon:1 / 3.0]; + _colorWell2.color = [self autoColorAtPositon:2 / 3.0]; + _colorWell3.color = _colorWell4.color; + } + [self savePalette:nil]; +} + +- (IBAction)disabledLCDColorCheckboxChanged:(id)sender +{ + [self updateEnabledControls]; +} + +- (IBAction)manualModeChanged:(id)sender +{ + [self updateEnabledControls]; +} + +- (IBAction)updateColor4:(id)sender +{ + if (!self.disableLCDColorCheckbox.state) { + self.colorWell4.color = self.colorWell3.color; + } + [self savePalette:self]; +} + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *themes = [defaults dictionaryForKey:@"GBThemes"]; + if (themes.count == 0) { + [defaults setObject:@"Untitled Palette" forKey:@"GBCurrentTheme"]; + [self savePalette:nil]; + return 1; + } + return themes.count; +} + +-(void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSString *oldName = [self tableView:tableView objectValueForTableColumn:tableColumn row:row]; + if ([oldName isEqualToString:object]) { + return; + } + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSMutableDictionary *themes = [[defaults dictionaryForKey:@"GBThemes"] ?: @[] mutableCopy]; + NSString *newName = object; + unsigned i = 2; + if (!newName.length) { + newName = @"Untitled Palette"; + } + while (themes[newName]) { + newName = [NSString stringWithFormat:@"%@ %d", object, i]; + } + themes[newName] = themes[oldName]; + [themes removeObjectForKey:oldName]; + if ([oldName isEqualToString:[defaults stringForKey:@"GBCurrentTheme"]]) { + [defaults setObject:newName forKey:@"GBCurrentTheme"]; + } + [defaults setObject:themes forKey:@"GBThemes"]; + [tableView reloadData]; + [self awakeFromNib]; +} + +- (IBAction)deleteTheme:(id)sender +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *name = [defaults stringForKey:@"GBCurrentTheme"]; + NSMutableDictionary *themes = [[defaults dictionaryForKey:@"GBThemes"] ?: @[] mutableCopy]; + [themes removeObjectForKey:name]; + [defaults setObject:themes forKey:@"GBThemes"]; + [_themesList reloadData]; + [self awakeFromNib]; +} + +- (void)tableViewSelectionDidChange:(NSNotification *)notification +{ + NSString *name = [self tableView:nil objectValueForTableColumn:nil row:_themesList.selectedRow]; + [[NSUserDefaults standardUserDefaults] setObject:name forKey:@"GBCurrentTheme"]; + [self loadPalette]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorPaletteChanged" object:nil]; +} + +- (void)tableViewSelectionIsChanging:(NSNotification *)notification +{ + [self tableViewSelectionDidChange:notification]; +} + +- (void)awakeFromNib +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *themes = [defaults dictionaryForKey:@"GBThemes"]; + NSString *theme = [defaults stringForKey:@"GBCurrentTheme"]; + if (theme && themes[theme]) { + unsigned index = [[themes.allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] indexOfObject:theme]; + [_themesList selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:false]; + } + else { + [_themesList selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:false]; + } + [self tableViewSelectionDidChange:nil]; +} + +- (IBAction)addTheme:(id)sender +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *themes = [defaults dictionaryForKey:@"GBThemes"]; + NSString *newName = @"Untitled Palette"; + unsigned i = 2; + while (themes[newName]) { + newName = [NSString stringWithFormat:@"Untitled Palette %d", i++]; + } + [defaults setObject:newName forKey:@"GBCurrentTheme"]; + [self savePalette:sender]; + [_themesList reloadData]; + [self awakeFromNib]; +} + +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *themes = [defaults dictionaryForKey:@"GBThemes"]; + return [themes.allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)][row]; +} + +- (void)loadPalette +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *theme = [defaults dictionaryForKey:@"GBThemes"][[defaults stringForKey:@"GBCurrentTheme"]]; + NSArray *colors = theme[@"Colors"]; + if (colors.count == 5) { + unsigned i = 0; + for (NSNumber *color in colors) { + uint32_t c = [color unsignedIntValue]; + self.colorWells[i++].color = [NSColor colorWithRed:(c & 0xFF) / 255.0 + green:((c >> 8) & 0xFF) / 255.0 + blue:((c >> 16) & 0xFF) / 255.0 + alpha:1.0]; + } + } + _disableLCDColorCheckbox.state = [theme[@"DisabledLCDColor"] boolValue]; + _manualModeCheckbox.state = [theme[@"Manual"] boolValue]; + _brightnessSlider.doubleValue = [theme[@"BrightnessBias"] doubleValue] * 128 + 128; + _hueSlider.doubleValue = [theme[@"HueBias"] doubleValue] * 360; + _hueStrengthSlider.doubleValue = [theme[@"HueBiasStrength"] doubleValue] * 256; + [self updateEnabledControls]; +} + +- (IBAction)savePalette:(id)sender +{ + NSDictionary *theme = @{ + @"Colors": + @[@(_colorWell0.color.intValue), + @(_colorWell1.color.intValue), + @(_colorWell2.color.intValue), + @(_colorWell3.color.intValue), + @(_colorWell4.color.intValue)], + @"DisabledLCDColor": _disableLCDColorCheckbox.state? @YES : @NO, + @"Manual": _manualModeCheckbox.state? @YES : @NO, + @"BrightnessBias": @((_brightnessSlider.doubleValue - 128) / 128.0), + @"HueBias": @(_hueSlider.doubleValue / 360.0), + @"HueBiasStrength": @(_hueStrengthSlider.doubleValue / 256.0) + }; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSMutableDictionary *themes = [[defaults dictionaryForKey:@"GBThemes"] ?: @[] mutableCopy]; + themes[[defaults stringForKey:@"GBCurrentTheme"]] = theme; + [defaults setObject:themes forKey:@"GBThemes"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorPaletteChanged" object:nil]; +} + ++ (const GB_palette_t *)userPalette +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + switch ([defaults integerForKey:@"GBColorPalette"]) { + case 1: return &GB_PALETTE_DMG; + case 2: return &GB_PALETTE_MGB; + case 3: return &GB_PALETTE_GBL; + default: return &GB_PALETTE_GREY; + case -1: { + static GB_palette_t customPalette; + NSArray *colors = [defaults dictionaryForKey:@"GBThemes"][[defaults stringForKey:@"GBCurrentTheme"]][@"Colors"]; + if (colors.count == 5) { + unsigned i = 0; + for (NSNumber *color in colors) { + uint32_t c = [color unsignedIntValue]; + customPalette.colors[i++] = (struct GB_color_s) {c, c >> 8, c >> 16}; + } + } + return &customPalette; + } + } +} + +- (IBAction)export:(id)sender +{ + NSSavePanel *savePanel = [NSSavePanel savePanel]; + [savePanel setAllowedFileTypes:@[@"sbp"]]; + savePanel.nameFieldStringValue = [NSString stringWithFormat:@"%@.sbp", [[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"]]; + if ([savePanel runModal] == NSModalResponseOK) { + theme_t theme = {0,}; + theme.magic = MAGIC; + theme.manual = _manualModeCheckbox.state; + theme.disabled_lcd_color = _disableLCDColorCheckbox.state; + unsigned i = 0; + for (NSColorWell *well in self.colorWells) { + theme.colors[i++] = well.color.gbColor; + } + theme.brightness_bias = (_brightnessSlider.doubleValue - 128) * (0x40000000 / 128); + theme.hue_bias = round(_hueSlider.doubleValue * (0x80000000 / 360.0)); + theme.hue_bias_strength = (_hueStrengthSlider.doubleValue) * (0x80000000 / 256); + size_t size = sizeof(theme); + if (theme.manual) { + size = theme.disabled_lcd_color? 5 + 5 * sizeof(theme.colors[0]) : 5 + 4 * sizeof(theme.colors[0]); + } + [[NSData dataWithBytes:&theme length:size] writeToURL:savePanel.URL atomically:false]; + } +} + +- (IBAction)import:(id)sender +{ + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + [openPanel setAllowedFileTypes:@[@"sbp"]]; + if ([openPanel runModal] == NSModalResponseOK) { + NSData *data = [NSData dataWithContentsOfURL:openPanel.URL]; + theme_t theme = {0,}; + memcpy(&theme, data.bytes, MIN(sizeof(theme), data.length)); + if (theme.magic != MAGIC) { + NSBeep(); + return; + } + _manualModeCheckbox.state = theme.manual; + _disableLCDColorCheckbox.state = theme.disabled_lcd_color; + unsigned i = 0; + for (NSColorWell *well in self.colorWells) { + well.color = [NSColor colorWithRed:theme.colors[i].r / 255.0 + green:theme.colors[i].g / 255.0 + blue:theme.colors[i].b / 255.0 + alpha:1.0]; + i++; + } + if (!theme.disabled_lcd_color) { + _colorWell4.color = _colorWell3.color; + } + _brightnessSlider.doubleValue = theme.brightness_bias / (0x40000000 / 128.0) + 128; + _hueSlider.doubleValue = theme.hue_bias / (0x80000000 / 360.0); + _hueStrengthSlider.doubleValue = theme.hue_bias_strength / (0x80000000 / 256.0); + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *themes = [defaults dictionaryForKey:@"GBThemes"]; + NSString *baseName = openPanel.URL.lastPathComponent.stringByDeletingPathExtension; + NSString *newName = baseName; + i = 2; + while (themes[newName]) { + newName = [NSString stringWithFormat:@"%@ %d", baseName, i++]; + } + [defaults setObject:newName forKey:@"GBCurrentTheme"]; + [self savePalette:sender]; + [self awakeFromNib]; + } +} + +- (IBAction)done:(NSButton *)sender +{ + [sender.window.sheetParent endSheet:sender.window]; +} + +- (instancetype)init +{ + static id singleton = nil; + if (singleton) return singleton; + return (singleton = [super init]); +} +@end diff --git a/Cocoa/GBPreferencesWindow.h b/Cocoa/GBPreferencesWindow.h index e11c5d3..355dc6e 100644 --- a/Cocoa/GBPreferencesWindow.h +++ b/Cocoa/GBPreferencesWindow.h @@ -1,5 +1,6 @@ #import #import +#import "GBPaletteEditorController.h" @interface GBPreferencesWindow : NSWindow @property (nonatomic, strong) IBOutlet NSTableView *controlsTableView; @@ -29,4 +30,6 @@ @property (weak) IBOutlet NSSlider *volumeSlider; @property (weak) IBOutlet NSButton *OSDCheckbox; @property (weak) IBOutlet NSButton *screenshotFilterCheckbox; +@property (weak) IBOutlet GBPaletteEditorController *paletteEditorController; +@property (strong) IBOutlet NSWindow *paletteEditor; @end diff --git a/Cocoa/GBPreferencesWindow.m b/Cocoa/GBPreferencesWindow.m index 60df2dd..e1f9fc0 100644 --- a/Cocoa/GBPreferencesWindow.m +++ b/Cocoa/GBPreferencesWindow.m @@ -153,8 +153,14 @@ - (void)setColorPalettePopupButton:(NSPopUpButton *)colorPalettePopupButton { _colorPalettePopupButton = colorPalettePopupButton; + [self updatePalettesMenu]; NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"]; - [_colorPalettePopupButton selectItemAtIndex:mode]; + if (mode >= 0) { + [_colorPalettePopupButton selectItemWithTag:mode]; + } + else { + [_colorPalettePopupButton selectItemWithTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"] ?: @""]; + } } - (NSPopUpButton *)colorPalettePopupButton @@ -366,10 +372,51 @@ } +- (void)updatePalettesMenu +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDictionary *themes = [defaults dictionaryForKey:@"GBThemes"]; + NSMenu *menu = _colorPalettePopupButton.menu; + while (menu.itemArray.count != 4) { + [menu removeItemAtIndex:4]; + } + [menu addItem:[NSMenuItem separatorItem]]; + for (NSString *name in [themes.allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:name action:nil keyEquivalent:@""]; + item.tag = -2; + [menu addItem:item]; + } + if (themes) { + [menu addItem:[NSMenuItem separatorItem]]; + } + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Custom…" action:nil keyEquivalent:@""]; + item.tag = -1; + [menu addItem:item]; +} + - (IBAction)colorPaletteChanged:(id)sender { - [[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem]) - forKey:@"GBColorPalette"]; + signed tag = [sender selectedItem].tag; + if (tag == -2) { + [[NSUserDefaults standardUserDefaults] setObject:@(-1) + forKey:@"GBColorPalette"]; + [[NSUserDefaults standardUserDefaults] setObject:[sender selectedItem].title + forKey:@"GBCurrentTheme"]; + + } + else if (tag == -1) { + [[NSUserDefaults standardUserDefaults] setObject:@(-1) + forKey:@"GBColorPalette"]; + [_paletteEditorController awakeFromNib]; + [self beginSheet:_paletteEditor completionHandler:^(NSModalResponse returnCode) { + [self updatePalettesMenu]; + [_colorPalettePopupButton selectItemWithTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"] ?: @""]; + }]; + } + else { + [[NSUserDefaults standardUserDefaults] setObject:@([sender selectedItem].tag) + forKey:@"GBColorPalette"]; + } [[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorPaletteChanged" object:nil]; } diff --git a/Cocoa/Preferences.xib b/Cocoa/Preferences.xib index 67e57b1..c9fb8ce 100644 --- a/Cocoa/Preferences.xib +++ b/Cocoa/Preferences.xib @@ -85,6 +85,8 @@ + + @@ -257,9 +259,9 @@ - - - + + + @@ -319,7 +321,7 @@ - + @@ -579,7 +581,7 @@ - + @@ -608,7 +610,7 @@ - + @@ -770,7 +772,7 @@ - + @@ -803,14 +805,262 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/gb.h b/Core/gb.h index bd0fa83..636d98e 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -81,7 +81,7 @@ #endif typedef struct { - struct { + struct GB_color_s { uint8_t r, g, b; } colors[5]; } GB_palette_t;