From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / OSX / XScreenSaverConfigSheet.m
index 1e58dc26666a6aafcd20acd6d1a4f31853cdf7c3..eaa5add13cb4da1e07cf56c3f84c5763a4b5379b 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2006-2013 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2006-2017 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -129,6 +129,7 @@ typedef enum { SimpleXMLCommentKind,
     [n setName:key];
     [n setObjectValue:val];
     [attributes addObject:n];
+    [n release];
   }
 }
 
@@ -149,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.
@@ -228,10 +271,13 @@ typedef enum { SimpleXMLCommentKind,
   webView = [[UIWebView alloc] init];
   webView.delegate = self;
   webView.dataDetectorTypes = UIDataDetectorTypeNone;
-  self.   autoresizingMask = (UIViewAutoresizingFlexibleWidth |
-                              UIViewAutoresizingFlexibleHeight);
-  webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
-                              UIViewAutoresizingFlexibleHeight);
+  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;
@@ -270,6 +316,7 @@ typedef enum { SimpleXMLCommentKind,
                       " 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>"
@@ -282,6 +329,7 @@ typedef enum { SimpleXMLCommentKind,
               [font pointSize],
               [font lineHeight],
               h];
+  [webView stopLoading];
   [webView loadHTMLString:h2 baseURL:[NSURL URLWithString:@""]];
 }
 
@@ -290,6 +338,8 @@ static char *anchorize (const char *url);
 
 - (void) setText: (NSString *)t
 {
+  t = [t stringByTrimmingCharactersInSet:[NSCharacterSet
+                                           whitespaceCharacterSet]];
   t = [t stringByReplacingOccurrencesOfString:@"&" withString:@"&amp;"];
   t = [t stringByReplacingOccurrencesOfString:@"<" withString:@"&lt;"];
   t = [t stringByReplacingOccurrencesOfString:@">" withString:@"&gt;"];
@@ -313,6 +363,12 @@ static char *anchorize (const char *url);
     }
     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];
 }
 
@@ -336,8 +392,6 @@ static char *anchorize (const char *url);
   r.origin.x = 0;
   r.origin.y = 0;
   [webView setFrame: r];
-  [self setHTML: html];
-  [webView reload];
 }
 
 
