http://www.jwz.org/xscreensaver/xscreensaver-5.07.tar.gz
[xscreensaver] / OSX / XScreenSaverConfigSheet.m
index 9601eac42c1706c12aa63e1a9652d192c58b3ab6..06804c70429b915d84eb34dcbe30ad90fde0889c 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2006-2008 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
@@ -606,12 +606,21 @@ make_number_selector (NSUserDefaultsController *prefs,
                label);
   }
     
+  // If either the min or max field contains a decimal point, then this
+  // option may have a floating point value; otherwise, it is constrained
+  // to be an integer.
+  //
+  NSCharacterSet *dot =
+    [NSCharacterSet characterSetWithCharactersInString:@"."];
+  BOOL float_p = ([low rangeOfCharacterFromSet:dot].location != NSNotFound ||
+                  [high rangeOfCharacterFromSet:dot].location != NSNotFound);
+
   if ([type isEqualToString:@"slider"]) {
 
     NSRect rect;
     rect.origin.x = rect.origin.y = 0;    
     rect.size.width = 150;
-    rect.size.height = 20;
+    rect.size.height = 23;  // apparent min height for slider with ticks...
     NSSlider *slider;
     if (cvt)
       slider = [[InvertedSlider alloc] initWithFrame:rect];
@@ -621,6 +630,31 @@ make_number_selector (NSUserDefaultsController *prefs,
     [slider setMaxValue:[high doubleValue]];
     [slider setMinValue:[low  doubleValue]];
     
+    int range = [slider maxValue] - [slider minValue] + 1;
+    int range2 = range;
+    int max_ticks = 21;
+    while (range2 > max_ticks)
+      range2 /= 10;
+
+    // If we have elided ticks, leave it at the max number of ticks.
+    if (range != range2 && range2 < max_ticks)
+      range2 = max_ticks;
+
+    // If it's a float, always display the max number of ticks.
+    if (float_p && range2 < max_ticks)
+      range2 = max_ticks;
+
+    [slider setNumberOfTickMarks:range2];
+
+    [slider setAllowsTickMarkValuesOnly:
+              (range == range2 &&  // we are showing the actual number of ticks
+               !float_p)];         // and we want integer results
+
+    // #### Note: when the slider's range is large enough that we aren't
+    //      showing all possible ticks, the slider's value is not constrained
+    //      to be an integer, even though it should be...
+    //      Maybe we need to use a value converter or something?
+
     if (label) {
       NSTextField *lab = make_label (label);
       place_child (parent, lab, NO);
@@ -711,8 +745,8 @@ make_number_selector (NSUserDefaultsController *prefs,
     [step sizeToFit];
     place_child (parent, step, YES);
     rect = [step frame];
-    rect.size.height = [txt frame].size.height;
     rect.origin.x -= COLUMN_SPACING;  // this one goes close
+    rect.origin.y += ([txt frame].size.height - rect.size.height) / 2;
     [step setFrame:rect];
     
     [step setMinValue:[low  doubleValue]];
@@ -728,6 +762,18 @@ make_number_selector (NSUserDefaultsController *prefs,
     else
       [step setIncrement:1.0];
 
+    NSNumberFormatter *fmt = [[[NSNumberFormatter alloc] init] autorelease];
+    [fmt setFormatterBehavior:NSNumberFormatterBehavior10_4];
+    [fmt setNumberStyle:NSNumberFormatterDecimalStyle];
+    [fmt setMinimum:[NSNumber numberWithDouble:[low  doubleValue]]];
+    [fmt setMaximum:[NSNumber numberWithDouble:[high doubleValue]]];
+    [fmt setMinimumFractionDigits: (float_p ? 1 : 0)];
+    [fmt setMaximumFractionDigits: (float_p ? 2 : 0)];
+
+    [fmt setGeneratesDecimalNumbers:float_p];
+    [[txt cell] setFormatter:fmt];
+
+
     bind_switch_to_preferences (prefs, step, arg, opts);
     bind_switch_to_preferences (prefs, txt,  arg, opts);
     
@@ -997,6 +1043,45 @@ unwrap (NSString *text)
 }
 
 
+static char *
+anchorize (const char *url)
+{
+  const char *wiki = "http://en.wikipedia.org/wiki/";
+  if (!strncmp (wiki, url, strlen(wiki))) {
+    char *anchor = (char *) malloc (strlen(url) * 3 + 10);
+    strcpy (anchor, "Wikipedia: \"");
+    const char *in = url + strlen(wiki);
+    char *out = anchor + strlen(anchor);
+    while (*in) {
+      if (*in == '_') {
+        *out++ = ' ';
+      } else if (*in == '#') {
+        *out++ = ':';
+        *out++ = ' ';
+      } else if (*in == '%') {
+        char hex[3];
+        hex[0] = in[1];
+        hex[1] = in[2];
+        hex[2] = 0;
+        int n = 0;
+        sscanf (hex, "%x", &n);
+        *out++ = (char) n;
+        in += 2;
+      } else {
+        *out++ = *in;
+      }
+      in++;
+    }
+    *out++ = '"';
+    *out = 0;
+    return anchor;
+
+  } else {
+    return strdup (url);
+  }
+}
+
+
 /* Converts any http: URLs in the given text field to clickable links.
  */
 static void
@@ -1040,15 +1125,24 @@ hreffify (NSText *nstext)
     NSString *nsurl = [text substringWithRange:r2];
     const char *url = [nsurl UTF8String];
 
-    // Construct the RTF corresponding to <A HREF="url">url</A>
+    // If this is a Wikipedia URL, make the linked text be prettier.
+    //
+    char *anchor = anchorize(url);
+
+    // Construct the RTF corresponding to <A HREF="url">anchor</A>
     //
     const char *fmt = "{\\field{\\*\\fldinst{HYPERLINK \"%s\"}}%s}";
-    char *rtf = malloc (strlen (fmt) + (strlen (url) * 2) + 10);
-    sprintf (rtf, fmt, url, url);
+    char *rtf = malloc (strlen (fmt) + strlen(url) + strlen(anchor) + 10);
+    sprintf (rtf, fmt, url, anchor);
+    free (anchor);
     NSData *rtfdata = [NSData dataWithBytesNoCopy:rtf length:strlen(rtf)];
 
     // Insert the RTF into the NSText.
     [nstext replaceCharactersInRange:r2 withRTF:rtfdata];
+
+    int L2 = [text length];  // might have changed
+    start.location -= (L - L2);
+    L = L2;
   }
 }
 
@@ -1147,7 +1241,7 @@ make_text_controls (NSUserDefaultsController *prefs,
 {
   /*
     Display Text:
-     (x)  Computer Name and Time
+     (x)  Computer name and time
      ( )  Text       [__________________________]
      ( )  Text file  [_________________] [Choose]
      ( )  URL        [__________________________]
@@ -1183,7 +1277,7 @@ make_text_controls (NSUserDefaultsController *prefs,
   [matrix setAllowsEmptySelection:NO];
 
   NSArrayController *cnames  = [[NSArrayController alloc] initWithContent:nil];
-  [cnames addObject:@"Computer Name and Time"];
+  [cnames addObject:@"Computer name and time"];
   [cnames addObject:@"Text"];
   [cnames addObject:@"File"];
   [cnames addObject:@"URL"];
@@ -1301,13 +1395,13 @@ make_image_controls (NSUserDefaultsController *prefs,
                      NSView *parent, NSXMLNode *node)
 {
   /*
-    [x]  Grab Desktop Images
-    [ ]  Choose Random Image:
+    [x]  Grab desktop images
+    [ ]  Choose random image:
          [__________________________]  [Choose]
 
-   <boolean id="grabDesktopImages" _label="Grab Desktop Images"
+   <boolean id="grabDesktopImages" _label="Grab desktop images"
        arg-unset="-no-grab-desktop"/>
-   <boolean id="chooseRandomImages" _label="Grab Desktop Images"
+   <boolean id="chooseRandomImages" _label="Grab desktop images"
        arg-unset="-choose-random-images"/>
    <file id="imageDirectory" _label="" arg-set="-image-directory %"/>
    */
@@ -1318,7 +1412,7 @@ make_image_controls (NSUserDefaultsController *prefs,
   [node2 setAttributesAsDictionary:
           [NSDictionary dictionaryWithObjectsAndKeys:
                         @"grabDesktopImages",   @"id",
-                        @"Grab Desktop Images", @"_label",
+                        @"Grab desktop images", @"_label",
                         @"-no-grab-desktop",    @"arg-unset",
                         nil]];
   make_checkbox (prefs, opts, parent, node2);
@@ -1328,7 +1422,7 @@ make_image_controls (NSUserDefaultsController *prefs,
   [node2 setAttributesAsDictionary:
           [NSDictionary dictionaryWithObjectsAndKeys:
                         @"chooseRandomImages",    @"id",
-                        @"Choose Random Images",  @"_label",
+                        @"Choose random images",  @"_label",
                         @"-choose-random-images", @"arg-set",
                         nil]];
   make_checkbox (prefs, opts, parent, node2);
@@ -1338,7 +1432,7 @@ make_image_controls (NSUserDefaultsController *prefs,
   [node2 setAttributesAsDictionary:
           [NSDictionary dictionaryWithObjectsAndKeys:
                         @"imageDirectory",     @"id",
-                        @"Images Directory:",  @"_label",
+                        @"Images directory:",  @"_label",
                         @"-image-directory %", @"arg",
                         nil]];
   make_file_selector (prefs, opts, parent, node2, YES, NO);
@@ -1654,9 +1748,16 @@ wrap_with_buttons (NSWindow *window, NSView *panel)
   [pbox setTitlePosition:NSNoTitle];
   [pbox setBorderType:NSBezelBorder];
 
+  // Enforce a max height on the dialog, so that it's obvious to me
+  // (on a big screen) when the dialog will fall off the bottom of
+  // a small screen (e.g., 1024x768 laptop with a huge bottom dock).
   {
     NSRect f = [panel frame];
-    int screen_height = 800 - 64;
+    int screen_height = (768    // shortest "modern" Mac display
+                         - 22   // menu bar
+                         - 56   // System Preferences toolbar
+                         - 140  // default magnified bottom dock icon
+                         );
     if (f.size.height > screen_height) {
       NSLog(@"%@ height was %.0f; clipping to %d", 
           [panel class], f.size.height, screen_height);