From 67847892c023174a0f4771a473196e85945b73c7 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 30 Jul 2019 16:02:49 +0200 Subject: Remove android and OSX files --- OSX/XScreenSaverConfigSheet.m | 3710 ----------------------------------------- 1 file changed, 3710 deletions(-) delete mode 100644 OSX/XScreenSaverConfigSheet.m (limited to 'OSX/XScreenSaverConfigSheet.m') diff --git a/OSX/XScreenSaverConfigSheet.m b/OSX/XScreenSaverConfigSheet.m deleted file mode 100644 index eaa5add..0000000 --- a/OSX/XScreenSaverConfigSheet.m +++ /dev/null @@ -1,3710 +0,0 @@ -/* xscreensaver, Copyright (c) 2006-2017 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. - */ - -/* XScreenSaver uses XML files to describe the user interface for configuring - the various screen savers. These files live in .../hacks/config/ and - say relatively high level things like: "there should be a checkbox - labelled "Leave Trails", and when it is checked, add the option '-trails' - to the command line when launching the program." - - This code reads that XML and constructs a Cocoa interface from it. - The Cocoa controls are hooked up to NSUserDefaultsController to save - those settings into the MacOS preferences system. The Cocoa preferences - names are the same as the resource names specified in the screenhack's - 'options' array (we use that array to map the command line switches - specified in the XML to the resource names to use). - */ - -#import "XScreenSaverConfigSheet.h" -#import "Updater.h" - -#import "jwxyz.h" -#import "InvertedSlider.h" - -#ifdef USE_IPHONE -# define NSView UIView -# define NSRect CGRect -# define NSSize CGSize -# define NSTextField UITextField -# define NSButton UIButton -# define NSFont UIFont -# define NSStepper UIStepper -# define NSMenuItem UIMenuItem -# define NSText UILabel -# define minValue minimumValue -# define maxValue maximumValue -# define setMinValue setMinimumValue -# define setMaxValue setMaximumValue -# define LABEL UILabel -#else -# define LABEL NSTextField -#endif // USE_IPHONE - -#undef LABEL_ABOVE_SLIDER -#define USE_HTML_LABELS - - -#pragma mark XML Parser - -/* I used to use the "NSXMLDocument" XML parser, but that doesn't exist - on iOS. The "NSXMLParser" parser exists on both OSX and iOS, so I - converted to use that. However, to avoid having to re-write all of - the old code, I faked out a halfassed implementation of the - "NSXMLNode" class that "NSXMLDocument" used to return. - */ - -#define NSXMLNode SimpleXMLNode -#define NSXMLElement SimpleXMLNode -#define NSXMLCommentKind SimpleXMLCommentKind -#define NSXMLElementKind SimpleXMLElementKind -#define NSXMLAttributeKind SimpleXMLAttributeKind -#define NSXMLTextKind SimpleXMLTextKind - -typedef enum { SimpleXMLCommentKind, - SimpleXMLElementKind, - SimpleXMLAttributeKind, - SimpleXMLTextKind, -} SimpleXMLKind; - -@interface SimpleXMLNode : NSObject -{ - SimpleXMLKind kind; - NSString *name; - SimpleXMLNode *parent; - NSMutableArray *children; - NSMutableArray *attributes; - id object; -} - -@property(nonatomic) SimpleXMLKind kind; -@property(nonatomic, retain) NSString *name; -@property(nonatomic, retain) SimpleXMLNode *parent; -@property(nonatomic, retain) NSMutableArray *children; -@property(nonatomic, retain) NSMutableArray *attributes; -@property(nonatomic, retain, getter=objectValue, setter=setObjectValue:) - id object; - -@end - -@implementation SimpleXMLNode - -@synthesize kind; -@synthesize name; -//@synthesize parent; -@synthesize children; -@synthesize attributes; -@synthesize object; - -- (id) init -{ - self = [super init]; - attributes = [NSMutableArray arrayWithCapacity:10]; - return self; -} - - -- (id) initWithName:(NSString *)n -{ - self = [self init]; - [self setKind:NSXMLElementKind]; - [self setName:n]; - return self; -} - - -- (void) setAttributesAsDictionary:(NSDictionary *)dict -{ - for (NSString *key in dict) { - NSObject *val = [dict objectForKey:key]; - SimpleXMLNode *n = [[SimpleXMLNode alloc] init]; - [n setKind:SimpleXMLAttributeKind]; - [n setName:key]; - [n setObjectValue:val]; - [attributes addObject:n]; - [n release]; - } -} - -- (SimpleXMLNode *) parent { return parent; } - -- (void) setParent:(SimpleXMLNode *)p -{ - NSAssert (!parent, @"parent already set"); - if (!p) return; - parent = p; - NSMutableArray *kids = [p children]; - if (!kids) { - kids = [NSMutableArray arrayWithCapacity:10]; - [p setChildren:kids]; - } - [kids addObject:self]; -} -@end - - -#pragma mark textMode value transformer - -// A value transformer for mapping "url" to "3" and vice versa in the -// "textMode" preference, since NSMatrix uses NSInteger selectedIndex. - -#ifndef USE_IPHONE -@interface TextModeTransformer: NSValueTransformer {} -@end -@implementation TextModeTransformer -+ (Class)transformedValueClass { return [NSString class]; } -+ (BOOL)allowsReverseTransformation { return YES; } - -- (id)transformedValue:(id)value { - if ([value isKindOfClass:[NSString class]]) { - int i = -1; - if ([value isEqualToString:@"date"]) { i = 0; } - else if ([value isEqualToString:@"literal"]) { i = 1; } - else if ([value isEqualToString:@"file"]) { i = 2; } - else if ([value isEqualToString:@"url"]) { i = 3; } - else if ([value isEqualToString:@"program"]) { i = 4; } - if (i != -1) - value = [NSNumber numberWithInt: i]; - } - return value; -} - -- (id)reverseTransformedValue:(id)value { - if ([value isKindOfClass:[NSNumber class]]) { - switch ((int) [value doubleValue]) { - case 0: value = @"date"; break; - case 1: value = @"literal"; break; - case 2: value = @"file"; break; - case 3: value = @"url"; break; - case 4: value = @"program"; break; - } - } - return value; -} -@end -#endif // USE_IPHONE - - -#pragma mark Implementing radio buttons - -/* The UIPickerView is a hideous and uncustomizable piece of shit. - I can't believe Apple actually released that thing on the world. - Let's fake up some radio buttons instead. - */ - -#if defined(USE_IPHONE) && !defined(USE_PICKER_VIEW) - -@interface RadioButton : UILabel -{ - int index; - NSArray *items; -} - -@property(nonatomic) int index; -@property(nonatomic, retain) NSArray *items; - -@end - -@implementation RadioButton - -@synthesize index; -@synthesize items; - -- (id) initWithIndex:(int)_index items:_items -{ - self = [super initWithFrame:CGRectZero]; - index = _index; - items = [_items retain]; - - [self setText: [[items objectAtIndex:index] objectAtIndex:0]]; - [self setBackgroundColor:[UIColor clearColor]]; - [self sizeToFit]; - - return self; -} - -@end - - -# endif // !USE_PICKER_VIEW - - -# pragma mark Implementing labels with clickable links - -#if defined(USE_IPHONE) && defined(USE_HTML_LABELS) - -@interface HTMLLabel : UIView -{ - NSString *html; - UIFont *font; - UIWebView *webView; -} - -@property(nonatomic, retain) NSString *html; -@property(nonatomic, retain) UIWebView *webView; - -- (id) initWithHTML:(NSString *)h font:(UIFont *)f; -- (id) initWithText:(NSString *)t font:(UIFont *)f; -- (void) setHTML:(NSString *)h; -- (void) setText:(NSString *)t; -- (void) sizeToFit; - -@end - -@implementation HTMLLabel - -@synthesize html; -@synthesize webView; - -- (id) initWithHTML:(NSString *)h font:(UIFont *)f -{ - self = [super init]; - if (! self) return 0; - font = [f retain]; - webView = [[UIWebView alloc] init]; - webView.delegate = self; - webView.dataDetectorTypes = UIDataDetectorTypeNone; - self. autoresizingMask = UIViewAutoresizingNone; // we do it manually - webView.autoresizingMask = UIViewAutoresizingNone; - webView.scrollView.scrollEnabled = NO; - webView.scrollView.bounces = NO; - webView.opaque = NO; - [webView setBackgroundColor:[UIColor clearColor]]; - - [self addSubview: webView]; - [self setHTML: h]; - return self; -} - -- (id) initWithText:(NSString *)t font:(UIFont *)f -{ - self = [self initWithHTML:@"" font:f]; - if (! self) return 0; - [self setText: t]; - return self; -} - - -- (void) setHTML: (NSString *)h -{ - if (! h) return; - [h retain]; - if (html) [html release]; - html = h; - NSString *h2 = - [NSString stringWithFormat: - @"" - "" - "" -// "" - "" - "" - "" - "%@" - "" - "", - [font fontName], - [font pointSize], - [font lineHeight], - h]; - [webView stopLoading]; - [webView loadHTMLString:h2 baseURL:[NSURL URLWithString:@""]]; -} - - -static char *anchorize (const char *url); - -- (void) setText: (NSString *)t -{ - t = [t stringByTrimmingCharactersInSet:[NSCharacterSet - whitespaceCharacterSet]]; - t = [t stringByReplacingOccurrencesOfString:@"&" withString:@"&"]; - t = [t stringByReplacingOccurrencesOfString:@"<" withString:@"<"]; - t = [t stringByReplacingOccurrencesOfString:@">" withString:@">"]; - t = [t stringByReplacingOccurrencesOfString:@"\n\n" withString:@"