@@ -345,6 +399,7 @@ static char *anchorize (const char *url);
 {
   NSString *result = @"";
 
+  // Add newlines.
   str = [str stringByReplacingOccurrencesOfString:@"<P>"
              withString:@"<BR><BR>"
              options:NSCaseInsensitiveSearch
@@ -354,12 +409,25 @@ static char *anchorize (const char *url);
              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;
 }
 
@@ -370,8 +438,15 @@ static char *anchorize (const char *url);
 
   /* 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?
+     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
@@ -382,14 +457,10 @@ static char *anchorize (const char *url);
   NSString *text = [self stripTags: html];
   CGSize s = r.size;
   s.height = 999999;
-  s = [text sizeWithFont: font
-            constrainedToSize: s
-            lineBreakMode:NSLineBreakByWordWrapping];
-
-  // 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];
-
+  s = [text boundingRectWithSize:s
+                         options:NSStringDrawingUsesLineFragmentOrigin
+                      attributes:@{NSFontAttributeName: font}
+                         context:nil].size;
   r.size.height = s.height;
 # endif
 
@@ -474,7 +545,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)
@@ -639,6 +710,16 @@ static void layout_group (NSView *group, BOOL horiz_p);
 
 - (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];
@@ -686,15 +767,23 @@ static void layout_group (NSView *group, BOOL horiz_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:nil];
+        options:opts_dict];
+
 # else  // USE_IPHONE
   SEL sel;
   NSObject *val = [prefs objectForKey:pref_key];
@@ -765,9 +854,17 @@ static void layout_group (NSView *group, BOOL horiz_p);
   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
 }
 
@@ -825,6 +922,7 @@ unwrap (NSString *text)
       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.
@@ -870,12 +968,16 @@ boldify (NSText *nstext)
 static char *
 anchorize (const char *url)
 {
-  const char *wiki = "http://en.wikipedia.org/wiki/";
-  const char *math = "http://mathworld.wolfram.com/";
-  if (!strncmp (wiki, url, strlen(wiki))) {
+  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(wiki);
+    const char *in = url + strlen(!strncmp (wiki1, url, strlen(wiki1))
+                                  ? wiki1 : wiki2);
     char *out = anchor + strlen(anchor);
     while (*in) {
       if (*in == '_') {
@@ -901,10 +1003,12 @@ anchorize (const char *url)
     *out = 0;
     return anchor;
 
-  } else if (!strncmp (math, url, strlen(math))) {
+  } 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(wiki);
+    const char *start = url + strlen(!strncmp (math1, url, strlen(math1))
+                                     ? math1 : math2);
     const char *in = start;
     char *out = anchor + strlen(anchor);
     while (*in) {
@@ -944,7 +1048,7 @@ hreffify (NSText *nstext)
   NSString *text = [nstext text];
 # endif
 
-  int L = [text length];
+  NSUInteger L = [text length];
   NSRange start;               // range is start-of-search to end-of-string
   start.location = 0;
   start.length = L;
@@ -952,7 +1056,14 @@ hreffify (NSText *nstext)
 
     // Find the beginning of a URL...
     //
-    NSRange r2 = [text rangeOfString:@"http://" options:0 range:start];
+    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;
 
@@ -962,9 +1073,9 @@ hreffify (NSText *nstext)
 
     // Find the end of a URL (whitespace or EOF)...
     //
-    NSRange r3 = [text rangeOfCharacterFromSet:
-                         [NSCharacterSet whitespaceAndNewlineCharacterSet]
-                       options:0 range:start];
+    r3 = [text rangeOfCharacterFromSet:
+                 [NSCharacterSet whitespaceAndNewlineCharacterSet]
+               options:0 range:start];
     if (r3.location == NSNotFound)    // EOF
       r3.location = L, r3.length = 0;
 
@@ -1005,7 +1116,7 @@ hreffify (NSText *nstext)
 
     free (anchor);
 
-    int L2 = [text length];  // might have changed
+    NSUInteger L2 = [text length];  // might have changed
     start.location -= (L - L2);
     L = L2;
   }
@@ -1100,6 +1211,8 @@ hreffify (NSText *nstext)
   [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);
@@ -1133,6 +1246,7 @@ hreffify (NSText *nstext)
   [lab setAutoresizingMask: (UIViewAutoresizingFlexibleWidth |
                              UIViewAutoresizingFlexibleHeight)];
 # endif // USE_IPHONE
+  [lab autorelease];
   return lab;
 }
 
@@ -1150,6 +1264,8 @@ hreffify (NSText *nstext)
   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]);
@@ -1193,7 +1309,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
   
@@ -1229,6 +1344,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);
@@ -1282,6 +1399,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;
@@ -1290,7 +1408,6 @@ hreffify (NSText *nstext)
     if (float_p && range2 < max_ticks)
       range2 = max_ticks;
 
-# ifndef USE_IPHONE
     [slider setNumberOfTickMarks:range2];
 
     [slider setAllowsTickMarkValuesOnly:
@@ -1313,7 +1430,6 @@ hreffify (NSText *nstext)
         [lab setFont:[NSFont boldSystemFontOfSize:s]];
       }
 # endif
-      [lab release];
     }
     
     if (low_label) {
@@ -1329,10 +1445,10 @@ hreffify (NSText *nstext)
       [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
-
-      [lab release];
      }
     
 # ifndef USE_IPHONE
@@ -1363,8 +1479,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];
@@ -1404,7 +1523,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)];
@@ -1505,6 +1623,8 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   //
   NSMutableDictionary *dict = [@{ @"id": @"", } mutableCopy];
   [self parseAttrs:dict node:node];
+  [dict release];
+  dict = 0;
   
   NSRect rect;
   rect.origin.x = rect.origin.y = 0;
@@ -1557,6 +1677,8 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
     [self parseAttrs:dict2 node:child];
     NSString *label   = [dict2 objectForKey:@"_label"];
     NSString *arg_set = [dict2 objectForKey:@"arg-set"];
+    [dict2 release];
+    dict2 = 0;
     
     if (!label) {
       NSAssert1 (0, @"no _label in %@", [child name]);
@@ -1677,7 +1799,7 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   // Store the items for this picker in the picker_values array.
   // This is so fucking stupid.
 
-  int menu_number = [pref_keys count] - 1;
+  unsigned long menu_number = [pref_keys count] - 1;
   if (! picker_values)
     picker_values = [[NSMutableArray arrayWithCapacity:menu_number] retain];
   while ([picker_values count] <= menu_number)
@@ -1696,6 +1818,7 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
     [b setLineBreakMode:NSLineBreakByTruncatingHead];
     [b setFont:[NSFont boldSystemFontOfSize: FONT_SIZE]];
     [self placeChild:b on:parent];
+    [b release];
     i++;
   }
 
@@ -1733,6 +1856,7 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   rect.size.height = 50;  // sized later
 # ifndef USE_IPHONE
   NSText *lab = [[NSText alloc] initWithFrame:rect];
+  [lab autorelease];
   [lab setEditable:NO];
   [lab setDrawsBackground:NO];
   [lab setHorizontallyResizable:YES];
@@ -1754,6 +1878,7 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   HTMLLabel *lab = [[HTMLLabel alloc] 
                      initWithText:text
                      font:[NSFont systemFontOfSize: [NSFont systemFontSize]]];
+  [lab autorelease];
   [lab setFrame:rect];
   [lab sizeToFit];
 #  endif // USE_HTML_LABELS
@@ -1763,7 +1888,6 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
 # endif // USE_IPHONE
 
   [self placeChild:lab on:parent];
-  [lab release];
 }
 
 
@@ -1781,6 +1905,8 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   [self parseAttrs:dict node:node];
   NSString *label = [dict objectForKey:@"_label"];
   NSString *arg   = [dict objectForKey:@"arg"];
+  [dict release];
+  dict = 0;
 
   if (!label && label_p) {
     NSAssert1 (0, @"no _label in %@", [node name]);
@@ -1831,7 +1957,6 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   if (label) {
     LABEL *lab = [self makeLabel:label];
     [self placeChild:lab on:parent];
-    [lab release];
   }
 
   [self placeChild:txt on:parent right:(label ? YES : NO)];
@@ -1858,6 +1983,8 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   [self parseAttrs:dict node:node];
   NSString *label = [dict objectForKey:@"_label"];
   NSString *arg   = [dict objectForKey:@"arg"];
+  [dict release];
+  dict = 0;
 
   if (!label && label_p) {
     NSAssert1 (0, @"no _label in %@", [node name]);
@@ -1889,7 +2016,6 @@ set_menu_item_object (NSMenuItem *item, NSObject *obj)
   if (label) {
     lab = [self makeLabel:label];
     [self placeChild:lab on:parent];
-    [lab release];
   }
 
   [self placeChild:txt on:parent right:(label ? YES : NO)];
@@ -1947,21 +2073,10 @@ do_file_selector (NSTextField *txt, BOOL dirs_p)
   [panel setCanChooseFiles:!dirs_p];
   [panel setCanChooseDirectories:dirs_p];
 
-  NSString *file = [txt stringValue];
-  if ([file length] <= 0) {
-    file = NSHomeDirectory();
-    if (dirs_p)
-      file = [file stringByAppendingPathComponent:@"Pictures"];
-  }
-
-//  NSString *dir = [file stringByDeletingLastPathComponent];
-
-  int result = [panel runModalForDirectory:file //dir
-                                      file:nil //[file lastPathComponent]
-                                     types:nil];
+  NSInteger result = [panel runModal];
   if (result == NSOKButton) {
-    NSArray *files = [panel filenames];
-    file = ([files count] > 0 ? [files objectAtIndex:0] : @"");
+    NSArray *files = [panel URLs];
+    NSString *file = ([files count] > 0 ? [[files objectAtIndex:0] path] : @"");
     file = [file stringByAbbreviatingWithTildeInPath];
     [txt setStringValue:file];
 
@@ -1974,22 +2089,6 @@ do_file_selector (NSTextField *txt, BOOL dirs_p)
     if ([path hasPrefix:@"values."])  // WTF.
       path = [path substringFromIndex:7];
     [[prefs values] setValue:file forKey:path];
-
-#if 0
-    // make sure the end of the string is visible.
-    NSText *fe = [[txt window] fieldEditor:YES forObject:txt];
-    NSRange range;
-    range.location = [file length]-3;
-    range.length = 1;
-    if (! [[txt window] makeFirstResponder:[txt window]])
-      [[txt window] endEditingFor:nil];
-//    [[txt window] makeFirstResponder:nil];
-    [fe setSelectedRange:range];
-//    [tv scrollRangeToVisible:range];
-//    [txt setNeedsDisplay:YES];
-//    [[txt cell] setNeedsDisplay:YES];
-//    [txt selectAll:txt];
-#endif
   }
 }
 
@@ -2001,7 +2100,7 @@ find_text_field_of_button (NSButton *button)
 {
   NSView *parent = [button superview];
   NSArray *kids = [parent subviews];
-  int nkids = [kids count];
+  NSUInteger nkids = [kids count];
   int i;
   NSTextField *f = 0;
   for (i = 0; i < nkids; i++) {
@@ -2093,6 +2192,9 @@ find_text_field_of_button (NSButton *button)
 
   [self placeChild:matrix on:group];
   [self placeChild:rgroup on:group right:YES];
+  [proto release];
+  [matrix release];
+  [rgroup release];
 
   NSXMLNode *node2;
 
@@ -2116,7 +2218,7 @@ find_text_field_of_button (NSButton *button)
               @"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:
@@ -2124,16 +2226,17 @@ find_text_field_of_button (NSButton *button)
               @"arg-set": @"-text-mode literal",
               @"_label":  @"Display static text" }];
   [node3 setParent: node2];
-  //[node3 release];
+  [node3 autorelease];
 
   node3 = [[NSXMLElement alloc] initWithName:@"option"];
   [node3 setAttributesAsDictionary:
            @{ @"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
 
@@ -2154,6 +2257,7 @@ find_text_field_of_button (NSButton *button)
         withLabel:YES
 # endif
         horizontal:NO];
+  [node2 release];
 
 //  rect = [last_child(rgroup) frame];
 
@@ -2174,6 +2278,7 @@ find_text_field_of_button (NSButton *button)
               @"arg": @"-text-file %" }];
   [self makeFileSelector:node2 on:rgroup
         dirsOnly:NO withLabel:NO editable:NO];
+  [node2 release];
 # endif // !USE_IPHONE
 
 //  rect = [last_child(rgroup) frame];
@@ -2194,6 +2299,7 @@ find_text_field_of_button (NSButton *button)
         withLabel:YES
 # endif
         horizontal:NO];
+  [node2 release];
 
 //  rect = [last_child(rgroup) frame];
 
@@ -2206,6 +2312,7 @@ find_text_field_of_button (NSButton *button)
                  @"arg": @"-text-program %",
               }];
     [self makeTextField:node2 on:rgroup withLabel:NO horizontal:NO];
+    [node2 release];
   }
 
 //  rect = [last_child(rgroup) frame];
@@ -2261,6 +2368,8 @@ find_text_field_of_button (NSButton *button)
   [box sizeToFit];
 
   [self placeChild:box on:parent];
+  [group release];
+  [box release];
 
 # endif // !USE_IPHONE
 }
@@ -2297,6 +2406,7 @@ find_text_field_of_button (NSButton *button)
               @"arg-unset": @"-no-grab-desktop",
             }];
   [self makeCheckbox:node2 on:parent];
+  [node2 release];
 
   node2 = [[NSXMLElement alloc] initWithName:@"boolean"];
   [node2 setAttributesAsDictionary:
@@ -2305,6 +2415,7 @@ find_text_field_of_button (NSButton *button)
               @"arg-set": @"-choose-random-images",
             }];
   [self makeCheckbox:node2 on:parent];
+  [node2 release];
 
   node2 = [[NSXMLElement alloc] initWithName:@"string"];
   [node2 setAttributesAsDictionary:
@@ -2314,6 +2425,7 @@ find_text_field_of_button (NSButton *button)
             }];
   [self makeFileSelector:node2 on:parent
         dirsOnly:YES withLabel:YES editable:YES];
+  [node2 release];
 
 # undef SCREENS
 # undef PHOTOS
@@ -2330,7 +2442,6 @@ find_text_field_of_button (NSButton *button)
   r2.origin.x += 20;
   r2.origin.y += 14;
   [lab2 setFrameOrigin:r2.origin];
-  [lab2 release];
 # endif // USE_IPHONE
 }
 
@@ -2372,6 +2483,7 @@ find_text_field_of_button (NSButton *button)
               @"arg-unset": @"-no-" SUSUEnableAutomaticChecksKey,
             }];
   [self makeCheckbox:node2 on:group];
+  [node2 release];
 
   // <select ...>
 
@@ -2387,7 +2499,7 @@ find_text_field_of_button (NSButton *button)
               @"arg-set": @"-" SUScheduledCheckIntervalKey " 3600",
               @"_label":  @"Hourly" }];
   [node3 setParent: node2];
-  //[node3 release];
+  [node3 autorelease];
 
   node3 = [[NSXMLElement alloc] initWithName:@"option"];
   [node3 setAttributesAsDictionary:
@@ -2395,7 +2507,7 @@ find_text_field_of_button (NSButton *button)
               @"arg-set": @"-" SUScheduledCheckIntervalKey " 86400",
               @"_label":  @"Daily" }];
   [node3 setParent: node2];
-  //[node3 release];
+  [node3 autorelease];
 
   node3 = [[NSXMLElement alloc] initWithName:@"option"];
   [node3 setAttributesAsDictionary:
@@ -2404,7 +2516,7 @@ find_text_field_of_button (NSButton *button)
               @"_label": @"Weekly",
             }];
   [node3 setParent: node2];
-  //[node3 release];
+  [node3 autorelease];
 
   node3 = [[NSXMLElement alloc] initWithName:@"option"];
   [node3 setAttributesAsDictionary:
@@ -2413,10 +2525,11 @@ find_text_field_of_button (NSButton *button)
               @"_label":  @"Monthly",
              }];
   [node3 setParent: node2];
-  //[node3 release];
+  [node3 autorelease];
 
   // </option>
   [self makeOptionMenu:node2 on:group];
+  [node2 release];
 
   // </hgroup>
   layout_group (group, TRUE);
@@ -2446,7 +2559,7 @@ static NSView *
 last_child (NSView *parent)
 {
   NSArray *kids = [parent subviews];
-  int nkids = [kids count];
+  NSUInteger nkids = [kids count];
   if (nkids == 0)
     return 0;
   else
@@ -2488,7 +2601,25 @@ last_child (NSView *parent)
 
 # else // USE_IPHONE
 
-  // Controls is an array of arrays of the controls, divided into sections.
+  /* Controls is an array of arrays of the controls, divided into sections.
+     Each hgroup / vgroup gets a nested array, too, e.g.:
+
+       [ [ [ <label>, <checkbox> ],
+           [ <label>, <checkbox> ],
+           [ <label>, <checkbox> ] ],
+         [ <label>, <text-field> ],
+         [ <label>, <low-label>, <slider>, <high-label> ],
+         [ <low-label>, <slider>, <high-label> ],
+         <HTML-label>
+       ];
+
+     If an element begins with a label, it is terminal, otherwise it is a
+     group.  There are (currently) never more than 4 elements in a single
+     terminal element.
+
+     A blank vertical spacer is placed between each hgroup / vgroup,
+     by making each of those a new section in the TableView.
+   */
   if (! controls)
     controls = [[NSMutableArray arrayWithCapacity:10] retain];
   if ([controls count] == 0)
@@ -2506,7 +2637,7 @@ last_child (NSView *parent)
       NSAssert ([(NSArray *) old count] < 4, @"internal error");
       [(NSMutableArray *) old addObject: child];
     } else {
-      // Replace the control in this cell with an array, then app
+      // Replace the control in this cell with an array, then append
       NSMutableArray *a = [NSMutableArray arrayWithObjects: old, child, nil];
       [current replaceObjectAtIndex:[current count]-1 withObject:a];
     }
