#endif // USE_IPHONE
#undef LABEL_ABOVE_SLIDER
+#define USE_HTML_LABELS
#pragma mark XML Parser
# endif // !USE_PICKER_VIEW
+# pragma mark Implementing labels with clickable links
+
+#if defined(USE_IPHONE) && defined(USE_HTML_LABELS)
+
+@interface HTMLLabel : UIView <UIWebViewDelegate>
+{
+ 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 = (UIViewAutoresizingFlexibleWidth |
+ UIViewAutoresizingFlexibleHeight);
+ webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
+ UIViewAutoresizingFlexibleHeight);
+ [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:
+ @"<!DOCTYPE HTML PUBLIC "
+ "\"-//W3C//DTD HTML 4.01 Transitional//EN\""
+ " \"http://www.w3.org/TR/html4/loose.dtd\">"
+ "<HTML>"
+ "<HEAD>"
+// "<META NAME=\"viewport\" CONTENT=\""
+// "width=device-width"
+// "initial-scale=1.0;"
+// "maximum-scale=1.0;\">"
+ "<STYLE>"
+ "<!--\n"
+ "body {"
+ " margin: 0; padding: 0; border: 0;"
+ " font-family: \"%@\";"
+ " font-size: %.4fpx;" // Must be "px", not "pt"!
+ " line-height: %.4fpx;" // And no spaces before it.
+ "}"
+ "\n//-->\n"
+ "</STYLE>"
+ "</HEAD>"
+ "<BODY>"
+ "%@"
+ "</BODY>"
+ "</HTML>",
+ [font fontName],
+ [font pointSize],
+ [font lineHeight],
+ h];
+ [webView loadHTMLString:h2 baseURL:[NSURL URLWithString:@""]];
+}
+
+
+static char *anchorize (const char *url);
+
+- (void) setText: (NSString *)t
+{
+ t = [t stringByReplacingOccurrencesOfString:@"&" withString:@"&"];
+ t = [t stringByReplacingOccurrencesOfString:@"<" withString:@"<"];
+ t = [t stringByReplacingOccurrencesOfString:@">" withString:@">"];
+ t = [t stringByReplacingOccurrencesOfString:@"\n\n" withString:@" <P> "];
+ t = [t stringByReplacingOccurrencesOfString:@"<P> "
+ withString:@"<P> "];
+ t = [t stringByReplacingOccurrencesOfString:@"\n "
+ withString:@"<BR> "];
+
+ 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: @"<A HREF=\"%@\">%@</A><BR>", s, a2];
+ free (anchor);
+ }
+ h = [NSString stringWithFormat: @"%@ %@", h, s];
+ }
+ [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];
+ [self setHTML: html];
+ [webView reload];
+}
+
+
+- (NSString *) stripTags:(NSString *)str
+{
+ NSString *result = @"";
+
+ str = [str stringByReplacingOccurrencesOfString:@"<P>"
+ withString:@"<BR><BR>"
+ options:NSCaseInsensitiveSearch
+ range:NSMakeRange(0, [str length])];
+ str = [str stringByReplacingOccurrencesOfString:@"<BR>"
+ withString:@"\n"
+ options:NSCaseInsensitiveSearch
+ range:NSMakeRange(0, [str length])];
+
+ 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];
+ }
+ 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 I can't make that work.
+ Maybe because it loads async?
+ */
+# 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: UILineBreakModeWordWrap];
+
+ // GAAAH. Add one more line, or the UIWebView is still scrollable!
+ // The text is sized right, but it lets you scroll it up anyway.
+ s.height += [font pointSize];
+
+ 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)
# 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
}
+#if !defined(USE_IPHONE) || !defined(USE_HTML_LABELS)
+
/* Converts any http: URLs in the given text field to clickable links.
*/
static void
# endif
}
+#endif /* !USE_IPHONE || !USE_HTML_LABELS */
+
+
#pragma mark Creating controls from XML
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
}
[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
[lab setBackgroundColor:[UIColor clearColor]];
[lab setNumberOfLines:0]; // unlimited
- [lab setLineBreakMode:UILineBreakModeWordWrap];
+ // [lab setLineBreakMode:UILineBreakModeWordWrap];
+ [lab setLineBreakMode:UILineBreakModeHeadTruncation];
[lab setAutoresizingMask: (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight)];
# endif // USE_IPHONE
for (NSArray *item in items) {
RadioButton *b = [[RadioButton alloc] initWithIndex:i
items:items];
- [b setFont:[NSFont boldSystemFontOfSize:
- // #### Fucking hardcoded UITableView font size BS!
- 17 // [NSFont systemFontSize]
- ]];
+ [b setLineBreakMode:UILineBreakModeHeadTruncation];
+ [b setFont:[NSFont boldSystemFontOfSize: FONT_SIZE]];
[self placeChild:b on:parent];
i++;
}
hreffify (lab);
boldify (lab);
[lab sizeToFit];
+
# else // USE_IPHONE
+
+# ifndef USE_HTML_LABELS
+
UILabel *lab = [self makeLabel:text];
[lab setFont:[NSFont systemFontOfSize: [NSFont systemFontSize]]];
hreffify (lab);
+
+# else // USE_HTML_LABELS
+ HTMLLabel *lab = [[HTMLLabel alloc]
+ initWithText:text
+ font:[NSFont systemFontOfSize: [NSFont systemFontSize]]];
+ [lab setFrame:rect];
+ [lab sizeToFit];
+# endif // USE_HTML_LABELS
+
[self placeSeparator];
+
# endif // USE_IPHONE
[self placeChild:lab on:parent];
txt.adjustsFontSizeToFitWidth = YES;
txt.textColor = [UIColor blackColor];
- // #### Fucking hardcoded UITableView font size BS!
- txt.font = [UIFont systemFontOfSize: 17];
+ txt.font = [UIFont systemFontOfSize: FONT_SIZE];
txt.placeholder = @"";
txt.borderStyle = UITextBorderStyleRoundedRect;
txt.textAlignment = UITextAlignmentRight;
- (void) makeImageLoaderControlBox:(NSXMLNode *)node on:(NSView *)parent
{
-# ifndef USE_IPHONE
/*
[x] Grab desktop images
[ ] Choose random image:
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",
+ @ SCREENS, @"_label",
@"-no-grab-desktop", @"arg-unset",
nil]];
[self makeCheckbox:node2 on:parent];
[node2 setAttributesAsDictionary:
[NSDictionary dictionaryWithObjectsAndKeys:
@"chooseRandomImages", @"id",
- @"Choose random images", @"_label",
+ @ PHOTOS, @"_label",
@"-choose-random-images", @"arg-set",
nil]];
[self makeCheckbox:node2 on:parent];
[self makeFileSelector:node2 on:parent
dirsOnly:YES withLabel:YES editable:YES];
+# undef SCREENS
+# undef PHOTOS
+
+# ifndef USE_IPHONE
// Add a second, explanatory label below the file/URL selector.
LABEL *lab2 = 0;
r2.origin.y += 14;
[lab2 setFrameOrigin:r2.origin];
[lab2 release];
-# endif // !USE_IPHONE
+# endif // USE_IPHONE
}
}
saver_name = [self parseXScreenSaverTag: node];
+ saver_name = [saver_name stringByReplacingOccurrencesOfString:@" "
+ withString:@""];
[saver_name retain];
# ifndef USE_IPHONE
- (CGFloat)pickerView:(UIPickerView *)pv
rowHeightForComponent:(NSInteger)column
{
- return [NSFont systemFontSize] * 1.5; // #### WHAT
+ return FONT_SIZE;
}
- (CGFloat)pickerView:(UIPickerView *)pv
style: UIBarButtonItemStyleBordered
target:self
action:@selector(resetAction:)]];
+ NSString *s = saver_name;
+ if ([self view].frame.size.width > 320)
+ s = [s stringByAppendingString: @" Settings"];
+ [self navigationItem].title = s;
}
titleForHeaderInSection:(NSInteger)section
{
// Titles above each vertically-stacked white box.
- if (section == 0)
- return [saver_name stringByAppendingString:@" Settings"];
+// if (section == 0)
+// return [saver_name stringByAppendingString:@" Settings"];
return nil;
}
[t sizeToFit];
r = t.frame;
h = r.size.height + LINE_SPACING * 3;
+# ifdef USE_HTML_LABELS
+ } else if ([ctl isKindOfClass:[HTMLLabel class]]) {
+
+ HTMLLabel *t = (HTMLLabel *) ctl;
+ CGRect r = t.frame;
+ r.size.width = [tv frame].size.width;
+ r.size.width -= LEFT_MARGIN * 2;
+ [t setFrame:r];
+ [t sizeToFit];
+ r = t.frame;
+ h = r.size.height + LINE_SPACING * 3;
+
+# endif // USE_HTML_LABELS
} else {
CGFloat h2 = [ctl frame].size.height;
h2 += LINE_SPACING * 2;
case 2:
{
// With 2 elements, the first of the pair must be a label.
- ctl = [set objectAtIndex: 0];
- NSAssert ([ctl isKindOfClass:[UILabel class]], @"unhandled type");
- cell.textLabel.text = [(UILabel *) ctl text];
+ UILabel *label = (UILabel *) [set objectAtIndex: 0];
+ NSAssert ([label isKindOfClass:[UILabel class]], @"unhandled type");
ctl = [set objectAtIndex: 1];
r = [ctl frame];
}
r.origin.y = (p.size.height - r.size.height) / 2;
[ctl setFrame:r];
+
+ // Make a box.
+ NSView *box = [[UIView alloc] initWithFrame:p];
+ [box addSubview: ctl];
+
+ // cell.textLabel.text = [(UILabel *) ctl text];
+ r = [label frame];
+ r.origin.x = LEFT_MARGIN;
+ r.origin.y = 0;
+ r.size.width = [ctl frame].origin.x - r.origin.x;
+ r.size.height = p.size.height;
+ [label setFrame:r];
+ [label setFont:[NSFont boldSystemFontOfSize: FONT_SIZE]];
+ label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
+ box. autoresizingMask = UIViewAutoresizingFlexibleWidth;
+ [box addSubview: label];
+
+ ctl = box;
}
break;
case 3:
// Top label goes above, flush center/top.
if (top) {
- // [top setFont:[[cell textLabel] font]]; // 0 point?
r.size = [[top text] sizeWithFont:[top font]
constrainedToSize:
CGSizeMake (p.size.width - LEFT_MARGIN*2,
top.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin|
UIViewAutoresizingFlexibleRightMargin);
# else
- cell.textLabel.text = [top text];
+ r = [top frame];
+ r.origin.x = LEFT_MARGIN;
+ r.origin.y = 0;
+ r.size.width = [mid frame].origin.x - r.origin.x;
+ r.size.height = p.size.height;
+ [top setFrame:r];
+ top.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
+ [ctl addSubview: top];
# endif
}
[ctl addSubview: left];
# endif // USE_PICKER_VIEW
}
+ if ([ctl isKindOfClass:[UILabel class]]) {
+ // Make label full height to allow text to line-wrap if necessary.
+ r = [ctl frame];
+ r.origin.y = p.origin.y;
+ r.size.height = p.size.height;
+ [ctl setFrame:r];
+ }
+
[cell.contentView addSubview: ctl];
return cell;