Implemented the Select Cases Dialog
[pspp-builds.git] / src / ui / gui / widget-io.c
diff --git a/src/ui/gui/widget-io.c b/src/ui/gui/widget-io.c
new file mode 100644 (file)
index 0000000..81ffd73
--- /dev/null
@@ -0,0 +1,214 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2007  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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/>. */
+
+#include <config.h>
+
+#include "widget-io.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <gl/printf-parse.h>
+#include <stdarg.h>
+#include <gtk/gtk.h>
+
+#include <gl/gettext.h>
+
+
+
+static void
+ship_label (GtkBox *box, const char **s, const char_directive *dir)
+{
+  GtkWidget *label ;
+  gchar *text = g_strdup (*s);
+
+  if ( dir )
+    {
+      text [ dir->dir_start - *s ] = '\0';
+      *s = dir->dir_end;
+    }
+
+  label = gtk_label_new (text);
+  g_free (text);
+
+  gtk_box_pack_start (box, label, FALSE, FALSE, 0);
+  gtk_widget_show (label);
+}
+
+/* Returns a string generated from FMT and a list of GtkEntry widgets.
+   Each conversion in FMT will be replaced with the text from the
+   corresponding GtkEntry.  The normal printf semantics will be ignored.
+   Note that the GtkEntry widgets may be GtkSpinbuttons or any other widget
+   derived from GtkEntry.
+   The returned string should be freed when no longer required.
+ */
+gchar *
+widget_printf (const gchar *fmt, ...)
+{
+  gint i;
+  char_directives d;
+  arguments a;
+  GString *output;
+  GtkWidget **widgets;
+  gchar *text;
+  va_list ap;
+  const char *s = fmt;
+
+  if ( 0 !=  printf_parse (fmt, &d, &a) )
+    return NULL;
+
+  widgets = calloc (sizeof (*widgets), d.count);
+  va_start (ap, fmt);
+  for (i = 0 ; i < d.count ; ++i )
+    {
+      if ( d.dir[i].conversion != '%')
+       widgets[i] = va_arg (ap, GtkWidget *);
+    }
+  va_end (ap);
+
+  g_free (a.arg);
+
+  output = g_string_sized_new (strlen (fmt));
+
+  for (i = 0 ; i < d.count ; ++i )
+    {
+      char_directive dir = d.dir[i];
+      GtkWidget *w ;
+      const gchar *entry_text;
+
+      if ( dir.conversion == '%')
+       {
+         s++;
+         continue;
+       }
+
+      w = widgets [dir.arg_index];
+      entry_text = gtk_entry_get_text (GTK_ENTRY (w));
+
+      if ( dir.dir_start > s )
+       g_string_append_len (output, s, dir.dir_start - s);
+
+      s = dir.dir_end;
+
+      g_string_append (output, entry_text);
+    }
+
+  free (widgets);
+  free (d.dir);
+
+  if (*s)
+    g_string_append_len (output, s, -1);
+
+  text = output->str;
+  g_string_free (output, FALSE);
+  return text;
+}
+
+/*
+   Returns a GtkHBox populated with an 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 **,
+   where N is the number of conversions.
+   These arguments will be filled with a pointer to the corresponding widgets.
+   Their properties may be changed, but they should not be unrefed.
+ */
+GtkWidget *
+widget_scanf (const gchar *fmt, ...)
+{
+  char_directives d;
+  arguments a;
+  int i;
+  va_list ap;
+  GtkWidget ***widgets = NULL;
+  GtkWidget *hbox = NULL;
+  GtkWidget **w;
+  const char *s = fmt;
+
+  if ( 0 !=  printf_parse (fmt, &d, &a) )
+    return NULL;
+
+  g_free (a.arg);
+
+  va_start (ap, fmt);
+
+  if ( d.count > 0 )
+    {
+      hbox = gtk_hbox_new (FALSE, 0);
+      widgets = calloc (sizeof (*widgets), d.count);
+    }
+
+  for (i = 0 ; i < d.count ; ++i )
+    {
+      if ( d.dir[i].conversion != '%')
+       widgets[i] = va_arg (ap, GtkWidget **);
+    }
+  va_end (ap);
+
+
+  for (i = 0 ; i < d.count ; ++i )
+    {
+      char_directive dir = d.dir[i];
+      int precision = 0;
+      int width = 0;
+
+
+      if ( dir.precision_start && dir.precision_end)
+       precision = strtol (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.dir_start > s )
+       ship_label (GTK_BOX (hbox), &s, &dir);
+
+      if ( dir.conversion == '%')
+       {
+         s++;
+         continue;
+       }
+
+      w = widgets [dir.arg_index];
+      switch (dir.conversion)
+       {
+       case 'd':
+       case 'i':
+       case 'f':
+         {
+           *w = gtk_spin_button_new_with_range (0, 100.0, 1.0);
+           g_object_set (*w, "digits", precision, NULL);
+         }
+         break;
+       case 's':
+         *w = gtk_entry_new ();
+         break;
+       };
+
+      g_object_set (*w, "width-chars", width, NULL);
+      gtk_box_pack_start (GTK_BOX (hbox), *w, FALSE, FALSE, 0);
+      gtk_widget_show (*w);
+    }
+
+  if ( *s )
+    ship_label (GTK_BOX (hbox), &s, NULL);
+
+
+  g_free (widgets);
+
+  free (d.dir);
+
+  return hbox;
+}