@@ -2567,6 +2698,8 @@ last_child (NSView *parent)
   [box sizeToFit];
 
   [self placeChild:box on:parent];
+  [group release];
+  [box release];
 # endif // !USE_IPHONE
 }
 
@@ -2576,8 +2709,8 @@ static void
 layout_group (NSView *group, BOOL horiz_p)
 {
   NSArray *kids = [group subviews];
-  int nkids = [kids count];
-  int i;
+  NSUInteger nkids = [kids count];
+  NSUInteger i;
   double maxx = 0, miny = 0;
   for (i = 0; i < nkids; i++) {
     NSView *kid = [kids objectAtIndex:i];
@@ -2649,6 +2782,9 @@ layout_group (NSView *group, BOOL horiz_p)
   } else if ([name isEqualToString:@"command"]) {
     // do nothing: this is the "-root" business
 
+  } else if ([name isEqualToString:@"video"]) {
+    // ignored
+
   } else if ([name isEqualToString:@"boolean"]) {
     [self makeCheckbox:node on:parent];
 
@@ -2705,10 +2841,10 @@ fix_contentview_size (NSView *parent)
 {
   NSRect f;
   NSArray *kids = [parent subviews];
-  int nkids = [kids count];
+  NSUInteger nkids = [kids count];
   NSView *text = 0;  // the NSText at the bottom of the window
   double maxx = 0, miny = 0;
-  int i;
+  NSUInteger i;
 
   /* Find the size of the rectangle taken up by each of the children
      except the final "NSText" child.
@@ -3019,6 +3155,7 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
         attributes:(NSDictionary *)attrs
 {
   NSXMLElement *e = [[NSXMLElement alloc] initWithName:elt];
+  [e autorelease];
   [e setKind:SimpleXMLElementKind];
   [e setAttributesAsDictionary:attrs];
   NSXMLElement *p = xml_parsing;
@@ -3052,6 +3189,7 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
   NSXMLElement *p = xml_parsing;
   [e setParent:p];
   [e setObjectValue: string];
+  [e autorelease];
 }
 
 
@@ -3091,6 +3229,7 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
   CGFloat max = 0;
   for (NSArray *a2 in a) {
     NSString *s = [a2 objectAtIndex:0];
+    // #### sizeWithFont deprecated as of iOS 7; use boundingRectWithSize.
     CGSize r = [s sizeWithFont:f];
     if (r.width > max) max = r.width;
   }
@@ -3129,7 +3268,7 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
   [[self navigationItem] 
     setRightBarButtonItem: [[UIBarButtonItem alloc]
                              initWithTitle: @"Reset to Defaults"
-                             style: UIBarButtonItemStyleBordered
+                             style: UIBarButtonItemStylePlain
                              target:self
                              action:@selector(resetAction:)]];
   NSString *s = saver_name;
@@ -3170,7 +3309,7 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
 - (CGFloat)tableView:(UITableView *)tv
            heightForRowAtIndexPath:(NSIndexPath *)ip
 {
-  CGFloat h = [tv rowHeight];
+  CGFloat h = 0;
 
   NSView *ctl = [[controls objectAtIndex:[ip indexAtPosition:0]]
                   objectAtIndex:[ip indexAtPosition:1]];
@@ -3178,27 +3317,19 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
   if ([ctl isKindOfClass:[NSArray class]]) {
     NSArray *set = (NSArray *) ctl;
     switch ([set count]) {
-    case 4:
-# ifdef LABEL_ABOVE_SLIDER
-      h *= 1.7; break; // label + left/slider/right: 2 1/2 lines
-# endif
-    case 3: h *= 1.2; break;   // left/slider/right: 1 1/2 lines
-    case 2:
-      if ([[set objectAtIndex:1] isKindOfClass:[UITextField class]])
-        h *= 1.2;
+    case 4:                    // label + left/slider/right.
+    case 3:                    // left/slider/right.
+      h = FONT_SIZE * 3.0;
+      break;
+    case 2:                    // Checkboxes, or text fields.
+      h = FONT_SIZE * 2.4;
       break;
     }
   } else if ([ctl isKindOfClass:[UILabel class]]) {
-    UILabel *t = (UILabel *) ctl;
-    CGRect r = t.frame;
-    r.size.width = 250;                // WTF! Black magic!
-    r.size.width -= LEFT_MARGIN;
-    [t setFrame:r];
-    [t sizeToFit];
-    r = t.frame;
-    h = r.size.height + LINE_SPACING * 3;
-# ifdef USE_HTML_LABELS
+    // Radio buttons in a multi-select list.
+    h = FONT_SIZE * 1.9;
 
+# ifdef USE_HTML_LABELS
   } else if ([ctl isKindOfClass:[HTMLLabel class]]) {
     
     HTMLLabel *t = (HTMLLabel *) ctl;
@@ -3208,15 +3339,14 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
     [t setFrame:r];
     [t sizeToFit];
     r = t.frame;
-    h = r.size.height + LINE_SPACING * 3;
-
+    h = r.size.height;
 # endif // USE_HTML_LABELS
-  } else {
-    CGFloat h2 = [ctl frame].size.height;
-    h2 += LINE_SPACING * 2;
-    if (h2 > h) h = h2;
+
+  } else {                     // Does this ever happen?
+    h = FONT_SIZE + LINE_SPACING * 2;
   }
 
+  if (h <= 0) abort();
   return h;
 }
 
@@ -3239,6 +3369,11 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
   [tv beginUpdates];
   [tv reloadRowsAtIndexPaths:a withRowAnimation:UITableViewRowAnimationNone];
   [tv endUpdates];
+
+  // Default opacity looks bad.
+  // #### Oh great, this only works *sometimes*.
+  UIView *v = [[self navigationItem] titleView];
+  [v setBackgroundColor:[[v backgroundColor] colorWithAlphaComponent:1]];
 }
 
 
@@ -3304,46 +3439,23 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
 - (UITableViewCell *)tableView:(UITableView *)tv
                      cellForRowAtIndexPath:(NSIndexPath *)ip
 {
-#if 0
-  /* #### If we re-use cells, then clicking on a checkbox RadioButton
-          (in non-USE_PICKER_VIEW mode) makes all the cells disappear.
-          This doesn't happen if we don't re-use any cells. Oh well.
-   */
-  NSString *id = [NSString stringWithFormat: @"%d:%d",
-                           [ip indexAtPosition:0],
-                           [ip indexAtPosition:1]];
-  UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier: id];
-
-  if (cell) return cell;
-#else
-  NSString *id = nil;
-  UITableViewCell *cell;
-#endif
-
-  cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
-                                   reuseIdentifier: id]
-           autorelease];
-  cell.selectionStyle = UITableViewCellSelectionStyleNone;
+  CGFloat ww = [tv frame].size.width;
+  CGFloat hh = [self tableView:tv heightForRowAtIndexPath:ip];
 
