X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=OSX%2FSaverListController.m;fp=OSX%2FSaverListController.m;h=7eadc95ec327ad0eab80bd99812bcc7934b7b6f8;hb=f8cf5ac7b2f53510f80a0eaf286a25298be17bfe;hp=0000000000000000000000000000000000000000;hpb=ec8d2b32b63649e6d32bdfb306eda062769af823;p=xscreensaver diff --git a/OSX/SaverListController.m b/OSX/SaverListController.m new file mode 100644 index 00000000..7eadc95e --- /dev/null +++ b/OSX/SaverListController.m @@ -0,0 +1,272 @@ +/* xscreensaver, Copyright (c) 2012 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * This implements the top-level screen-saver selection list in the iOS app. + */ + +#ifdef USE_IPHONE // whole file + + +#import "SaverListController.h" + +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + + +@implementation SaverListController + +- (id)initWithNames:(NSArray *)names descriptions:(NSDictionary *)descs; +{ + self = [self init]; + if (! self) return 0; + [self reload:names descriptions:descs]; + return self; +} + + +- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tv +{ + int n = countof(list_by_letter); + NSMutableArray *a = [NSMutableArray arrayWithCapacity: n]; + for (int i = 0; i < n; i++) { + char s[2]; + s[0] = (i == 'Z'-'A'+1 ? '#' : i+'A'); + s[1] = 0; + [a addObject: [NSString stringWithCString:s + encoding:NSASCIIStringEncoding]]; + } + return a; +} + + +- (void) reload:(NSArray *)names descriptions:(NSDictionary *)descs +{ + if (descriptions) + [descriptions release]; + descriptions = [descs retain]; + + int n = countof(list_by_letter); + for (int i = 0; i < n; i++) { + list_by_letter[i] = [[NSMutableArray alloc] init]; + } + + for (NSString *name in names) { + int index = ([name cStringUsingEncoding: NSASCIIStringEncoding])[0]; + if (index >= 'a' && index <= 'z') + index -= 'a'-'A'; + if (index >= 'A' && index <= 'Z') + index -= 'A'; + else + index = n-1; + [list_by_letter[index] addObject: name]; + } + + active_section_count = 0; + letter_sections = [[[NSMutableArray alloc] init] retain]; + section_titles = [[[NSMutableArray alloc] init] retain]; + for (int i = 0; i < n; i++) { + if ([list_by_letter[i] count] > 0) { + active_section_count++; + [letter_sections addObject: list_by_letter[i]]; + if (i <= 'Z'-'A') + [section_titles addObject: [NSString stringWithFormat: @"%c", i+'A']]; + else + [section_titles addObject: @"#"]; + } + } + [self.tableView reloadData]; +} + + +- (NSString *)tableView:(UITableView *)tv + titleForHeaderInSection:(NSInteger)section +{ + return [section_titles objectAtIndex: section]; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tv +{ + return active_section_count; +} + + +- (NSInteger)tableView:(UITableView *)tv + numberOfRowsInSection:(NSInteger)section +{ + return [[letter_sections objectAtIndex: section] count]; +} + +- (NSInteger)tableView:(UITableView *)tv + sectionForSectionIndexTitle:(NSString *)title + atIndex:(NSInteger) index +{ + int i = 0; + for (NSString *sectionTitle in section_titles) { + if ([sectionTitle isEqualToString: title]) + return i; + i++; + } + return -1; +} + + +- (UITableViewCell *)tableView:(UITableView *)tv + cellForRowAtIndexPath:(NSIndexPath *)ip +{ + NSString *id = + [[letter_sections objectAtIndex: [ip indexAtPosition: 0]] + objectAtIndex: [ip indexAtPosition: 1]]; + NSString *desc = [descriptions objectForKey:id]; + + UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier: id]; + if (!cell) { + cell = [[[UITableViewCell alloc] + initWithStyle: (desc + ? UITableViewCellStyleSubtitle + : UITableViewCellStyleDefault) + reuseIdentifier: id] + autorelease]; + cell.textLabel.text = id; + if (desc) + cell.detailTextLabel.text = desc; + } + return cell; +} + + +- (void)tapTimer:(NSTimer *)t +{ + [last_tap release]; + last_tap = 0; + tap_count = 0; + tap_timer = 0; +} + + +- (void)tableView:(UITableView *)tv + didSelectRowAtIndexPath:(NSIndexPath *)ip +{ + UITableViewCell *cell = [tv cellForRowAtIndexPath: ip]; + selected = cell.textLabel.text; + [self.navigationItem.leftBarButtonItem setEnabled: !!selected]; + [self.navigationItem.rightBarButtonItem setEnabled: !!selected]; + + if (tap_count == 0) { // First tap + tap_count = 1; + last_tap = [[ip copy] retain]; + tap_timer = [NSTimer scheduledTimerWithTimeInterval: 0.3 + target:self + selector:@selector(tapTimer:) + userInfo:nil + repeats:NO]; + + } else if (tap_count == 1 && tap_timer && // Second tap + [ip isEqual:last_tap]) { + [tap_timer invalidate]; + [last_tap release]; + last_tap = 0; + tap_timer = 0; + tap_count = 0; + + // Press the leftmost button in the button-bar. + UIBarButtonItem *b = self.navigationItem.leftBarButtonItem; + [[b target] performSelector: [b action] withObject: cell]; + + } else if (! [ip isEqual:last_tap]) { // Tap on a new row + if (tap_timer) [tap_timer invalidate]; + tap_timer = 0; + tap_count = 0; + } +} + + +/* We can't select a row immediately after creation, but selecting it + a little while later works (presumably after redisplay has happened) + so do it on a timer. + */ +- (void) scrollToCB: (NSTimer *) timer +{ + NSString *name = [timer userInfo]; + + int i = 0; + int j = 0; + Bool ok = NO; + for (NSArray *a in letter_sections) { + j = 0; + for (NSString *n in a) { + ok = [n isEqualToString: name]; + if (ok) goto DONE; + j++; + } + i++; + } + DONE: + if (ok) { + NSIndexPath *ip = [NSIndexPath indexPathForRow: j inSection: i]; + [self.tableView selectRowAtIndexPath:ip + animated:NO + scrollPosition: UITableViewScrollPositionMiddle]; + [self tableView:self.tableView didSelectRowAtIndexPath:ip]; + } +} + + +- (void) scrollTo: (NSString *) name +{ + [NSTimer scheduledTimerWithTimeInterval: 0 + target:self + selector:@selector(scrollToCB:) + userInfo:name + repeats:NO]; +} + + +- (void)viewWillAppear:(BOOL)animated +{ + /* Hitting the back button and returing to this view deselects, + and we can't re-select it from here, so again, do it once + we return to the event loop. + */ + if (selected) + [NSTimer scheduledTimerWithTimeInterval: 0 + target:self + selector:@selector(scrollToCB:) + userInfo:selected + repeats:NO]; + [super viewWillAppear:animated]; +} + + +- (NSString *) selected +{ + return selected; +} + + +- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o +{ + return YES; +} + + +- (void)dealloc +{ + for (int i = 0; i < countof(list_by_letter); i++) + [list_by_letter[i] release]; + [letter_sections release]; + [section_titles release]; + [descriptions release]; + [super dealloc]; +} + +@end + + +#endif // USE_IPHONE -- whole file