1 /* xscreensaver, Copyright (c) 2012 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * This implements the top-level screen-saver selection list in the iOS app.
14 #ifdef USE_IPHONE // whole file
17 #import "SaverListController.h"
18 #import "SaverRunner.h"
22 #define countof(x) (sizeof((x))/sizeof((*x)))
25 @implementation SaverListController
27 - (void) titleTapped:(id) sender
29 [[UIApplication sharedApplication]
30 openURL:[NSURL URLWithString:@"http://www.jwz.org/xscreensaver/"]];
36 // Extract the version number and release date from the version string.
37 // Here's an area where I kind of wish I had "Two Problems".
39 NSArray *a = [[NSString stringWithCString: screensaver_id
40 encoding:NSASCIIStringEncoding]
41 componentsSeparatedByCharactersInSet:
43 characterSetWithCharactersInString:@" ()-"]];
44 NSString *vers = [a objectAtIndex: 3];
45 NSString *year = [a objectAtIndex: 7];
47 NSString *line1 = [@"XScreenSaver " stringByAppendingString: vers];
48 NSString *line2 = [@"\u00A9 " stringByAppendingString:
49 [year stringByAppendingString:
50 @" Jamie Zawinski <jwz@jwz.org>"]];
52 UIView *v = [[UIView alloc] initWithFrame:CGRectZero];
54 // The "go to web page" button on the right
56 UIImage *img = [UIImage imageWithContentsOfFile:
57 [[[NSBundle mainBundle] bundlePath]
58 stringByAppendingPathComponent:
59 @"iSaverRunner29t.png"]];
60 UIBarButtonItem *button = [[[UIBarButtonItem alloc]
62 style: UIBarButtonItemStylePlain
64 action: @selector(titleTapped:)]
66 button.width = img.size.width;
67 self.navigationItem.rightBarButtonItem = button;
71 UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectZero];
72 UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectZero];
73 [label1 setText: line1];
74 [label2 setText: line2];
75 [label1 setBackgroundColor:[UIColor clearColor]];
76 [label2 setBackgroundColor:[UIColor clearColor]];
78 [label1 setFont: [UIFont boldSystemFontOfSize: 17]];
79 [label2 setFont: [UIFont systemFontOfSize: 12]];
83 CGRect r1 = [label1 frame];
84 CGRect r2 = [label2 frame];
87 CGRect win = [self view].frame;
88 if (win.size.width > 320) { // iPad
89 [label1 setTextAlignment: UITextAlignmentLeft];
90 [label2 setTextAlignment: UITextAlignmentRight];
91 label2.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
92 r3.size.width = win.size.width;
99 r3.size.width = 320; // force it to be flush-left
100 [label1 setTextAlignment: UITextAlignmentLeft];
101 [label2 setTextAlignment: UITextAlignmentLeft];
102 r1.origin.y = -1; // make it fit in landscape
103 r2.origin.y = r1.origin.y + r1.size.height - 2;
104 r3.size.height = r1.size.height + r2.size.height;
106 v.autoresizingMask = UIViewAutoresizingFlexibleWidth;
107 [label1 setFrame:r1];
108 [label2 setFrame:r2];
111 [v addSubview:label1];
112 [v addSubview:label2];
114 self.navigationItem.titleView = v;
118 - (id)initWithNames:(NSArray *)names descriptions:(NSDictionary *)descs;
121 if (! self) return 0;
122 [self reload:names descriptions:descs];
128 - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tv
130 int n = countof(list_by_letter);
131 NSMutableArray *a = [NSMutableArray arrayWithCapacity: n];
132 for (int i = 0; i < n; i++) {
134 s[0] = (i == 'Z'-'A'+1 ? '#' : i+'A');
136 [a addObject: [NSString stringWithCString:s
137 encoding:NSASCIIStringEncoding]];
143 - (void) reload:(NSArray *)names descriptions:(NSDictionary *)descs
146 [descriptions release];
147 descriptions = [descs retain];
149 int n = countof(list_by_letter);
150 for (int i = 0; i < n; i++) {
151 list_by_letter[i] = [[NSMutableArray alloc] init];
154 for (NSString *name in names) {
155 int index = ([name cStringUsingEncoding: NSASCIIStringEncoding])[0];
156 if (index >= 'a' && index <= 'z')
158 if (index >= 'A' && index <= 'Z')
162 [list_by_letter[index] addObject: name];
165 active_section_count = 0;
166 letter_sections = [[[NSMutableArray alloc] init] retain];
167 section_titles = [[[NSMutableArray alloc] init] retain];
168 for (int i = 0; i < n; i++) {
169 if ([list_by_letter[i] count] > 0) {
170 active_section_count++;
171 [letter_sections addObject: list_by_letter[i]];
173 [section_titles addObject: [NSString stringWithFormat: @"%c", i+'A']];
175 [section_titles addObject: @"#"];
178 [self.tableView reloadData];
182 - (NSString *)tableView:(UITableView *)tv
183 titleForHeaderInSection:(NSInteger)section
185 return [section_titles objectAtIndex: section];
188 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tv
190 return active_section_count;
194 - (NSInteger)tableView:(UITableView *)tv
195 numberOfRowsInSection:(NSInteger)section
197 return [[letter_sections objectAtIndex: section] count];
200 - (NSInteger)tableView:(UITableView *)tv
201 sectionForSectionIndexTitle:(NSString *)title
202 atIndex:(NSInteger) index
205 for (NSString *sectionTitle in section_titles) {
206 if ([sectionTitle isEqualToString: title])
214 - (UITableViewCell *)tableView:(UITableView *)tv
215 cellForRowAtIndexPath:(NSIndexPath *)ip
218 [[letter_sections objectAtIndex: [ip indexAtPosition: 0]]
219 objectAtIndex: [ip indexAtPosition: 1]];
220 NSString *desc = [descriptions objectForKey:id];
222 UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier: id];
224 cell = [[[UITableViewCell alloc]
226 ? UITableViewCellStyleSubtitle
227 : UITableViewCellStyleDefault)
230 cell.textLabel.text = id;
232 cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
234 cell.detailTextLabel.text = desc;
240 /* Selecting a row launches the saver.
242 - (void)tableView:(UITableView *)tv
243 didSelectRowAtIndexPath:(NSIndexPath *)ip
245 UITableViewCell *cell = [tv cellForRowAtIndexPath: ip];
247 (SaverRunner *) [[UIApplication sharedApplication] delegate];
249 if (! [s isKindOfClass:[SaverRunner class]])
251 [s loadSaver: cell.textLabel.text];
254 /* Selecting a row's Disclosure Button opens the preferences.
256 - (void)tableView:(UITableView *)tv
257 accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)ip
259 UITableViewCell *cell = [tv cellForRowAtIndexPath: ip];
261 (SaverRunner *) [[UIApplication sharedApplication] delegate];
263 if (! [s isKindOfClass:[SaverRunner class]])
265 [s openPreferences: cell.textLabel.text];
269 - (void) scrollTo: (NSString *) name
274 for (NSArray *a in letter_sections) {
276 for (NSString *n in a) {
277 ok = [n isEqualToString: name];
285 NSIndexPath *ip = [NSIndexPath indexPathForRow: j inSection: i];
286 [self.tableView selectRowAtIndexPath:ip
288 scrollPosition: UITableViewScrollPositionMiddle];
293 - (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o
301 for (int i = 0; i < countof(list_by_letter); i++)
302 [list_by_letter[i] release];
303 [letter_sections release];
304 [section_titles release];
305 [descriptions release];
312 #endif // USE_IPHONE -- whole file