-  CGRect p = [cell frame];
-  CGRect r;
+  float os_version = [[[UIDevice currentDevice] systemVersion] floatValue];
 
-  p.size.height = [self tableView:tv heightForRowAtIndexPath:ip];
-  [cell setFrame:p];
+  // Width of the column of labels on the left.
+  CGFloat left_width = ww * 0.4;
+  CGFloat right_edge = ww - LEFT_MARGIN;
 
-  // Allocate more space to the controls on iPad screens,
-  // and on landscape-mode iPhones.
-  CGFloat ww = [tv frame].size.width;
-  CGFloat left_edge = (ww > 700
-                       ? p.size.width * 0.9
-                       : ww > 320
-                       ? p.size.width * 0.5
-                       : p.size.width * 0.3);
-  CGFloat right_edge = p.origin.x + p.size.width - LEFT_MARGIN;
+  if (os_version < 7)  // margins were wider on iOS 6.1
+    right_edge -= 10;
 
+  CGFloat max = FONT_SIZE * 12;
+  if (left_width > max) left_width = max;
 
   NSView *ctl = [[controls objectAtIndex:[ip indexAtPosition:0]]
-                  objectAtIndex:[ip indexAtPosition:1]];
+                           objectAtIndex:[ip indexAtPosition:1]];
 
   if ([ctl isKindOfClass:[NSArray class]]) {
     // This cell has a set of objects in it.
@@ -3356,36 +3468,41 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
         NSAssert ([label isKindOfClass:[UILabel class]], @"unhandled type");
         ctl = [set objectAtIndex: 1];
 
-        r = [ctl frame];
-        if ([ctl isKindOfClass:[UISwitch class]]) {
-          // Flush right checkboxes.
-          ctl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
+        CGRect r = [ctl frame];
+
+        if ([ctl isKindOfClass:[UISwitch class]]) {    // Checkboxes.
           r.size.width = 80;  // Magic.
-          r.origin.x = right_edge - r.size.width;
+          r.origin.x = right_edge - r.size.width + 30;  // beats me
+
+          if (os_version < 7)  // checkboxes were wider on iOS 6.1
+            r.origin.x -= 25;
+
         } else {
-          // Expandable sliders.
-          ctl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
-          r.origin.x = left_edge;
+          r.origin.x = left_width;                     // Text fields, etc.
           r.size.width = right_edge - r.origin.x;
         }
-        r.origin.y = (p.size.height - r.size.height) / 2;
+
+        r.origin.y = (hh - r.size.height) / 2;   // Center vertically.
         [ctl setFrame:r];
 
-        // Make a box.
-        NSView *box = [[UIView alloc] initWithFrame:p];
+        // Make a box and put the label and checkbox/slider into it.
+        r.origin.x = 0;
+        r.origin.y = 0;
+        r.size.width  = ww;
+        r.size.height = hh;
+        NSView *box = [[UIView alloc] initWithFrame:r];
         [box addSubview: ctl];
 
-        // cell.textLabel.text = [(UILabel *) ctl text];
+        // Let the label make use of any space not taken up by the control.
         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;
+        r.size.height = hh;
         [label setFrame:r];
         [label setFont:[NSFont boldSystemFontOfSize: FONT_SIZE]];
-        label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
-        box.  autoresizingMask = UIViewAutoresizingFlexibleWidth;
         [box addSubview: label];
+        [box autorelease];
 
         ctl = box;
       }
@@ -3393,8 +3510,8 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
     case 3:
     case 4:
       {
-        // With 3 elements, the first and last must be labels.
-        // With 4 elements, the first, second and last must be labels.
+        // With 3 elements, 1 and 3 are labels.
+        // With 4 elements, 1, 2 and 4 are labels.
         int i = 0;
         UILabel *top  = ([set count] == 4
                          ? [set objectAtIndex: i++]
@@ -3409,108 +3526,105 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
 
         // 3 elements: control at top of cell.
         // 4 elements: center the control vertically.
-        r = [mid frame];
+        CGRect r = [mid frame];
+        r.size.height = 32;   // Unchangable height of the slider thumb.
+
+        // Center the slider between left_width and right_edge.
 # ifdef  LABEL_ABOVE_SLIDER
-        left_edge = LEFT_MARGIN;
+        r.origin.x = LEFT_MARGIN;
+# else
+        r.origin.x = left_width;
 # endif
-        r.origin.x = left_edge;
+        r.origin.y = (hh - r.size.height) / 2;
         r.size.width = right_edge - r.origin.x;
-        r.origin.y = ([set count] == 3
-                      ? 8
-                      : (p.size.height - r.size.height) / 2);
         [mid setFrame:r];
 
-        // Top label goes above, flush center/top.
         if (top) {
+# ifdef LABEL_ABOVE_SLIDER
+          // Top label goes above, flush center/top.
+          r.origin.x = (ww - r.size.width) / 2;
+          r.origin.y = 4;
+          // #### sizeWithFont deprecated as of iOS 7; use boundingRectWithSize.
           r.size = [[top text] sizeWithFont:[top font]
                                constrainedToSize:
-                                 CGSizeMake (p.size.width - LEFT_MARGIN*2,
-                                             100000)
+                                 CGSizeMake (ww - LEFT_MARGIN*2, 100000)
                                lineBreakMode:[top lineBreakMode]];
-          r.origin.x = (p.size.width - r.size.width) / 2;
-          r.origin.y = 4;
+# else  // !LABEL_ABOVE_SLIDER
+          // Label goes on the left.
+          r.origin.x = LEFT_MARGIN;
+          r.origin.y = 0;
+          r.size.width  = left_width - LEFT_MARGIN;
+          r.size.height = hh;
+# endif // !LABEL_ABOVE_SLIDER
           [top setFrame:r];
         }
 
         // Left label goes under control, flush left/bottom.
-        r.size = [[left text] sizeWithFont:[left font]
-                               constrainedToSize:
-                                 CGSizeMake(p.size.width - LEFT_MARGIN*2,
-                                            100000)
-                              lineBreakMode:[left lineBreakMode]];
-        r.origin.x = [mid frame].origin.x;
-        r.origin.y = p.size.height - r.size.height - 4;
-        [left setFrame:r];
+        left.frame = CGRectMake([mid frame].origin.x, hh - 4,
+                                ww - LEFT_MARGIN*2, 100000);
+        [left sizeToFit];
+        r = left.frame;
+        r.origin.y -= r.size.height;
+        left.frame = r;
 
         // Right label goes under control, flush right/bottom.
-        r = [right frame];
-        r.size = [[right text] sizeWithFont:[right font]
-                               constrainedToSize:
-                                 CGSizeMake(p.size.width - LEFT_MARGIN*2,
-                                            1000000)
-                               lineBreakMode:[right lineBreakMode]];
-        r.origin.x = ([mid frame].origin.x + [mid frame].size.width -
-                      r.size.width);
-        r.origin.y = [left frame].origin.y;
-        [right setFrame:r];
-
-        // Then make a box.
-        ctl = [[UIView alloc] initWithFrame:p];
-        if (top) {
-# ifdef LABEL_ABOVE_SLIDER
-          [ctl addSubview: top];
-          top.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin|
-                                  UIViewAutoresizingFlexibleRightMargin);
-# else
-          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];
-        [ctl addSubview: mid];
-        [ctl addSubview: right];
-
-        left. autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
-        mid.  autoresizingMask = UIViewAutoresizingFlexibleWidth;
-        right.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
-        ctl.  autoresizingMask = UIViewAutoresizingFlexibleWidth;
+        right.frame =
+          CGRectMake([mid frame].origin.x + [mid frame].size.width,
+                     [left frame].origin.y, ww - LEFT_MARGIN*2, 1000000);
+        [right sizeToFit];
+        r = right.frame;
+        r.origin.x -= r.size.width;
+        right.frame = r;
+
+        // Make a box and put the labels and slider into it.
+        r.origin.x = 0;
+        r.origin.y = 0;
+        r.size.width  = ww;
+        r.size.height = hh;
+        NSView *box = [[UIView alloc] initWithFrame:r];
+        if (top)
+          [box addSubview: top];
+        [box addSubview: left];
+        [box addSubview: right];
+        [box addSubview: mid];
+        [box autorelease];
+
+        ctl = box;
       }
       break;
     default:
       NSAssert (0, @"unhandled size");
     }
