Move the palette picker to its own class

This commit is contained in:
Lior Halphon 2024-09-19 21:02:59 +03:00
parent 2aa4726e01
commit 8ded1ca3b3
5 changed files with 155 additions and 93 deletions

7
iOS/GBPalettePicker.h Normal file
View File

@ -0,0 +1,7 @@
#import <UIKit/UIKit.h>
#import <Core/gb.h>
@interface GBPalettePicker : UITableViewController
+ (const GB_palette_t *)paletteForTheme:(NSString *)theme;
@end

132
iOS/GBPalettePicker.m Normal file
View File

@ -0,0 +1,132 @@
#import "GBPalettePicker.h"
@interface GBPalettePicker ()
{
NSArray <NSString *>* _cacheNames;
}
@end
@implementation GBPalettePicker
+ (const GB_palette_t *)paletteForTheme:(NSString *)theme
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([theme isEqualToString:@"Greyscale"]) {
return &GB_PALETTE_GREY;
}
if ([theme isEqualToString:@"Lime (Game Boy)"]) {
return &GB_PALETTE_DMG;
}
if ([theme isEqualToString:@"Olive (Pocket)"]) {
return &GB_PALETTE_MGB;
}
if ([theme isEqualToString:@"Teal (Light)"]) {
return &GB_PALETTE_GBL;
}
static GB_palette_t customPalette;
NSArray *colors = [defaults dictionaryForKey:@"GBThemes"][theme][@"Colors"];
if (colors.count != 5) return &GB_PALETTE_DMG;
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;
}
+ (UIColor *)colorFromGBColor:(const struct GB_color_s *)color
{
return [UIColor colorWithRed:color->r / 255.0
green:color->g / 255.0
blue:color->b / 255.0
alpha:1.0];
}
+ (UIImage *)previewImageForTheme:(NSString *)theme
{
const GB_palette_t *palette = [self paletteForTheme:theme];
UIGraphicsBeginImageContextWithOptions((CGSize){29, 29}, false, [UIScreen mainScreen].scale);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 29, 29) cornerRadius:7];
[[self colorFromGBColor:&palette->colors[4]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(4, 4, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[0]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(16, 4, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[1]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(4, 16, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[2]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(16, 16, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[3]] set];
[path fill];
UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return ret;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) return 4;
return [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBThemes"].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
NSString *name = nil;
if (indexPath.section == 0) {
name = @[
@"Greyscale",
@"Lime (Game Boy)",
@"Olive (Pocket)",
@"Teal (Light)",
][indexPath.row];
}
else {
if (!_cacheNames) {
_cacheNames = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBThemes"].allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}
name = _cacheNames[indexPath.row];
}
cell.textLabel.text = name;
if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"] isEqual:name]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
cell.imageView.image = [self.class previewImageForTheme:name];
return cell;
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[NSUserDefaults standardUserDefaults] setObject:[self.tableView cellForRowAtIndexPath:indexPath].textLabel.text
forKey:@"GBCurrentTheme"];
[self.tableView reloadData];
return nil;
}
- (NSString *)title
{
return @"Monochrome Palette";
}
@end

View File

@ -25,7 +25,6 @@ typedef enum {
@interface GBSettingsViewController : UITableViewController
+ (UIViewController *)settingsViewControllerWithLeftButton:(UIBarButtonItem *)button;
+ (const GB_palette_t *)paletteForTheme:(NSString *)theme;
+ (GBButton)controller:(GCController *)controller convertUsageToButton:(GBControllerUsage)usage;
+ (GBTheme *)themeNamed:(NSString *)name;
@end

View File

@ -2,6 +2,7 @@
#import "GBTemperatureSlider.h"
#import "GBViewBase.h"
#import "GBThemesViewController.h"
#import "GBPalettePicker.h"
#import "GBHapticManager.h"
#import "GCExtendedGamepad+AllElements.h"
#import <objc/runtime.h>
@ -23,95 +24,6 @@ static NSString const *typeLightTemp = @"typeLightTemp";
NSArray<NSArray<GBTheme *> *> *_themes; // For prewarming
}
+ (const GB_palette_t *)paletteForTheme:(NSString *)theme
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([theme isEqualToString:@"Greyscale"]) {
return &GB_PALETTE_GREY;
}
if ([theme isEqualToString:@"Lime (Game Boy)"]) {
return &GB_PALETTE_DMG;
}
if ([theme isEqualToString:@"Olive (Pocket)"]) {
return &GB_PALETTE_MGB;
}
if ([theme isEqualToString:@"Teal (Light)"]) {
return &GB_PALETTE_GBL;
}
static GB_palette_t customPalette;
NSArray *colors = [defaults dictionaryForKey:@"GBThemes"][theme][@"Colors"];
if (colors.count != 5) return &GB_PALETTE_DMG;
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;
}
+ (UIColor *) colorFromGBColor:(const struct GB_color_s *)color
{
return [UIColor colorWithRed:color->r / 255.0
green:color->g / 255.0
blue:color->b / 255.0
alpha:1.0];
}
+ (UIImage *)previewImageForTheme:(NSString *)theme
{
const GB_palette_t *palette = [self paletteForTheme:theme];
UIGraphicsBeginImageContextWithOptions((CGSize){29, 29}, false, [UIScreen mainScreen].scale);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 29, 29) cornerRadius:7];
[[self colorFromGBColor:&palette->colors[4]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(4, 4, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[0]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(16, 4, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[1]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(4, 16, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[2]] set];
[path fill];
path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(16, 16, 9, 9) cornerRadius:2];
[[self colorFromGBColor:&palette->colors[3]] set];
[path fill];
UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return ret;
}
+ (NSArray<NSDictionary *> *)paletteMenu
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *themes = [@[
@"Greyscale",
@"Lime (Game Boy)",
@"Olive (Pocket)",
@"Teal (Light)",
] arrayByAddingObjectsFromArray:[[defaults dictionaryForKey:@"GBThemes"] allKeys]];
NSMutableArray<NSDictionary *> *themeItems = [NSMutableArray arrayWithCapacity:themes.count];
for (NSString *theme in themes) {
[themeItems addObject: @{@"type": typeRadio, @"pref": @"GBCurrentTheme",
@"title": theme, @"value": theme,
@"image": [self previewImageForTheme:theme]}];
}
return @[
@{
@"items": [themeItems subarrayWithRange:(NSRange){0, 4}]
},
@{
@"items": [themeItems subarrayWithRange:(NSRange){4, themeItems.count - 4}]
}
];
}
+ (NSArray<NSDictionary *> *)rootStructure
{
#define QUICK_SUBMENU(title, ...) @{@"type": typeOptionSubmenu, @"title": title, @"submenu": @[@{@"items": __VA_ARGS__}]}
@ -306,8 +218,16 @@ static NSString const *typeLightTemp = @"typeLightTemp";
@{
@"items": @[@{
@"title": @"Monochrome Palette",
@"type": typeOptionSubmenu,
@"submenu": [self paletteMenu]
@"type": typeBlock,
@"block": ^bool(GBSettingsViewController *controller) {
UITableViewStyle style = UITableViewStyleGrouped;
if (@available(iOS 13.0, *)) {
style = UITableViewStyleInsetGrouped;
}
[controller.navigationController pushViewController:[[GBPalettePicker alloc] initWithStyle:style] animated:true];
return true;
},
@"pref": @"GBCurrentTheme",
}],
@"footer": @"This palette will be used when emulating a monochrome model such as the original Game Boy."
}
@ -791,6 +711,9 @@ static id ValueForItem(NSDictionary *item)
}
}
}
else if (item[@"pref"]) {
cell.detailTextLabel.text = [[NSUserDefaults standardUserDefaults] stringForKey:item[@"pref"]];
}
}
else if (item[@"type"] == typeRadio) {
if ([ValueForItem(item) isEqual:item[@"value"]]) {

View File

@ -11,6 +11,7 @@
#import "GBOptionViewController.h"
#import "GBAboutController.h"
#import "GBSettingsViewController.h"
#import "GBPalettePicker.h"
#import "GBStatesViewController.h"
#import "GBCheckableAlertController.h"
#import "GBPrinterFeedController.h"
@ -1294,7 +1295,7 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
- (void)updatePalette
{
memcpy(&_palette,
[GBSettingsViewController paletteForTheme:[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"]],
[GBPalettePicker paletteForTheme:[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"]],
sizeof(_palette));
GB_set_palette(&_gb, &_palette);
}