"]; - t = [t stringByReplacingOccurrencesOfString:@"

" - withString:@"

        "]; - t = [t stringByReplacingOccurrencesOfString:@"\n " - withString:@"
        "]; - - NSString *h = @""; - for (NSString *s in - [t componentsSeparatedByCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]]) { - if ([s hasPrefix:@"http://"] || - [s hasPrefix:@"https://"]) { - char *anchor = anchorize ([s cStringUsingEncoding:NSUTF8StringEncoding]); - NSString *a2 = [NSString stringWithCString: anchor - encoding: NSUTF8StringEncoding]; - s = [NSString stringWithFormat: @"%@
", s, a2]; - free (anchor); - } - h = [NSString stringWithFormat: @"%@ %@", h, s]; - } - - h = [h stringByReplacingOccurrencesOfString:@"

" withString:@"

"]; - h = [h stringByReplacingOccurrencesOfString:@"

" withString:@"

"]; - h = [h stringByTrimmingCharactersInSet:[NSCharacterSet - whitespaceAndNewlineCharacterSet]]; - - [self setHTML: h]; -} - - --(BOOL) webView:(UIWebView *)wv - shouldStartLoadWithRequest:(NSURLRequest *)req - navigationType:(UIWebViewNavigationType)type -{ - // Force clicked links to open in Safari, not in this window. - if (type == UIWebViewNavigationTypeLinkClicked) { - [[UIApplication sharedApplication] openURL:[req URL]]; - return NO; - } - return YES; -} - - -- (void) setFrame: (CGRect)r -{ - [super setFrame: r]; - r.origin.x = 0; - r.origin.y = 0; - [webView setFrame: r]; -} - - -- (NSString *) stripTags:(NSString *)str -{ - NSString *result = @""; - - // Add newlines. - str = [str stringByReplacingOccurrencesOfString:@"

" - withString:@"

" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [str length])]; - str = [str stringByReplacingOccurrencesOfString:@"
" - withString:@"\n" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [str length])]; - - // Remove HREFs. - for (NSString *s in [str componentsSeparatedByString: @"<"]) { - NSRange r = [s rangeOfString:@">"]; - if (r.length > 0) - s = [s substringFromIndex: r.location + r.length]; - result = [result stringByAppendingString: s]; - } - - // Compress internal horizontal whitespace. - str = result; - result = @""; - for (NSString *s in [str componentsSeparatedByCharactersInSet: - [NSCharacterSet whitespaceCharacterSet]]) { - if ([result length] == 0) - result = s; - else if ([s length] > 0) - result = [NSString stringWithFormat: @"%@ %@", result, s]; - } - - return result; -} - - -- (void) sizeToFit -{ - CGRect r = [self frame]; - - /* It would be sensible to just ask the UIWebView how tall the page is, - instead of hoping that NSString and UIWebView measure fonts and do - wrapping in exactly the same way, but since UIWebView is asynchronous, - we'd have to wait for the document to load first, e.g.: - - - Start the document loading; - - return a default height to use for the UITableViewCell; - - wait for the webViewDidFinishLoad delegate method to fire; - - then force the UITableView to reload, to pick up the new height. - - But I couldn't make that work. - */ -# if 0 - r.size.height = [[webView - stringByEvaluatingJavaScriptFromString: - @"document.body.offsetHeight"] - doubleValue]; -# else - NSString *text = [self stripTags: html]; - CGSize s = r.size; - s.height = 999999; - s = [text boundingRectWithSize:s - options:NSStringDrawingUsesLineFragmentOrigin - attributes:@{NSFontAttributeName: font} - context:nil].size; - r.size.height = s.height; -# endif - - [self setFrame: r]; -} - - -- (void) dealloc -{ - [html release]; - [font release]; - [webView release]; - [super dealloc]; -} - -@end - -#endif // USE_IPHONE && USE_HTML_LABELS - - -@interface XScreenSaverConfigSheet (Private) - -- (void)traverseChildren:(NSXMLNode *)node on:(NSView *)parent; - -# ifndef USE_IPHONE -- (void) placeChild: (NSView *)c on:(NSView *)p right:(BOOL)r; -- (void) placeChild: (NSView *)c on:(NSView *)p; -static NSView *last_child (NSView *parent); -static void layout_group (NSView *group, BOOL horiz_p); -# else // USE_IPHONE -- (void) placeChild: (NSObject *)c on:(NSView *)p right:(BOOL)r; -- (void) placeChild: (NSObject *)c on:(NSView *)p; -- (void) placeSeparator; -- (void) bindResource:(NSObject *)ctl key:(NSString *)k reload:(BOOL)r; -- (void) refreshTableView; -# endif // USE_IPHONE - -@end - - -@implementation XScreenSaverConfigSheet - -# define LEFT_MARGIN 20 // left edge of window -# define COLUMN_SPACING 10 // gap between e.g. labels and text fields -# define LEFT_LABEL_WIDTH 70 // width of all left labels -# define LINE_SPACING 10 // leading between each line - -# define FONT_SIZE 17 // Magic hardcoded UITableView font size. - -#pragma mark Talking to the resource database - - -/* Normally we read resources by looking up "KEY" in the database - "org.jwz.xscreensaver.SAVERNAME". But in the all-in-one iPhone - app, everything is stored in the database "org.jwz.xscreensaver" - instead, so transform keys to "SAVERNAME.KEY". - - NOTE: This is duplicated in PrefsReader.m, cause I suck. - */ -- (NSString *) makeKey:(NSString *)key -{ -# ifdef USE_IPHONE - NSString *prefix = [saver_name stringByAppendingString:@"."]; - if (! [key hasPrefix:prefix]) // Don't double up! - key = [prefix stringByAppendingString:key]; -# endif - return key; -} - - -- (NSString *) makeCKey:(const char *)key -{ - return [self makeKey:[NSString stringWithCString:key - encoding:NSUTF8StringEncoding]]; -} - - -/* Given a command-line option, returns the corresponding resource name. - Any arguments in the switch string are ignored (e.g., "-foo x"). - */ -- (NSString *) switchToResource:(NSString *)cmdline_switch - opts:(const XrmOptionDescRec *)opts_array - valRet:(NSString **)val_ret -{ - char buf[1280]; - char *tail = 0; - NSAssert(cmdline_switch, @"cmdline switch is null"); - if (! [cmdline_switch getCString:buf maxLength:sizeof(buf) - encoding:NSUTF8StringEncoding]) { - NSAssert1(0, @"unable to convert %@", cmdline_switch); - return 0; - } - char *s = strpbrk(buf, " \t\r\n"); - if (s && *s) { - *s = 0; - tail = s+1; - while (*tail && (*tail == ' ' || *tail == '\t')) - tail++; - } - - while (opts_array[0].option) { - if (!strcmp (opts_array[0].option, buf)) { - const char *ret = 0; - - if (opts_array[0].argKind == XrmoptionNoArg) { - if (tail && *tail) - NSAssert1 (0, @"expected no args to switch: \"%@\"", - cmdline_switch); - ret = opts_array[0].value; - } else { - if (!tail || !*tail) - NSAssert1 (0, @"expected args to switch: \"%@\"", - cmdline_switch); - ret = tail; - } - - if (val_ret) - *val_ret = (ret - ? [NSString stringWithCString:ret - encoding:NSUTF8StringEncoding] - : 0); - - const char *res = opts_array[0].specifier; - while (*res && (*res == '.' || *res == '*')) - res++; - return [self makeCKey:res]; - } - opts_array++; - } - - NSAssert1 (0, @"\"%@\" not present in options", cmdline_switch); - return 0; -} - - -- (NSUserDefaultsController *)controllerForKey:(NSString *)key -{ - static NSDictionary *a = 0; - if (! a) { - a = UPDATER_DEFAULTS; - [a retain]; - } - if ([a objectForKey:key]) - // These preferences are global to all xscreensavers. - return globalDefaultsController; - else - // All other preferences are per-saver. - return userDefaultsController; -} - - -#ifdef USE_IPHONE - -// Called when a slider is bonked. -// -- (void)sliderAction:(UISlider*)sender -{ - if ([active_text_field canResignFirstResponder]) - [active_text_field resignFirstResponder]; - NSString *pref_key = [pref_keys objectAtIndex: [sender tag]]; - - // Hacky API. See comment in InvertedSlider.m. - double v = ([sender isKindOfClass: [InvertedSlider class]] - ? [(InvertedSlider *) sender transformedValue] - : [sender value]); - - [[self controllerForKey:pref_key] - setObject:((v == (int) v) - ? [NSNumber numberWithInt:(int) v] - : [NSNumber numberWithDouble: v]) - forKey:pref_key]; -} - -// Called when a checkbox/switch is bonked. -// -- (void)switchAction:(UISwitch*)sender -{ - if ([active_text_field canResignFirstResponder]) - [active_text_field resignFirstResponder]; - NSString *pref_key = [pref_keys objectAtIndex: [sender tag]]; - NSString *v = ([sender isOn] ? @"true" : @"false"); - [[self controllerForKey:pref_key] setObject:v forKey:pref_key]; -} - -# ifdef USE_PICKER_VIEW -// Called when a picker is bonked. -// -- (void)pickerView:(UIPickerView *)pv - didSelectRow:(NSInteger)row - inComponent:(NSInteger)column -{ - if ([active_text_field canResignFirstResponder]) - [active_text_field resignFirstResponder]; - - NSAssert (column == 0, @"internal error"); - NSArray *a = [picker_values objectAtIndex: [pv tag]]; - if (! a) return; // Too early? - a = [a objectAtIndex:row]; - NSAssert (a, @"missing row"); - -//NSString *label = [a objectAtIndex:0]; - NSString *pref_key = [a objectAtIndex:1]; - NSObject *pref_val = [a objectAtIndex:2]; - [[self controllerForKey:pref_key] setObject:pref_val forKey:pref_key]; -} -# else // !USE_PICKER_VIEW - -// Called when a RadioButton is bonked. -// -- (void)radioAction:(RadioButton*)sender -{ - if ([active_text_field canResignFirstResponder]) - [active_text_field resignFirstResponder]; - - NSArray *item = [[sender items] objectAtIndex: [sender index]]; - NSString *pref_key = [item objectAtIndex:1]; - NSObject *pref_val = [item objectAtIndex:2]; - [[self controllerForKey:pref_key] setObject:pref_val forKey:pref_key]; -} - -- (BOOL)textFieldShouldBeginEditing:(UITextField *)tf -{ - active_text_field = tf; - return YES; -} - -- (void)textFieldDidEndEditing:(UITextField *)tf -{ - NSString *pref_key = [pref_keys objectAtIndex: [tf tag]]; - NSString *txt = [tf text]; - [[self controllerForKey:pref_key] setObject:txt forKey:pref_key]; -} - -- (BOOL)textFieldShouldReturn:(UITextField *)tf -{ - active_text_field = nil; - [tf resignFirstResponder]; - return YES; -} - -# endif // !USE_PICKER_VIEW - -#endif // USE_IPHONE - - -# ifndef USE_IPHONE - -- (void) okAction:(NSObject *)arg -{ - // Without the setAppliesImmediately:, when the saver restarts, it's still - // got the old settings. -[XScreenSaverConfigSheet traverseTree] sets this - // to NO; default is YES. - - // #### However: I'm told that when these are set to YES, then changes to - // 'textLiteral', 'textURL' and 'textProgram' are ignored, but 'textFile' - // works. In StarWars, at least... - - [userDefaultsController setAppliesImmediately:YES]; - [globalDefaultsController setAppliesImmediately:YES]; - [userDefaultsController commitEditing]; - [globalDefaultsController commitEditing]; - [userDefaultsController save:self]; - [globalDefaultsController save:self]; - [NSApp endSheet:self returnCode:NSOKButton]; - [self close]; -} - -- (void) cancelAction:(NSObject *)arg -{ - [userDefaultsController revert:self]; - [globalDefaultsController revert:self]; - [NSApp endSheet:self returnCode:NSCancelButton]; - [self close]; -} -# endif // !USE_IPHONE - - -- (void) resetAction:(NSObject *)arg -{ -# ifndef USE_IPHONE - [userDefaultsController revertToInitialValues:self]; - [globalDefaultsController revertToInitialValues:self]; -# else // USE_IPHONE - - for (NSString *key in defaultOptions) { - NSObject *val = [defaultOptions objectForKey:key]; - [[self controllerForKey:key] setObject:val forKey:key]; - } - - for (UIControl *ctl in pref_ctls) { - NSString *pref_key = [pref_keys objectAtIndex: ctl.tag]; - [self bindResource:ctl key:pref_key reload:YES]; - } - - [self refreshTableView]; -# endif // USE_IPHONE -} - - -/* Connects a control (checkbox, etc) to the corresponding preferences key. - */ -- (void) bindResource:(NSObject *)control key:(NSString *)pref_key - reload:(BOOL)reload_p -{ - NSUserDefaultsController *prefs = [self controllerForKey:pref_key]; -# ifndef USE_IPHONE - NSDictionary *opts_dict = nil; - NSString *bindto = ([control isKindOfClass:[NSPopUpButton class]] - ? @"selectedObject" - : ([control isKindOfClass:[NSMatrix class]] - ? @"selectedIndex" - : @"value")); - - if ([control isKindOfClass:[NSMatrix class]]) { - opts_dict = @{ NSValueTransformerNameBindingOption: - @"TextModeTransformer" }; - } - - [control bind:bindto - toObject:prefs - withKeyPath:[@"values." stringByAppendingString: pref_key] - options:opts_dict]; - -# else // USE_IPHONE - SEL sel; - NSObject *val = [prefs objectForKey:pref_key]; - NSString *sval = 0; - double dval = 0; - - if ([val isKindOfClass:[NSString class]]) { - sval = (NSString *) val; - if (NSOrderedSame == [sval caseInsensitiveCompare:@"true"] || - NSOrderedSame == [sval caseInsensitiveCompare:@"yes"] || - NSOrderedSame == [sval caseInsensitiveCompare:@"1"]) - dval = 1; - else - dval = [sval doubleValue]; - } else if ([val isKindOfClass:[NSNumber class]]) { - // NSBoolean (__NSCFBoolean) is really NSNumber. - dval = [(NSNumber *) val doubleValue]; - sval = [(NSNumber *) val stringValue]; - } - - if ([control isKindOfClass:[UISlider class]]) { - sel = @selector(sliderAction:); - // Hacky API. See comment in InvertedSlider.m. - if ([control isKindOfClass:[InvertedSlider class]]) - [(InvertedSlider *) control setTransformedValue: dval]; - else - [(UISlider *) control setValue: dval]; - } else if ([control isKindOfClass:[UISwitch class]]) { - sel = @selector(switchAction:); - [(UISwitch *) control setOn: ((int) dval != 0)]; -# ifdef USE_PICKER_VIEW - } else if ([control isKindOfClass:[UIPickerView class]]) { - sel = 0; - [(UIPickerView *) control selectRow:((int)dval) inComponent:0 - animated:NO]; -# else // !USE_PICKER_VIEW - } else if ([control isKindOfClass:[RadioButton class]]) { - sel = 0; // radioAction: sent from didSelectRowAtIndexPath. - } else if ([control isKindOfClass:[UITextField class]]) { - sel = 0; // #### - [(UITextField *) control setText: sval]; -# endif // !USE_PICKER_VIEW - } else { - NSAssert (0, @"unknown class"); - } - - // NSLog(@"\"%@\" = \"%@\" [%@, %.1f]", pref_key, val, [val class], dval); - - if (!reload_p) { - if (! pref_keys) { - pref_keys = [[NSMutableArray arrayWithCapacity:10] retain]; - pref_ctls = [[NSMutableArray arrayWithCapacity:10] retain]; - } - - [pref_keys addObject: [self makeKey:pref_key]]; - [pref_ctls addObject: control]; - ((UIControl *) control).tag = [pref_keys count] - 1; - - if (sel) { - [(UIControl *) control addTarget:self action:sel - forControlEvents:UIControlEventValueChanged]; - } - } - -# endif // USE_IPHONE - -# if 0 - NSObject *def = [[prefs defaults] objectForKey:pref_key]; - NSString *s = [NSString stringWithFormat:@"bind: \"%@\"", pref_key]; - s = [s stringByPaddingToLength:18 withString:@" " startingAtIndex:0]; - s = [NSString stringWithFormat:@"%@ = %@", s, - ([def isKindOfClass:[NSString class]] - ? [NSString stringWithFormat:@"\"%@\"", def] - : def)]; - s = [s stringByPaddingToLength:30 withString:@" " startingAtIndex:0]; - s = [NSString stringWithFormat:@"%@ %@ / %@", s, - [def class], [control class]]; -# ifndef USE_IPHONE - s = [NSString stringWithFormat:@"%@ / %@", s, bindto]; -# endif - NSLog (@"%@", s); -# endif -} - - -- (void) bindResource:(NSObject *)control key:(NSString *)pref_key -{ - [self bindResource:(NSObject *)control key:(NSString *)pref_key reload:NO]; -} - - - -- (void) bindSwitch:(NSObject *)control - cmdline:(NSString *)cmd -{ - [self bindResource:control - key:[self switchToResource:cmd opts:opts valRet:0]]; -} - - -#pragma mark Text-manipulating utilities - - -static NSString * -unwrap (NSString *text) -{ - // Unwrap lines: delete \n but do not delete \n\n. - // - NSArray *lines = [text componentsSeparatedByString:@"\n"]; - NSUInteger i, nlines = [lines count]; - BOOL eolp = YES; - - text = @"\n"; // start with one blank line - - // skip trailing blank lines in file - for (i = nlines-1; i > 0; i--) { - NSString *s = (NSString *) [lines objectAtIndex:i]; - if ([s length] > 0) - break; - nlines--; - } - - // skip leading blank lines in file - for (i = 0; i < nlines; i++) { - NSString *s = (NSString *) [lines objectAtIndex:i]; - if ([s length] > 0) - break; - } - - // unwrap - Bool any = NO; - for (; i < nlines; i++) { - NSString *s = (NSString *) [lines objectAtIndex:i]; - if ([s length] == 0) { - text = [text stringByAppendingString:@"\n\n"]; - eolp = YES; - } else if ([s characterAtIndex:0] == ' ' || - [s hasPrefix:@"Copyright "] || - [s hasPrefix:@"https://"] || - [s hasPrefix:@"http://"]) { - // don't unwrap if the following line begins with whitespace, - // or with the word "Copyright", or if it begins with a URL. - if (any && !eolp) - text = [text stringByAppendingString:@"\n"]; - text = [text stringByAppendingString:s]; - any = YES; - eolp = NO; - } else { - if (!eolp) - text = [text stringByAppendingString:@" "]; - text = [text stringByAppendingString:s]; - eolp = NO; - any = YES; - } - } - - return text; -} - - -# ifndef USE_IPHONE -/* Makes the text up to the first comma be bold. - */ -static void -boldify (NSText *nstext) -{ - NSString *text = [nstext string]; - NSRange r = [text rangeOfString:@"," options:0]; - r.length = r.location+1; - - r.location = 0; - - NSFont *font = [nstext font]; - font = [NSFont boldSystemFontOfSize:[font pointSize]]; - [nstext setFont:font range:r]; -} -# endif // !USE_IPHONE - - -/* Creates a human-readable anchor to put on a URL. - */ -static char * -anchorize (const char *url) -{ - const char *wiki1 = "http://en.wikipedia.org/wiki/"; - const char *wiki2 = "https://en.wikipedia.org/wiki/"; - const char *math1 = "http://mathworld.wolfram.com/"; - const char *math2 = "https://mathworld.wolfram.com/"; - if (!strncmp (wiki1, url, strlen(wiki1)) || - !strncmp (wiki2, url, strlen(wiki2))) { - char *anchor = (char *) malloc (strlen(url) * 3 + 10); - strcpy (anchor, "Wikipedia: \""); - const char *in = url + strlen(!strncmp (wiki1, url, strlen(wiki1)) - ? wiki1 : wiki2); - char *out = anchor + strlen(anchor); - while (*in) { - if (*in == '_') { - *out++ = ' '; - } else if (*in == '#') { - *out++ = ':'; - *out++ = ' '; - } else if (*in == '%') { - char hex[3]; - hex[0] = in[1]; - hex[1] = in[2]; - hex[2] = 0; - int n = 0; - sscanf (hex, "%x", &n); - *out++ = (char) n; - in += 2; - } else { - *out++ = *in; - } - in++; - } - *out++ = '"'; - *out = 0; - return anchor; - - } else if (!strncmp (math1, url, strlen(math1)) || - !strncmp (math2, url, strlen(math2))) { - char *anchor = (char *) malloc (strlen(url) * 3 + 10); - strcpy (anchor, "MathWorld: \""); - const char *start = url + strlen(!strncmp (math1, url, strlen(math1)) - ? math1 : math2); - const char *in = start; - char *out = anchor + strlen(anchor); - while (*in) { - if (*in == '_') { - *out++ = ' '; - } else if (in != start && *in >= 'A' && *in <= 'Z') { - *out++ = ' '; - *out++ = *in; - } else if (!strncmp (in, ".htm", 4)) { - break; - } else { - *out++ = *in; - } - in++; - } - *out++ = '"'; - *out = 0; - return anchor; - - } else { - return strdup (url); - } -} - - -#if !defined(USE_IPHONE) || !defined(USE_HTML_LABELS) - -/* Converts any http: URLs in the given text field to clickable links. - */ -static void -hreffify (NSText *nstext) -{ -# ifndef USE_IPHONE - NSString *text = [nstext string]; - [nstext setRichText:YES]; -# else - NSString *text = [nstext text]; -# endif - - NSUInteger L = [text length]; - NSRange start; // range is start-of-search to end-of-string - start.location = 0; - start.length = L; - while (start.location < L) { - - // Find the beginning of a URL... - // - NSRange r2 = [text rangeOfString: @"http://" options:0 range:start]; - NSRange r3 = [text rangeOfString:@"https://" options:0 range:start]; - if ((r2.location == NSNotFound && - r3.location != NSNotFound) || - (r2.location != NSNotFound && - r3.location != NSNotFound && - r3.location < r2.location)) - r2 = r3; - if (r2.location == NSNotFound) - break; - - // Next time around, start searching after this. - start.location = r2.location + r2.length; - start.length = L - start.location; - - // Find the end of a URL (whitespace or EOF)... - // - r3 = [text rangeOfCharacterFromSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet] - options:0 range:start]; - if (r3.location == NSNotFound) // EOF - r3.location = L, r3.length = 0; - - // Next time around, start searching after this. - start.location = r3.location; - start.length = L - start.location; - - // Set r2 to the start/length of this URL. - r2.length = start.location - r2.location; - - // Extract the URL. - NSString *nsurl = [text substringWithRange:r2]; - const char *url = [nsurl UTF8String]; - - // If this is a Wikipedia URL, make the linked text be prettier. - // - char *anchor = anchorize(url); - -# ifndef USE_IPHONE - - // Construct the RTF corresponding to anchor - // - const char *fmt = "{\\field{\\*\\fldinst{HYPERLINK \"%s\"}}%s}"; - char *rtf = malloc (strlen (fmt) + strlen(url) + strlen(anchor) + 10); - sprintf (rtf, fmt, url, anchor); - - NSData *rtfdata = [NSData dataWithBytesNoCopy:rtf length:strlen(rtf)]; - [nstext replaceCharactersInRange:r2 withRTF:rtfdata]; - -# else // !USE_IPHONE - // *anchor = 0; // Omit Wikipedia anchor - text = [text stringByReplacingCharactersInRange:r2 - withString:[NSString stringWithCString:anchor - encoding:NSUTF8StringEncoding]]; - // text = [text stringByReplacingOccurrencesOfString:@"\n\n\n" - // withString:@"\n\n"]; -# endif // !USE_IPHONE - - free (anchor); - - NSUInteger L2 = [text length]; // might have changed - start.location -= (L - L2); - L = L2; - } - -# ifdef USE_IPHONE - [nstext setText:text]; - [nstext sizeToFit]; -# endif -} - -#endif /* !USE_IPHONE || !USE_HTML_LABELS */ - - - -#pragma mark Creating controls from XML - - -/* Parse the attributes of an XML tag into a dictionary. - For input, the dictionary should have as attributes the keys, each - with @"" as their value. - On output, the dictionary will set the keys to the values specified, - and keys that were not specified will not be present in the dictionary. - Warnings are printed if there are duplicate or unknown attributes. - */ -- (void) parseAttrs:(NSMutableDictionary *)dict node:(NSXMLNode *)node -{ - NSArray *attrs = [(NSXMLElement *) node attributes]; - NSUInteger n = [attrs count]; - int i; - - // For each key in the dictionary, fill in the dict with the corresponding - // value. The value @"" is assumed to mean "un-set". Issue a warning if - // an attribute is specified twice. - // - for (i = 0; i < n; i++) { - NSXMLNode *attr = [attrs objectAtIndex:i]; - NSString *key = [attr name]; - NSString *val = [attr objectValue]; - NSString *old = [dict objectForKey:key]; - - if (! old) { - NSAssert2 (0, @"unknown attribute \"%@\" in \"%@\"", key, [node name]); - } else if ([old length] != 0) { - NSAssert3 (0, @"duplicate %@: \"%@\", \"%@\"", key, old, val); - } else { - [dict setValue:val forKey:key]; - } - } - - // Remove from the dictionary any keys whose value is still @"", - // meaning there was no such attribute specified. - // - NSArray *keys = [dict allKeys]; - n = [keys count]; - for (i = 0; i < n; i++) { - NSString *key = [keys objectAtIndex:i]; - NSString *val = [dict objectForKey:key]; - if ([val length] == 0) - [dict removeObjectForKey:key]; - } - -# ifdef USE_IPHONE - // Kludge for starwars.xml: - // If there is a "_low-label" and no "_label", but "_low-label" contains - // spaces, divide them. - NSString *lab = [dict objectForKey:@"_label"]; - NSString *low = [dict objectForKey:@"_low-label"]; - if (low && !lab) { - NSArray *split = - [[[low stringByTrimmingCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]] - componentsSeparatedByString: @" "] - filteredArrayUsingPredicate: - [NSPredicate predicateWithFormat:@"length > 0"]]; - if (split && [split count] == 2) { - [dict setValue:[split objectAtIndex:0] forKey:@"_label"]; - [dict setValue:[split objectAtIndex:1] forKey:@"_low-label"]; - } - } -# endif // USE_IPHONE -} - - -/* Handle the options on the top level tag. - */ -- (NSString *) parseXScreenSaverTag:(NSXMLNode *)node -{ - NSMutableDictionary *dict = [@{ @"name": @"", - @"_label": @"", - @"gl": @"" } - mutableCopy]; - [self parseAttrs:dict node:node]; - NSString *name = [dict objectForKey:@"name"]; - NSString *label = [dict objectForKey:@"_label"]; - [dict release]; - dict = 0; - - NSAssert1 (label, @"no _label in %@", [node name]); - NSAssert1 (name, @"no name in \"%@\"", label); - return label; -} - - -/* Creates a label: an un-editable NSTextField displaying the given text. - */ -- (LABEL *) makeLabel:(NSString *)text -{ - NSRect rect; - rect.origin.x = rect.origin.y = 0; - rect.size.width = rect.size.height = 10; -# ifndef USE_IPHONE - NSTextField *lab = [[NSTextField alloc] initWithFrame:rect]; - [lab setSelectable:NO]; - [lab setEditable:NO]; - [lab setBezeled:NO]; - [lab setDrawsBackground:NO]; - [lab setStringValue:text]; - [lab sizeToFit]; -# else // USE_IPHONE - UILabel *lab = [[UILabel alloc] initWithFrame:rect]; - [lab setText: [text stringByTrimmingCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]]]; - [lab setBackgroundColor:[UIColor clearColor]]; - [lab setNumberOfLines:0]; // unlimited - // [lab setLineBreakMode:UILineBreakModeWordWrap]; - [lab setLineBreakMode:NSLineBreakByTruncatingHead]; - [lab setAutoresizingMask: (UIViewAutoresizingFlexibleWidth | - UIViewAutoresizingFlexibleHeight)]; -# endif // USE_IPHONE - [lab autorelease]; - return lab; -} - - -/* Creates the checkbox (NSButton) described by the given XML node. - */ -- (void) makeCheckbox:(NSXMLNode *)node on:(NSView *)parent -{ - NSMutableDictionary *dict = [@{ @"id": @"", - @"_label": @"", - @"arg-set": @"", - @"arg-unset": @"" } - mutableCopy]; - [self parseAttrs:dict node:node]; - NSString *label = [dict objectForKey:@"_label"]; - NSString *arg_set = [dict objectForKey:@"arg-set"]; - NSString *arg_unset = [dict objectForKey:@"arg-unset"]; - [dict release]; - dict = 0; - - if (!label) { - NSAssert1 (0, @"no _label in %@", [node name]); - return; - } - if (!arg_set && !arg_unset) { - NSAssert1 (0, @"neither arg-set nor arg-unset provided in \"%@\"", - label); - } - if (arg_set && arg_unset) { - NSAssert1 (0, @"only one of arg-set and arg-unset may be used in \"%@\"", - label); - } - - // sanity-check the choice of argument names. - // - if (arg_set && ([arg_set hasPrefix:@"-no-"] || - [arg_set hasPrefix:@"--no-"])) - NSLog (@"arg-set should not be a \"no\" option in \"%@\": %@", - label, arg_set); - if (arg_unset && (![arg_unset hasPrefix:@"-no-"] && - ![arg_unset hasPrefix:@"--no-"])) - NSLog(@"arg-unset should be a \"no\" option in \"%@\": %@", - label, arg_unset); - - NSRect rect; - rect.origin.x = rect.origin.y = 0; - rect.size.width = rect.size.height = 10; - -# ifndef USE_IPHONE - - NSButton *button = [[NSButton alloc] initWithFrame:rect]; - [button setButtonType:NSSwitchButton]; - [button setTitle:label]; - [button sizeToFit]; - [self placeChild:button on:parent]; - -# else // USE_IPHONE - - LABEL *lab = [self makeLabel:label]; - [self placeChild:lab on:parent]; - UISwitch *button = [[UISwitch alloc] initWithFrame:rect]; - [self placeChild:button on:parent right:YES]; - -# endif // USE_IPHONE - - [self bindSwitch:button cmdline:(arg_set ? arg_set : arg_unset)]; - [button release]; -} - - -/* Creates the number selection control described by the given XML node. - If "type=slider", it's an NSSlider. - If "type=spinbutton", it's a text field with up/down arrows next to it. - */ -- (void) makeNumberSelector:(NSXMLNode *)node on:(NSView *)parent -{ - NSMutableDictionary *dict = [@{ @"id": @"", - @"_label": @"", - @"_low-label": @"", - @"_high-label": @"", - @"type": @"", - @"arg": @"", - @"low": @"", - @"high": @"", - @"default": @"", - @"convert": @"" } - mutableCopy]; - [self parseAttrs:dict node:node]; - NSString *label = [dict objectForKey:@"_label"]; - NSString *low_label = [dict objectForKey:@"_low-label"]; - NSString *high_label = [dict objectForKey:@"_high-label"]; - NSString *type = [dict objectForKey:@"type"]; - NSString *arg = [dict objectForKey:@"arg"]; - NSString *low = [dict objectForKey:@"low"]; - NSString *high = [dict objectForKey:@"high"]; - NSString *def = [dict objectForKey:@"default"]; - NSString *cvt = [dict objectForKey:@"convert"]; - [dict release]; - dict = 0; - - NSAssert1 (arg, @"no arg in %@", label); - NSAssert1 (type, @"no type in %@", label); - - if (! low) { - NSAssert1 (0, @"no low in %@", [node name]); - return; - } - if (! high) { - NSAssert1 (0, @"no high in %@", [node name]); - return; - } - if (! def) { - NSAssert1 (0, @"no default in %@", [node name]); - return; - } - if (cvt && ![cvt isEqualToString:@"invert"]) { - NSAssert1 (0, @"if provided, \"convert\" must be \"invert\" in %@", - label); - } - - // If either the min or max field contains a decimal point, then this - // option may have a floating point value; otherwise, it is constrained - // to be an integer. - // - NSCharacterSet *dot = - [NSCharacterSet characterSetWithCharactersInString:@"."]; - BOOL float_p = ([low rangeOfCharacterFromSet:dot].location != NSNotFound || - [high rangeOfCharacterFromSet:dot].location != NSNotFound); - - if ([type isEqualToString:@"slider"] -# ifdef USE_IPHONE // On iPhone, we use sliders for all numeric values. - || [type isEqualToString:@"spinbutton"] -# endif - ) { - - NSRect rect; - rect.origin.x = rect.origin.y = 0; - rect.size.width = 150; - rect.size.height = 23; // apparent min height for slider with ticks... - NSSlider *slider; - slider = [[InvertedSlider alloc] initWithFrame:rect - inverted: !!cvt - integers: !float_p]; - [slider setMaxValue:[high doubleValue]]; - [slider setMinValue:[low doubleValue]]; - - int range = [slider maxValue] - [slider minValue] + 1; - int range2 = range; - int max_ticks = 21; - while (range2 > max_ticks) - range2 /= 10; - -# ifndef USE_IPHONE - // If we have elided ticks, leave it at the max number of ticks. - if (range != range2 && range2 < max_ticks) - range2 = max_ticks; - - // If it's a float, always display the max number of ticks. - if (float_p && range2 < max_ticks) - range2 = max_ticks; - - [slider setNumberOfTickMarks:range2]; - - [slider setAllowsTickMarkValuesOnly: - (range == range2 && // we are showing the actual number of ticks - !float_p)]; // and we want integer results -# endif // !USE_IPHONE - - // #### Note: when the slider's range is large enough that we aren't - // showing all possible ticks, the slider's value is not constrained - // to be an integer, even though it should be... - // Maybe we need to use a value converter or something? - - LABEL *lab; - if (label) { - lab = [self makeLabel:label]; - [self placeChild:lab on:parent]; -# ifdef USE_IPHONE - if (low_label) { - CGFloat s = [NSFont systemFontSize] + 4; - [lab setFont:[NSFont boldSystemFontOfSize:s]]; - } -# endif - } - - if (low_label) { - lab = [self makeLabel:low_label]; - [lab setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; -# ifndef USE_IPHONE - [lab setAlignment:1]; // right aligned - rect = [lab frame]; - if (rect.size.width < LEFT_LABEL_WIDTH) - rect.size.width = LEFT_LABEL_WIDTH; // make all left labels same size - rect.size.height = [slider frame].size.height; - [lab setFrame:rect]; - [self placeChild:lab on:parent]; -# else // USE_IPHONE - [lab setTextAlignment: NSTextAlignmentRight]; - // Sometimes rotation screws up truncation. - [lab setLineBreakMode:NSLineBreakByClipping]; - [self placeChild:lab on:parent right:(label ? YES : NO)]; -# endif // USE_IPHONE - } - -# ifndef USE_IPHONE - [self placeChild:slider on:parent right:(low_label ? YES : NO)]; -# else // USE_IPHONE - [self placeChild:slider on:parent right:(label || low_label ? YES : NO)]; -# endif // USE_IPHONE - - if (low_label) { - // Make left label be same height as slider. - rect = [lab frame]; - rect.size.height = [slider frame].size.height; - [lab setFrame:rect]; - } - - if (! low_label) { - rect = [slider frame]; - if (rect.origin.x < LEFT_LABEL_WIDTH) - rect.origin.x = LEFT_LABEL_WIDTH; // make unlabelled sliders line up too - [slider setFrame:rect]; - } - - if (high_label) { - lab = [self makeLabel:high_label]; - [lab setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - rect = [lab frame]; - - // Make right label be same height as slider. - rect.size.height = [slider frame].size.height; - [lab setFrame:rect]; -# ifdef USE_IPHONE - // Sometimes rotation screws up truncation. - [lab setLineBreakMode:NSLineBreakByClipping]; -# endif - [self placeChild:lab on:parent right:YES]; - } - - [self bindSwitch:slider cmdline:arg]; - [slider release]; - -#ifndef USE_IPHONE // On iPhone, we use sliders for all numeric values. - - } else if ([type isEqualToString:@"spinbutton"]) { - - if (! label) { - NSAssert1 (0, @"no _label in spinbutton %@", [node name]); - return; - } - NSAssert1 (!low_label, - @"low-label not allowed in spinbutton \"%@\"", [node name]); - NSAssert1 (!high_label, - @"high-label not allowed in spinbutton \"%@\"", [node name]); - NSAssert1 (!cvt, @"convert not allowed in spinbutton \"%@\"", - [node name]); - - NSRect rect; - rect.origin.x = rect.origin.y = 0; - rect.size.width = rect.size.height = 10; - - NSTextField *txt = [[NSTextField alloc] initWithFrame:rect]; - [txt setStringValue:@"0000.0"]; - [txt sizeToFit]; - [txt setStringValue:@""]; - - if (label) { - LABEL *lab = [self makeLabel:label]; - //[lab setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; - [lab setAlignment:1]; // right aligned - rect = [lab frame]; - if (rect.size.width < LEFT_LABEL_WIDTH) - rect.size.width = LEFT_LABEL_WIDTH; // make all left labels same size - rect.size.height = [txt frame].size.height; - [lab setFrame:rect]; - [self placeChild:lab on:parent]; - } - - [self placeChild:txt on:parent right:(label ? YES : NO)]; - - if (! label) { - rect = [txt frame]; - if (rect.origin.x < LEFT_LABEL_WIDTH) - rect.origin.x = LEFT_LABEL_WIDTH; // make unlabelled spinbtns line up - [txt setFrame:rect]; - } - - rect.size.width = rect.size.height = 10; - NSStepper *step = [[NSStepper alloc] initWithFrame:rect]; - [step sizeToFit]; - [self placeChild:step on:parent right:YES]; - rect = [step frame]; - rect.origin.x -= COLUMN_SPACING; // this one goes close - rect.origin.y += ([txt frame].size.height - rect.size.height) / 2; - [step setFrame:rect]; - - [step setMinValue:[low doubleValue]]; - [step setMaxValue:[high doubleValue]]; - [step setAutorepeat:YES]; - [step setValueWraps:NO]; - - double range = [high doubleValue] - [low doubleValue]; - if (range < 1.0) - [step setIncrement:range / 10.0]; - else if (range >= 500) - [step setIncrement:range / 100.0]; - else - [step setIncrement:1.0]; - - NSNumberFormatter *fmt = [[[NSNumberFormatter alloc] init] autorelease]; - [fmt setFormatterBehavior:NSNumberFormatterBehavior10_4]; - [fmt setNumberStyle:NSNumberFormatterDecimalStyle]; - [fmt setMinimum:[NSNumber numberWithDouble:[low doubleValue]]]; - [fmt setMaximum:[NSNumber numberWithDouble:[high doubleValue]]]; - [fmt setMinimumFractionDigits: (float_p ? 1 : 0)]; - [fmt setMaximumFractionDigits: (float_p ? 2 : 0)]; - - [fmt setGeneratesDecimalNumbers:float_p]; - [[txt cell] setFormatter:fmt]; - - [self bindSwitch:step cmdline:arg]; - [self bindSwitch:txt cmdline:arg]; - - [step release]; - [txt release]; - -# endif // USE_IPHONE - - } else { - NSAssert2 (0, @"unknown type \"%@\" in \"%@\"", type, label); - } -} - - -# ifndef USE_IPHONE -static void -set_menu_item_object (NSMenuItem *item, NSObject *obj) -{ - /* If the object associated with this menu item looks like a boolean, - store an NSNumber instead of an NSString, since that's what - will be in the preferences (due to similar logic in PrefsReader). - */ - if ([obj isKindOfClass:[NSString class]]) { - NSString *string = (NSString *) obj; - if (NSOrderedSame == [string caseInsensitiveCompare:@"true"] || - NSOrderedSame == [string caseInsensitiveCompare:@"yes"]) - obj = [NSNumber numberWithBool:YES]; - else if (NSOrderedSame == [string caseInsensitiveCompare:@"false"] || - NSOrderedSame == [string caseInsensitiveCompare:@"no"]) - obj = [NSNumber numberWithBool:NO]; - else - obj = string; - } - - [item setRepresentedObject:obj]; - //NSLog (@"menu item \"%@\" = \"%@\" %@", [item title], obj, [obj class]); -} -# endif // !USE_IPHONE - - -/* Creates the popup menu described by the given XML node (and its children). - */ -- (void) makeOptionMenu:(NSXMLNode *)node on:(NSView *)parent -{ - NSArray *children = [node children]; - NSUInteger i, count = [children count]; - - if (count <= 0) { - NSAssert1 (0, @"no menu items in \"%@\"", [node name]); - return; - } - - // get the "id" attribute off the - //

- - -
- */ - - //
- - NSRect rect; - rect.size.width = rect.size.height = 1; - rect.origin.x = rect.origin.y = 0; - NSView *group = [[NSView alloc] initWithFrame:rect]; - - NSXMLElement *node2; - - // - - node2 = [[NSXMLElement alloc] initWithName:@"boolean"]; - [node2 setAttributesAsDictionary: - @{ @"id": @SUSUEnableAutomaticChecksKey, - @"_label": @"Automatically check for updates", - @"arg-unset": @"-no-" SUSUEnableAutomaticChecksKey, - }]; - [self makeCheckbox:node2 on:group]; - [node2 release]; - - //