-  } else {
-    // A single view, not a pair.
-
-    r = [ctl frame];
+  } else {     // A single view, not a pair.
+    CGRect r = [ctl frame];
     r.origin.x = LEFT_MARGIN;
-    r.origin.y = LINE_SPACING;
+    r.origin.y = 0;
     r.size.width = right_edge - r.origin.x;
+    r.size.height = hh;
     [ctl setFrame:r];
-
-    ctl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
-
-# ifndef USE_PICKER_VIEW
-    if ([ctl isKindOfClass:[RadioButton class]])
-      [self updateRadioGroupCell:cell button:(RadioButton *)ctl];
-# 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];
-  }
+  NSString *id = @"Cell";
+  UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:id];
+  if (!cell)
+    cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
+                                     reuseIdentifier: id]
+             autorelease];
 
+  for (UIView *subview in [cell.contentView subviews])
+    [subview removeFromSuperview];
   [cell.contentView addSubview: ctl];
+  CGRect r = [ctl frame];
+  r.origin.x = 0;
+  r.origin.y = 0;
+  [cell setFrame:r];
+  cell.selectionStyle = UITableViewCellSelectionStyleNone;
+  [cell setAccessoryType:UITableViewCellAccessoryNone];
+
+# ifndef USE_PICKER_VIEW
+  if ([ctl isKindOfClass:[RadioButton class]])
+    [self updateRadioGroupCell:cell button:(RadioButton *)ctl];
+# endif // USE_PICKER_VIEW
 
   return cell;
 }
@@ -3559,6 +3673,13 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
     return nil;
   }
 
+# ifndef USE_IPHONE
+  TextModeTransformer *t = [[TextModeTransformer alloc] init];
+  [NSValueTransformer setValueTransformer:t
+                      forName:@"TextModeTransformer"];
+  [t release];
+# endif // USE_IPHONE
+
   [self traverseTree];
   xml_root = 0;