X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=OSX%2FXScreenSaverConfigSheet.m;h=576c8ab3e805f6efe71131c17a6b8dc88ab9a7e7;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=12980fa7cf2f6222c15a3dd8394e797ca46dda62;hpb=f8cf5ac7b2f53510f80a0eaf286a25298be17bfe;p=xscreensaver diff --git a/OSX/XScreenSaverConfigSheet.m b/OSX/XScreenSaverConfigSheet.m index 12980fa7..576c8ab3 100644 --- a/OSX/XScreenSaverConfigSheet.m +++ b/OSX/XScreenSaverConfigSheet.m @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 2006-2012 Jamie Zawinski +/* xscreensaver, Copyright (c) 2006-2016 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 @@ -24,6 +24,7 @@ */ #import "XScreenSaverConfigSheet.h" +#import "Updater.h" #import "jwxyz.h" #import "InvertedSlider.h" @@ -48,6 +49,7 @@ #endif // USE_IPHONE #undef LABEL_ABOVE_SLIDER +#define USE_HTML_LABELS #pragma mark XML Parser @@ -127,6 +129,7 @@ typedef enum { SimpleXMLCommentKind, [n setName:key]; [n setObjectValue:val]; [attributes addObject:n]; + [n release]; } } @@ -147,6 +150,48 @@ typedef enum { SimpleXMLCommentKind, @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. @@ -191,6 +236,249 @@ typedef enum { SimpleXMLCommentKind, # 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 sizeWithFont: font + constrainedToSize: s + lineBreakMode:NSLineBreakByWordWrapping]; + 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) @@ -219,6 +507,7 @@ static void layout_group (NSView *group, BOOL horiz_p); # 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 @@ -229,7 +518,7 @@ static void layout_group (NSView *group, BOOL horiz_p); instead, so transform keys to "SAVERNAME.KEY". NOTE: This is duplicated in PrefsReader.m, cause I suck. -*/ + */ - (NSString *) makeKey:(NSString *)key { # ifdef USE_IPHONE @@ -255,7 +544,7 @@ static void layout_group (NSView *group, BOOL horiz_p); opts:(const XrmOptionDescRec *)opts_array valRet:(NSString **)val_ret { - char buf[255]; + char buf[1280]; char *tail = 0; NSAssert(cmdline_switch, @"cmdline switch is null"); if (! [cmdline_switch getCString:buf maxLength:sizeof(buf) @@ -306,6 +595,22 @@ static void layout_group (NSView *group, BOOL horiz_p); } +- (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. @@ -315,11 +620,17 @@ static void layout_group (NSView *group, BOOL horiz_p); if ([active_text_field canResignFirstResponder]) [active_text_field resignFirstResponder]; NSString *pref_key = [pref_keys objectAtIndex: [sender tag]]; - double v = [sender value]; - if (v == (int) v) - [userDefaultsController setInteger:v forKey:pref_key]; - else - [userDefaultsController setDouble:v forKey:pref_key]; + + // 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. @@ -330,7 +641,7 @@ static void layout_group (NSView *group, BOOL horiz_p); [active_text_field resignFirstResponder]; NSString *pref_key = [pref_keys objectAtIndex: [sender tag]]; NSString *v = ([sender isOn] ? @"true" : @"false"); - [userDefaultsController setObject:v forKey:pref_key]; + [[self controllerForKey:pref_key] setObject:v forKey:pref_key]; } # ifdef USE_PICKER_VIEW @@ -352,7 +663,7 @@ static void layout_group (NSView *group, BOOL horiz_p); //NSString *label = [a objectAtIndex:0]; NSString *pref_key = [a objectAtIndex:1]; NSObject *pref_val = [a objectAtIndex:2]; - [userDefaultsController setObject:pref_val forKey:pref_key]; + [[self controllerForKey:pref_key] setObject:pref_val forKey:pref_key]; } # else // !USE_PICKER_VIEW @@ -366,7 +677,7 @@ static void layout_group (NSView *group, BOOL horiz_p); NSArray *item = [[sender items] objectAtIndex: [sender index]]; NSString *pref_key = [item objectAtIndex:1]; NSObject *pref_val = [item objectAtIndex:2]; - [userDefaultsController setObject:pref_val forKey:pref_key]; + [[self controllerForKey:pref_key] setObject:pref_val forKey:pref_key]; } - (BOOL)textFieldShouldBeginEditing:(UITextField *)tf @@ -379,7 +690,7 @@ static void layout_group (NSView *group, BOOL horiz_p); { NSString *pref_key = [pref_keys objectAtIndex: [tf tag]]; NSString *txt = [tf text]; - [userDefaultsController setObject:txt forKey:pref_key]; + [[self controllerForKey:pref_key] setObject:txt forKey:pref_key]; } - (BOOL)textFieldShouldReturn:(UITextField *)tf @@ -398,15 +709,23 @@ static void layout_group (NSView *group, BOOL horiz_p); - (void) okAction:(NSObject *)arg { - [userDefaultsController commitEditing]; - [userDefaultsController save:self]; + // Without the setAppliesImmediately:, when the saver restarts, it's still + // got the old settings. -[XScreenSaverConfigSheet traverseTree] sets this + // to NO; default is YES. + [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]; + [userDefaultsController revert:self]; + [globalDefaultsController revert:self]; [NSApp endSheet:self returnCode:NSCancelButton]; [self close]; } @@ -416,12 +735,13 @@ static void layout_group (NSView *group, BOOL horiz_p); - (void) resetAction:(NSObject *)arg { # ifndef USE_IPHONE - [userDefaultsController revertToInitialValues:self]; + [userDefaultsController revertToInitialValues:self]; + [globalDefaultsController revertToInitialValues:self]; # else // USE_IPHONE for (NSString *key in defaultOptions) { NSObject *val = [defaultOptions objectForKey:key]; - [userDefaultsController setObject:val forKey:key]; + [[self controllerForKey:key] setObject:val forKey:key]; } for (UIControl *ctl in pref_ctls) { @@ -439,19 +759,28 @@ static void layout_group (NSView *group, BOOL horiz_p); - (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:userDefaultsController + toObject:prefs withKeyPath:[@"values." stringByAppendingString: pref_key] - options:nil]; + options:opts_dict]; + # else // USE_IPHONE SEL sel; - NSObject *val = [userDefaultsController objectForKey:pref_key]; + NSObject *val = [prefs objectForKey:pref_key]; NSString *sval = 0; double dval = 0; @@ -471,7 +800,11 @@ static void layout_group (NSView *group, BOOL horiz_p); if ([control isKindOfClass:[UISlider class]]) { sel = @selector(sliderAction:); - [(UISlider *) control setValue: dval]; + // 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)]; @@ -512,12 +845,20 @@ static void layout_group (NSView *group, BOOL horiz_p); # endif // USE_IPHONE # if 0 - NSObject *def = [[userDefaultsController defaults] objectForKey:pref_key]; + 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]; - s = [s stringByPaddingToLength:28 withString:@" " startingAtIndex:0]; - NSLog (@"%@ %@/%@", s, [def class], [control class]); + 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 } @@ -546,9 +887,8 @@ unwrap (NSString *text) // Unwrap lines: delete \n but do not delete \n\n. // NSArray *lines = [text componentsSeparatedByString:@"\n"]; - int nlines = [lines count]; + NSUInteger i, nlines = [lines count]; BOOL eolp = YES; - int i; text = @"\n"; // start with one blank line @@ -681,6 +1021,8 @@ anchorize (const char *url) } +#if !defined(USE_IPHONE) || !defined(USE_HTML_LABELS) + /* Converts any http: URLs in the given text field to clickable links. */ static void @@ -765,6 +1107,9 @@ hreffify (NSText *nstext) # endif } +#endif /* !USE_IPHONE || !USE_HTML_LABELS */ + + #pragma mark Creating controls from XML @@ -779,7 +1124,7 @@ hreffify (NSText *nstext) - (void) parseAttrs:(NSMutableDictionary *)dict node:(NSXMLNode *)node { NSArray *attrs = [(NSXMLElement *) node attributes]; - int n = [attrs count]; + NSUInteger n = [attrs count]; int i; // For each key in the dictionary, fill in the dict with the corresponding @@ -812,6 +1157,26 @@ hreffify (NSText *nstext) 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 } @@ -819,15 +1184,15 @@ hreffify (NSText *nstext) */ - (NSString *) parseXScreenSaverTag:(NSXMLNode *)node { - NSMutableDictionary *dict = - [NSMutableDictionary dictionaryWithObjectsAndKeys: - @"", @"name", - @"", @"_label", - @"", @"gl", - nil]; + 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); @@ -856,10 +1221,12 @@ hreffify (NSText *nstext) [NSCharacterSet whitespaceAndNewlineCharacterSet]]]; [lab setBackgroundColor:[UIColor clearColor]]; [lab setNumberOfLines:0]; // unlimited - [lab setLineBreakMode:UILineBreakModeWordWrap]; + // [lab setLineBreakMode:UILineBreakModeWordWrap]; + [lab setLineBreakMode:NSLineBreakByTruncatingHead]; [lab setAutoresizingMask: (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; # endif // USE_IPHONE + [lab autorelease]; return lab; } @@ -868,17 +1235,17 @@ hreffify (NSText *nstext) */ - (void) makeCheckbox:(NSXMLNode *)node on:(NSView *)parent { - NSMutableDictionary *dict = - [NSMutableDictionary dictionaryWithObjectsAndKeys: - @"", @"id", - @"", @"_label", - @"", @"arg-set", - @"", @"arg-unset", - nil]; + 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]); @@ -922,7 +1289,6 @@ hreffify (NSText *nstext) [self placeChild:lab on:parent]; UISwitch *button = [[UISwitch alloc] initWithFrame:rect]; [self placeChild:button on:parent right:YES]; - [lab release]; # endif // USE_IPHONE @@ -934,22 +1300,20 @@ hreffify (NSText *nstext) /* 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 = - [NSMutableDictionary dictionaryWithObjectsAndKeys: - @"", @"id", - @"", @"_label", - @"", @"_low-label", - @"", @"_high-label", - @"", @"type", - @"", @"arg", - @"", @"low", - @"", @"high", - @"", @"default", - @"", @"convert", - nil]; + 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"]; @@ -960,6 +1324,8 @@ hreffify (NSText *nstext) 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); @@ -1013,6 +1379,7 @@ hreffify (NSText *nstext) 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; @@ -1021,7 +1388,6 @@ hreffify (NSText *nstext) if (float_p && range2 < max_ticks) range2 = max_ticks; -# ifndef USE_IPHONE [slider setNumberOfTickMarks:range2]; [slider setAllowsTickMarkValuesOnly: @@ -1044,7 +1410,6 @@ hreffify (NSText *nstext) [lab setFont:[NSFont boldSystemFontOfSize:s]]; } # endif - [lab release]; } if (low_label) { @@ -1059,11 +1424,11 @@ hreffify (NSText *nstext) [lab setFrame:rect]; [self placeChild:lab on:parent]; # else // USE_IPHONE - [lab setTextAlignment: UITextAlignmentRight]; + [lab setTextAlignment: NSTextAlignmentRight]; + // Sometimes rotation screws up truncation. + [lab setLineBreakMode:NSLineBreakByClipping]; [self placeChild:lab on:parent right:(label ? YES : NO)]; # endif // USE_IPHONE - - [lab release]; } # ifndef USE_IPHONE @@ -1094,8 +1459,11 @@ hreffify (NSText *nstext) // 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]; - [lab release]; } [self bindSwitch:slider cmdline:arg]; @@ -1135,7 +1503,6 @@ hreffify (NSText *nstext) rect.size.height = [txt frame].size.height; [lab setFrame:rect]; [self placeChild:lab on:parent]; - [lab release]; } [self placeChild:txt on:parent right:(label ? YES : NO)]; @@ -1221,11 +1588,11 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj) /* Creates the popup menu described by the given XML node (and its children). -*/ + */ - (void) makeOptionMenu:(NSXMLNode *)node on:(NSView *)parent { NSArray *children = [node children]; - int i, count = [children count]; + NSUInteger i, count = [children count]; if (count <= 0) { NSAssert1 (0, @"no menu items in \"%@\"", [node name]); @@ -1234,11 +1601,10 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj) // get the "id" attribute off the node2 = [[NSXMLElement alloc] initWithName:@"select"]; - [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"textMode", @"id", - nil]]; + [node2 setAttributesAsDictionary:@{ @"id": @"textMode" }]; NSXMLNode *node3 = [[NSXMLElement alloc] initWithName:@"option"]; [node3 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"date", @"id", - @"-text-mode date", @"arg-set", - @"Display the date and time", @"_label", - nil]]; + @{ @"id": @"date", + @"arg-set": @"-text-mode date", + @"_label": @"Display the date and time" }]; [node3 setParent: node2]; - //[node3 release]; + [node3 autorelease]; node3 = [[NSXMLElement alloc] initWithName:@"option"]; [node3 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"text", @"id", - @"-text-mode literal", @"arg-set", - @"Display static text", @"_label", - nil]]; + @{ @"id": @"text", + @"arg-set": @"-text-mode literal", + @"_label": @"Display static text" }]; [node3 setParent: node2]; - //[node3 release]; + [node3 autorelease]; node3 = [[NSXMLElement alloc] initWithName:@"option"]; [node3 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"url", @"id", - @"Display the contents of a URL", @"_label", - nil]]; + @{ @"id": @"url", + @"_label": @"Display the contents of a URL" }]; [node3 setParent: node2]; - //[node3 release]; + [node3 autorelease]; [self makeOptionMenu:node2 on:rgroup]; + [node2 release]; # endif // USE_IPHONE @@ -1879,13 +2224,12 @@ find_text_field_of_button (NSButton *button) // node2 = [[NSXMLElement alloc] initWithName:@"string"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"textLiteral", @"id", - @"-text-literal %", @"arg", + @{ @"id": @"textLiteral", + @"arg": @"-text-literal %", # ifdef USE_IPHONE - @"Text to display", @"_label", + @"_label": @"Text to display" # endif - nil]]; + }]; [self makeTextField:node2 on:rgroup # ifndef USE_IPHONE withLabel:NO @@ -1893,6 +2237,7 @@ find_text_field_of_button (NSButton *button) withLabel:YES # endif horizontal:NO]; + [node2 release]; // rect = [last_child(rgroup) frame]; @@ -1902,19 +2247,18 @@ find_text_field_of_button (NSButton *button) toObject:[matrix cellAtRow:1 column:0] withKeyPath:@"value" options:nil]; -*/ + */ # ifndef USE_IPHONE // node2 = [[NSXMLElement alloc] initWithName:@"string"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"textFile", @"id", - @"-text-file %", @"arg", - nil]]; + @{ @"id": @"textFile", + @"arg": @"-text-file %" }]; [self makeFileSelector:node2 on:rgroup dirsOnly:NO withLabel:NO editable:NO]; + [node2 release]; # endif // !USE_IPHONE // rect = [last_child(rgroup) frame]; @@ -1922,13 +2266,12 @@ find_text_field_of_button (NSButton *button) // node2 = [[NSXMLElement alloc] initWithName:@"string"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"textURL", @"id", - @"-text-url %", @"arg", + @{ @"id": @"textURL", + @"arg": @"-text-url %", # ifdef USE_IPHONE - @"URL to display", @"_label", + @"_label": @"URL to display", # endif - nil]]; + }]; [self makeTextField:node2 on:rgroup # ifndef USE_IPHONE withLabel:NO @@ -1936,6 +2279,7 @@ find_text_field_of_button (NSButton *button) withLabel:YES # endif horizontal:NO]; + [node2 release]; // rect = [last_child(rgroup) frame]; @@ -1944,11 +2288,11 @@ find_text_field_of_button (NSButton *button) // node2 = [[NSXMLElement alloc] initWithName:@"string"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"textProgram", @"id", - @"-text-program %", @"arg", - nil]]; + @{ @"id": @"textProgram", + @"arg": @"-text-program %", + }]; [self makeTextField:node2 on:rgroup withLabel:NO horizontal:NO]; + [node2 release]; } // rect = [last_child(rgroup) frame]; @@ -2004,6 +2348,8 @@ find_text_field_of_button (NSButton *button) [box sizeToFit]; [self placeChild:box on:parent]; + [group release]; + [box release]; # endif // !USE_IPHONE } @@ -2011,7 +2357,6 @@ find_text_field_of_button (NSButton *button) - (void) makeImageLoaderControlBox:(NSXMLNode *)node on:(NSView *)parent { -# ifndef USE_IPHONE /* [x] Grab desktop images [ ] Choose random image: @@ -2026,34 +2371,46 @@ find_text_field_of_button (NSButton *button) NSXMLElement *node2; +# ifndef USE_IPHONE +# define SCREENS "Grab desktop images" +# define PHOTOS "Choose random images" +# else +# define SCREENS "Grab screenshots" +# define PHOTOS "Use photo library" +# endif + node2 = [[NSXMLElement alloc] initWithName:@"boolean"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"grabDesktopImages", @"id", - @"Grab desktop images", @"_label", - @"-no-grab-desktop", @"arg-unset", - nil]]; + @{ @"id": @"grabDesktopImages", + @"_label": @ SCREENS, + @"arg-unset": @"-no-grab-desktop", + }]; [self makeCheckbox:node2 on:parent]; + [node2 release]; node2 = [[NSXMLElement alloc] initWithName:@"boolean"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"chooseRandomImages", @"id", - @"Choose random images", @"_label", - @"-choose-random-images", @"arg-set", - nil]]; + @{ @"id": @"chooseRandomImages", + @"_label": @ PHOTOS, + @"arg-set": @"-choose-random-images", + }]; [self makeCheckbox:node2 on:parent]; + [node2 release]; node2 = [[NSXMLElement alloc] initWithName:@"string"]; [node2 setAttributesAsDictionary: - [NSDictionary dictionaryWithObjectsAndKeys: - @"imageDirectory", @"id", - @"Images from:", @"_label", - @"-image-directory %", @"arg", - nil]]; + @{ @"id": @"imageDirectory", + @"_label": @"Images from:", + @"arg": @"-image-directory %", + }]; [self makeFileSelector:node2 on:parent dirsOnly:YES withLabel:YES editable:YES]; + [node2 release]; +# undef SCREENS +# undef PHOTOS + +# ifndef USE_IPHONE // Add a second, explanatory label below the file/URL selector. LABEL *lab2 = 0; @@ -2065,7 +2422,111 @@ find_text_field_of_button (NSButton *button) r2.origin.x += 20; r2.origin.y += 14; [lab2 setFrameOrigin:r2.origin]; - [lab2 release]; +# endif // USE_IPHONE +} + + +- (void) makeUpdaterControlBox:(NSXMLNode *)node on:(NSView *)parent +{ +# ifndef USE_IPHONE + /* + [x] Check for Updates [ Monthly ] + +

+ + +
+ */ + + //
+ + 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]; + + //