SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit 178860e71580646530e95bbb90abbe3a32689664 parent f237b1e9b9ebec2089239c10b8efbb228f9ae26f Author: Lior Halphon <LIJI32@gmail.com> Date: Fri, 5 Nov 2021 19:07:27 +0200 Custom palette and editor Diffstat:
| M | Cocoa/Document.m | 21 | +++------------------ |
| A | Cocoa/GBHueSliderCell.h | 9 | +++++++++ |
| A | Cocoa/GBHueSliderCell.m | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | Cocoa/GBPaletteEditorController.h | 18 | ++++++++++++++++++ |
| A | Cocoa/GBPaletteEditorController.m | 378 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | Cocoa/GBPreferencesWindow.h | 3 | +++ |
| M | Cocoa/GBPreferencesWindow.m | 53 | ++++++++++++++++++++++++++++++++++++++++++++++++++--- |
| M | Cocoa/Preferences.xib | 266 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
| M | Core/gb.h | 2 | +- |
9 files changed, 833 insertions(+), 30 deletions(-)
diff --git 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 @@ -0,0 +1,9 @@ +#import <Cocoa/Cocoa.h> + +@interface NSSlider (GBHueSlider) +-(NSColor *)colorValue; +@end + +@interface GBHueSliderCell : NSSliderCell +-(NSColor *)colorValue; +@end diff --git a/Cocoa/GBHueSliderCell.m 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 @@ -0,0 +1,18 @@ +#import <AppKit/AppKit.h> +#import <Core/gb.h> + +@interface GBPaletteEditorController : NSObject<NSTableViewDataSource, NSTableViewDelegate> +@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 @@ -0,0 +1,378 @@ +#import "GBPaletteEditorController.h" +#import "GBHueSliderCell.h" +#import <Core/gb.h> + +#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<NSColorWell *> *)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 @@ -1,5 +1,6 @@ #import <Cocoa/Cocoa.h> #import <JoyKit/JoyKit.h> +#import "GBPaletteEditorController.h" @interface GBPreferencesWindow : NSWindow <NSTableViewDelegate, NSTableViewDataSource, JOYListener> @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 @@ -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 @@ -85,6 +85,8 @@ <outlet property="graphicsFilterPopupButton" destination="6pP-kK-EEC" id="LS7-HY-kHC"/> <outlet property="highpassFilterPopupButton" destination="T69-6N-dhT" id="0p6-4m-hb1"/> <outlet property="interferenceSlider" destination="FpE-5i-j5L" id="hfH-e8-7cx"/> + <outlet property="paletteEditor" destination="g32-xe-7al" id="WLk-Hh-h5v"/> + <outlet property="paletteEditorController" destination="Zxl-vm-6c9" id="uPS-zn-osL"/> <outlet property="playerListButton" destination="gWx-7h-0xq" id="zo6-82-JId"/> <outlet property="preferredJoypadButton" destination="0Az-0R-oNw" id="7JM-tw-BhK"/> <outlet property="rewindPopupButton" destination="7fg-Ww-JjR" id="Ka2-TP-B1x"/> @@ -257,9 +259,9 @@ <menuItem title="Greyscale" state="on" id="Ajr-5r-iIk"> <modifierMask key="keyEquivalentModifierMask"/> </menuItem> - <menuItem title="Lime (Game Boy)" id="snU-ht-fQq"/> - <menuItem title="Olive (Pocket)" id="MQi-yt-nsT"/> - <menuItem title="Teal (Light)" id="xlg-6i-Fhl"/> + <menuItem title="Lime (Game Boy)" tag="1" id="snU-ht-fQq"/> + <menuItem title="Olive (Pocket)" tag="2" id="MQi-yt-nsT"/> + <menuItem title="Teal (Light)" tag="3" id="xlg-6i-Fhl"/> </items> </menu> </popUpButtonCell> @@ -319,7 +321,7 @@ </connections> </button> </subviews> - <point key="canvasLocation" x="-176" y="690.5"/> + <point key="canvasLocation" x="-501" y="236.5"/> </customView> <customView id="ymk-46-SX7"> <rect key="frame" x="0.0" y="0.0" width="320" height="375"/> @@ -579,7 +581,7 @@ </connections> </slider> </subviews> - <point key="canvasLocation" x="-825" y="455.5"/> + <point key="canvasLocation" x="-854" y="627"/> </customView> <customView id="8TU-6J-NCg"> <rect key="frame" x="0.0" y="0.0" width="320" height="467"/> @@ -608,7 +610,7 @@ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <clipView key="contentView" focusRingType="none" ambiguous="YES" drawsBackground="NO" id="AMs-PO-nid"> <rect key="frame" x="1" y="1" width="255" height="209"/> - <autoresizingMask key="autoresizingMask"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" id="UDd-IJ-fxX"> <rect key="frame" x="0.0" y="0.0" width="255" height="209"/> @@ -770,7 +772,7 @@ </connections> </button> </subviews> - <point key="canvasLocation" x="-159" y="1161.5"/> + <point key="canvasLocation" x="-854" y="260"/> </customView> <customView id="ffn-ie-9C3"> <rect key="frame" x="0.0" y="0.0" width="320" height="95"/> @@ -803,14 +805,262 @@ </connections> </button> </subviews> - <point key="canvasLocation" x="-825" y="699.5"/> + <point key="canvasLocation" x="-854" y="808"/> </customView> + <window title="Palette Editor" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="g32-xe-7al"> + <windowStyleMask key="styleMask" titled="YES" closable="YES"/> + <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> + <rect key="contentRect" x="283" y="305" width="467" height="341"/> + <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/> + <view key="contentView" id="uMa-Yg-exg"> + <rect key="frame" x="0.0" y="0.0" width="467" height="341"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <scrollView focusRingType="none" fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DPL-nH-GVw"> + <rect key="frame" x="-1" y="24" width="160" height="318"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES"/> + <clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="5Al-aC-tq8"> + <rect key="frame" x="1" y="1" width="158" height="316"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <tableView focusRingType="none" verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" id="ZVn-bk-duk"> + <rect key="frame" x="0.0" y="0.0" width="158" height="316"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <size key="intercellSpacing" width="3" height="2"/> + <color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/> + <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> + <tableColumns> + <tableColumn width="155" minWidth="40" maxWidth="1000" id="qZn-U2-gsp"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> + </tableHeaderCell> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="K1k-hc-zcx"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + </tableColumn> + </tableColumns> + <connections> + <outlet property="dataSource" destination="Zxl-vm-6c9" id="Qpu-7V-i4Q"/> + <outlet property="delegate" destination="Zxl-vm-6c9" id="FoY-pT-glW"/> + </connections> + </tableView> + </subviews> + <nil key="backgroundColor"/> + </clipView> + <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="zn7-g9-fNo"> + <rect key="frame" x="1" y="274" width="158" height="16"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="fa0-wo-kQe"> + <rect key="frame" x="224" y="17" width="15" height="102"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + </scrollView> + <colorWell focusRingType="none" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="odC-WD-uUp"> + <rect key="frame" x="167" y="266" width="55" height="55"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <color key="color" red="0.03129877895116806" green="0.094370834529399872" blue="0.062739767134189606" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + <connections> + <action selector="updateAutoColors:" target="Zxl-vm-6c9" id="wmS-sP-YVR"/> + </connections> + </colorWell> + <colorWell focusRingType="none" fixedFrame="YES" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="mpV-pm-9ZF"> + <rect key="frame" x="222" y="266" width="55" height="55"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <color key="color" red="0.22354039549827576" green="0.38156121969223022" blue="0.22349703311920166" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + <connections> + <action selector="savePalette:" target="Zxl-vm-6c9" id="Ejl-bb-Vd8"/> + </connections> + </colorWell> + <colorWell focusRingType="none" fixedFrame="YES" tag="2" translatesAutoresizingMaskIntoConstraints="NO" id="NEt-gu-zL7"> + <rect key="frame" x="277" y="266" width="55" height="55"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <color key="color" red="0.51789730787277222" green="0.64901769161224365" blue="0.38817742466926575" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + <connections> + <action selector="savePalette:" target="Zxl-vm-6c9" id="lle-OO-YK2"/> + </connections> + </colorWell> + <colorWell focusRingType="none" fixedFrame="YES" tag="3" translatesAutoresizingMaskIntoConstraints="NO" id="fVn-3k-iuN"> + <rect key="frame" x="332" y="266" width="55" height="55"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <color key="color" red="0.77688723802566528" green="0.87309378385543823" blue="0.54894673824310303" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + <connections> + <action selector="updateColor4:" target="Zxl-vm-6c9" id="riQ-Kc-wcG"/> + </connections> + </colorWell> + <colorWell focusRingType="none" fixedFrame="YES" tag="4" translatesAutoresizingMaskIntoConstraints="NO" id="min-mf-sjI"> + <rect key="frame" x="392" y="266" width="55" height="55"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <color key="color" red="0.82731041736199085" green="0.92976116399242459" blue="0.58457564096374282" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + <connections> + <action selector="updateAutoColors:" target="Zxl-vm-6c9" id="Oo4-Dx-wvS"/> + </connections> + </colorWell> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZUa-QG-4ss"> + <rect key="frame" x="167" y="243" width="282" height="18"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <buttonCell key="cell" type="check" title="Distinct disabled LCD color" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="cRR-vH-5R2"> + <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="disabledLCDColorCheckboxChanged:" target="Zxl-vm-6c9" id="geJ-mH-o6c"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="l33-w0-rLw"> + <rect key="frame" x="167" y="221" width="277" height="18"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <buttonCell key="cell" type="check" title="Manual mode" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Gvn-Rq-LU5"> + <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="manualModeChanged:" target="Zxl-vm-6c9" id="BAF-n1-CiQ"/> + </connections> + </button> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XFt-AQ-h4m"> + <rect key="frame" x="165" y="198" width="284" height="17"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Brightness bias:" id="qhH-ls-JEl"> + <font key="font" metaFont="system"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wam-CT-owm"> + <rect key="frame" x="177" y="162" width="272" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <sliderCell key="cell" continuous="YES" enabled="NO" state="on" alignment="left" maxValue="256" doubleValue="128" tickMarkPosition="above" numberOfTickMarks="3" sliderType="linear" id="ktr-gF-oxu"/> + <connections> + <action selector="updateAutoColors:" target="Zxl-vm-6c9" id="Onm-Bw-sJu"/> + </connections> + </slider> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Dc6-NT-jgZ"> + <rect key="frame" x="167" y="139" width="282" height="17"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Hue bias:" id="GzN-2h-xBT"> + <font key="font" metaFont="system"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ImK-kc-EEn"> + <rect key="frame" x="177" y="105" width="272" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <sliderCell key="cell" continuous="YES" enabled="NO" state="on" alignment="left" maxValue="360" tickMarkPosition="above" sliderType="linear" id="2dt-f1-0bV" customClass="GBHueSliderCell"/> + <connections> + <action selector="updateAutoColors:" target="Zxl-vm-6c9" id="2OR-Nl-jrN"/> + </connections> + </slider> + <slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ij9-bn-1y8"> + <rect key="frame" x="177" y="48" width="272" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <sliderCell key="cell" continuous="YES" enabled="NO" state="on" alignment="left" maxValue="256" tickMarkPosition="above" sliderType="linear" id="4WJ-yV-tms"/> + <connections> + <action selector="updateAutoColors:" target="Zxl-vm-6c9" id="Hkn-HH-usp"/> + </connections> + </slider> + <box horizontalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="hcd-Iu-gEm"> + <rect key="frame" x="387" y="266" width="5" height="55"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + </box> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="t0j-uz-CIi"> + <rect key="frame" x="0.0" y="-1" width="32" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="61Q-ht-htH"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="addTheme:" target="Zxl-vm-6c9" id="lAZ-PU-7Rk"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1Qv-3A-Fy9"> + <rect key="frame" x="31" y="-1" width="32" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Qax-9H-bwb"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="deleteTheme:" target="Zxl-vm-6c9" id="nlR-Hp-4m9"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xtD-ub-MX7"> + <rect key="frame" x="62" y="-1" width="49" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="smallSquare" title="Export" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="RBw-u5-zpv"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="smallSystem"/> + </buttonCell> + <connections> + <action selector="export:" target="Zxl-vm-6c9" id="9Fg-bN-W6z"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2E2-qz-P8N"> + <rect key="frame" x="110" y="-1" width="49" height="28"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="smallSquare" title="Import" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="u9o-6G-fwU"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="smallSystem"/> + </buttonCell> + <connections> + <action selector="import:" target="Zxl-vm-6c9" id="OTl-HS-9Rt"/> + </connections> + </button> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="CZc-qZ-GLV"> + <rect key="frame" x="167" y="82" width="277" height="17"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Hue bias strength:" id="qLB-J6-2mT"> + <font key="font" metaFont="system"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tyc-KF-YTY"> + <rect key="frame" x="372.5" y="19" width="75" height="23"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="roundTextured" title="Close" bezelStyle="texturedRounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Vhg-3I-evG"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="done:" target="Zxl-vm-6c9" id="RKB-kM-yzA"/> + </connections> + </button> + </subviews> + </view> + <point key="canvasLocation" x="-62.5" y="222.5"/> + </window> + <customObject id="Zxl-vm-6c9" customClass="GBPaletteEditorController"> + <connections> + <outlet property="brightnessSlider" destination="Wam-CT-owm" id="8KP-J6-bwn"/> + <outlet property="colorWell0" destination="odC-WD-uUp" id="Ant-NL-9jb"/> + <outlet property="colorWell1" destination="mpV-pm-9ZF" id="ckr-ci-OFC"/> + <outlet property="colorWell2" destination="NEt-gu-zL7" id="Bzt-Fx-qLu"/> + <outlet property="colorWell3" destination="fVn-3k-iuN" id="7hN-Y8-efH"/> + <outlet property="colorWell4" destination="min-mf-sjI" id="5No-1R-X59"/> + <outlet property="disableLCDColorCheckbox" destination="ZUa-QG-4ss" id="Cn6-Ba-XOm"/> + <outlet property="hueSlider" destination="ImK-kc-EEn" id="bzo-ON-2bZ"/> + <outlet property="hueStrengthSlider" destination="ij9-bn-1y8" id="lcn-4q-27B"/> + <outlet property="manualModeCheckbox" destination="l33-w0-rLw" id="NBU-1I-UzJ"/> + <outlet property="menu" destination="dHJ-3R-Ora" id="SWT-qM-tca"/> + <outlet property="themesList" destination="ZVn-bk-duk" id="S4b-vM-ioi"/> + </connections> + </customObject> </objects> <resources> <image name="AppIcon" width="128" height="128"/> <image name="CPU" width="32" height="32"/> <image name="Display" width="32" height="32"/> <image name="Joypad" width="32" height="32"/> + <image name="NSAddTemplate" width="11" height="11"/> + <image name="NSRemoveTemplate" width="11" height="11"/> <image name="Speaker" width="32" height="32"/> </resources> </document> diff --git 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;
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.