numbers back in tables
[pspp] / src / ui / gui / psppire-scanf.c
index 2573c2e31093d62b814bdbafff417d16faf5820b..88128a3090a717f959502fcb1623ced90d39f974 100644 (file)
@@ -12,7 +12,8 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #include <config.h>
 #include <gtk/gtk.h>
 #include "xalloc.h"
 
 
-
-
 static void psppire_scanf_class_init          (PsppireScanfClass *class);
 static void psppire_scanf_init                (PsppireScanf      *w);
 
-G_DEFINE_TYPE (PsppireScanf, psppire_scanf, GTK_TYPE_HBOX)
+G_DEFINE_TYPE (PsppireScanf, psppire_scanf, GTK_TYPE_BOX)
 
 /* Properties */
 enum
 {
   PROP_0,
   PROP_FORMAT,
-  PROP_NCONV
+  PROP_NCONV,
+  PROP_USE_UNDERLINE,
+  PROP_MNEMONIC_WIDGET
 };
 
 /* Create a GtkLabel and pack it into BOX.
@@ -47,18 +48,18 @@ enum
    After this function returns, *S points to the first unused character.
 */
 static void
-ship_label (GtkBox *box, const char **s,
+ship_label (PsppireScanf *box, const char **s,
            const char_directives *dirs, size_t dir_idx)
 {
   GtkWidget *label ;
   GString *str = g_string_new (*s);
 
-  if ( dirs)
+  if (dirs)
     {
       char_directive dir = dirs->dir[dir_idx];
       int n = 0;
 
-      while (dir_idx < dirs->count && dir.conversion == '%' )
+      while (dir_idx < dirs->count && dir.conversion == '%')
        {
          g_string_erase (str, dir.dir_start - *s, 1);
          dir = dirs->dir[++dir_idx];
@@ -67,7 +68,7 @@ ship_label (GtkBox *box, const char **s,
 
       g_string_truncate (str, dir.dir_start - *s - n);
 
-      if ( dir_idx >= dirs->count)
+      if (dir_idx >= dirs->count)
        *s = NULL;
       else
        *s = dir.dir_end;
@@ -77,7 +78,7 @@ ship_label (GtkBox *box, const char **s,
 
   g_string_free (str, TRUE);
 
-  gtk_box_pack_start (box, label, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
   gtk_widget_show (label);
 }
 
@@ -91,31 +92,31 @@ guts (PsppireScanf *scanf)
   /* Get the number of args into D */
   g_return_if_fail (0 == printf_parse (scanf->format, &scanf->d, &a));
 
-  if ( scanf->d.count > 0)
-    scanf->widgets = xcalloc (sizeof (*scanf->widgets), scanf->d.count);
+  if (scanf->d.count > 0)
+    scanf->widgets = xcalloc (scanf->d.count, sizeof (*scanf->widgets));
 
   /* A is not used, so get rid of it */
   if (a.arg != a.direct_alloc_arg)
     free (a.arg);
 
-  for (i = 0 ; i < scanf->d.count ; ++i )
+  for (i = 0 ; i < scanf->d.count ; ++i)
     {
       GtkWidget **w;
       char_directive dir = scanf->d.dir[i];
       int precision = 0;
       int width = 0;
 
-      if ( dir.precision_start && dir.precision_end)
-       precision = strtol (dir.precision_start + 1,
+      if (dir.precision_start && dir.precision_end)
+       precision = g_ascii_strtoll (dir.precision_start + 1,
                            (char **) &dir.precision_end, 10);
 
-      if ( dir.width_start && dir.width_end )
-       width = strtol (dir.width_start, (char **) &dir.width_end, 10);
+      if (dir.width_start && dir.width_end)
+       width = g_ascii_strtoll (dir.width_start, (char **) &dir.width_end, 10);
 
-      if ( dir.dir_start > s )
-       ship_label (GTK_BOX (scanf), &s, &scanf->d, i);
+      if (dir.dir_start > s)
+       ship_label (scanf, &s, &scanf->d, i);
 
-      if ( dir.conversion == '%')
+      if (dir.conversion == '%')
        {
          if (s) s++;
          continue;
@@ -141,12 +142,39 @@ guts (PsppireScanf *scanf)
       gtk_widget_show (*w);
     }
 
-  if ( s && *s )
-    ship_label (GTK_BOX (scanf), &s, NULL, 0);
+  if (s && *s)
+    ship_label (scanf, &s, NULL, 0);
 
 }
 
 
+static void
+set_mnemonic (PsppireScanf *scanf)
+{
+  if (scanf->use_underline || scanf->mnemonic_widget)
+    {
+      GList *l = gtk_container_get_children (GTK_CONTAINER (scanf));
+      while (l)
+       {
+         if (GTK_IS_LABEL (l->data))
+           {
+             const gchar *t = gtk_label_get_label (l->data);
+             if  (g_strstr_len (t, -1,  "_"))
+               {
+                 g_object_set (l->data,
+                               "use-underline", TRUE,
+                               "mnemonic-widget", scanf->mnemonic_widget,
+                               NULL);
+
+                 break;
+               }
+           }
+         l = l->next;
+       }
+      g_list_free (l);
+    }
+}
+
 static void
 psppire_scanf_set_property (GObject         *object,
                            guint            prop_id,
@@ -161,6 +189,14 @@ psppire_scanf_set_property (GObject         *object,
       scanf->format = g_value_get_string (value);
       guts (scanf);
       break;
+    case PROP_MNEMONIC_WIDGET:
+      scanf->mnemonic_widget = g_value_get_object (value);
+      set_mnemonic (scanf);
+      break;
+    case PROP_USE_UNDERLINE:
+      scanf->use_underline = g_value_get_boolean (value);
+      set_mnemonic (scanf);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -184,6 +220,12 @@ psppire_scanf_get_property (GObject         *object,
     case PROP_NCONV:
       g_value_set_int (value, scanf->d.count);
       break;
+    case PROP_USE_UNDERLINE:
+      g_value_set_boolean (value, scanf->use_underline);
+      break;
+    case PROP_MNEMONIC_WIDGET:
+      g_value_set_object (value, scanf->mnemonic_widget);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -196,7 +238,7 @@ static GObjectClass *parent_class = NULL;
 static void
 psppire_scanf_dispose (GObject *obj)
 {
-  PsppireScanf *w = (PsppireScanf *)obj;
+  PsppireScanf *w = PSPPIRE_SCANF (obj);
 
   if (w->dispose_has_run)
     return;
@@ -243,6 +285,22 @@ psppire_scanf_class_init (PsppireScanfClass *class)
                       G_PARAM_READABLE);
 
 
+  GParamSpec *use_underline_spec =
+    g_param_spec_boolean ("use-underline",
+                      "Use Underline",
+                      "If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key",
+                         FALSE,
+                         G_PARAM_READWRITE);
+
+
+  GParamSpec *mnemonic_widget_spec =
+    g_param_spec_object ("mnemonic-widget",
+                      "Mnemonic widget",
+                      "The widget which is to be activated when the Scanf's mnemonic key is pressed.  Has no effect if use-underline is false.",
+                        GTK_TYPE_WIDGET,
+                        G_PARAM_READWRITE);
+
+
   parent_class = g_type_class_peek_parent (class);
 
   object_class->dispose = psppire_scanf_dispose;
@@ -259,6 +317,13 @@ psppire_scanf_class_init (PsppireScanfClass *class)
                                    PROP_FORMAT,
                                    format_spec);
 
+  g_object_class_install_property (object_class,
+                                   PROP_USE_UNDERLINE,
+                                   use_underline_spec);
+
+  g_object_class_install_property (object_class,
+                                   PROP_MNEMONIC_WIDGET,
+                                   mnemonic_widget_spec);
 }
 
 
@@ -266,25 +331,28 @@ psppire_scanf_class_init (PsppireScanfClass *class)
 static void
 psppire_scanf_init (PsppireScanf *w)
 {
+  w->dispose_has_run = FALSE;
+
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (w), GTK_ORIENTATION_HORIZONTAL);
 }
 
-gchar
+static gchar
 psppire_get_conversion_char (PsppireScanf *w, gint n)
 {
-  g_return_val_if_fail ( n < w->d.count, '\0');
+  g_return_val_if_fail (n < w->d.count, '\0');
   return w->d.dir[n].conversion;
 }
 
 GtkWidget *
 psppire_scanf_get_child (PsppireScanf *w, gint n)
 {
-  g_return_val_if_fail ( n < w->d.count, NULL);
+  g_return_val_if_fail (n < w->d.count, NULL);
   return w->widgets[n];
 }
 
 
 /*
-   This widget is a GtkHBox populated with GtkLabel and GtkEntry widgets.
+   This widget is a horizontal GtkBox populated with GtkLabel and GtkEntry widgets.
    Each conversion in FMT will cause a GtkEntry (possibly a GtkSpinButton) to
    be created.  Any text between conversions produces a GtkLabel.
    There should be N arguments following FMT should be of type GtkEntry **,
@@ -305,11 +373,11 @@ psppire_scanf_new (const gchar *fmt, ...)
 
   va_start (ap, fmt);
 
-  for (i = 0 ; i < n ; ++i )
+  for (i = 0 ; i < n ; ++i)
     {
       GtkWidget **field;
 
-      if ( psppire_get_conversion_char (PSPPIRE_SCANF (w), i) == '%')
+      if (psppire_get_conversion_char (PSPPIRE_SCANF (w), i) == '%')
        continue;
 
       field = va_arg (ap, GtkWidget **);