+
+#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];
+ }
+}
+
+- (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 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 <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 = 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:
+ @"<!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.
+ " -webkit-text-size-adjust: none;"
+ "}"
+ "\n//-->\n"
+ "</STYLE>"
+ "</HEAD>"
+ "<BODY>"
+ "%@"
+ "</BODY>"
+ "</HTML>",
+ [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:@" <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];
+ }
+
+ h = [h stringByReplacingOccurrencesOfString:@" <P> " withString:@"<P>"];
+ h = [h stringByReplacingOccurrencesOfString:@"<BR><P>" withString:@"<P>"];
+ 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:@"<P>"
+ withString:@"<BR><BR>"
+ options:NSCaseInsensitiveSearch
+ range:NSMakeRange(0, [str length])];
+ str = [str stringByReplacingOccurrencesOfString:@"<BR>"
+ 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)
+
+- (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
+