src/ui/gui/psppire-buttonbox.c \
src/ui/gui/psppire-hbuttonbox.c \
src/ui/gui/psppire-vbuttonbox.c \
+ src/ui/gui/psppire-scanf.c \
+ src/ui/gui/psppire-scanf.h \
src/ui/gui/psppire-acr.c \
src/ui/gui/autorecode-dialog.c \
src/ui/gui/autorecode-dialog.h \
#include "psppire-data-window.h"
#include "psppire-var-view.h"
-#include "widget-io.h"
+#include "psppire-scanf.h"
#include "executor.h"
#include "helper.h"
{
GtkWidget *hbox = get_widget_assert (fd.xml, "hbox6");
- GtkWidget *eigenvalue_extraction = widget_scanf (_("Eigenvalues over %4.2f times the mean eigenvalue"), &fd.mineigen);
+ GtkWidget *eigenvalue_extraction = psppire_scanf_new (_("Eigenvalues over %4.2f times the mean eigenvalue"), &fd.mineigen);
fd.nfactors_toggle = get_widget_assert (fd.xml, "nfactors-radiobutton");
fd.mineigen_toggle = get_widget_assert (fd.xml, "mineigen-radiobutton");
--- /dev/null
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ 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 <gtk/gtk.h>
+#include "psppire-scanf.h"
+
+#include <gl/printf-parse.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.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)
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_FORMAT,
+ PROP_NCONV
+};
+
+/* Create a GtkLabel and pack it into BOX.
+ The label is created using part of the string at S, and the directives
+ at DIRS[DIR_IDX] and subsequent.
+
+ After this function returns, *S points to the first unused character.
+*/
+static void
+ship_label (GtkBox *box, const char **s,
+ const char_directives *dirs, size_t dir_idx)
+{
+ GtkWidget *label ;
+ GString *str = g_string_new (*s);
+
+ if ( dirs)
+ {
+ char_directive dir = dirs->dir[dir_idx];
+ int n = 0;
+
+ while (dir_idx < dirs->count && dir.conversion == '%' )
+ {
+ g_string_erase (str, dir.dir_start - *s, 1);
+ dir = dirs->dir[++dir_idx];
+ n++;
+ }
+
+ g_string_truncate (str, dir.dir_start - *s - n);
+
+ if ( dir_idx >= dirs->count)
+ *s = NULL;
+ else
+ *s = dir.dir_end;
+ }
+
+ label = gtk_label_new (str->str);
+
+ g_string_free (str, TRUE);
+
+ gtk_box_pack_start (box, label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+}
+
+static void
+guts (PsppireScanf *scanf)
+{
+ gint i;
+ arguments a;
+ const char *s = scanf->format;
+
+ /* 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);
+
+ /* 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 )
+ {
+ 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,
+ (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 (scanf), &s, &scanf->d, i);
+
+ if ( dir.conversion == '%')
+ {
+ if (s) s++;
+ continue;
+ }
+
+ w = &scanf->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 (scanf), *w, FALSE, FALSE, 0);
+ gtk_widget_show (*w);
+ }
+
+ if ( s && *s )
+ ship_label (GTK_BOX (scanf), &s, NULL, 0);
+
+}
+
+
+static void
+psppire_scanf_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PsppireScanf *scanf = PSPPIRE_SCANF (object);
+
+ switch (prop_id)
+ {
+ case PROP_FORMAT:
+ scanf->format = g_value_get_string (value);
+ guts (scanf);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ };
+}
+
+
+static void
+psppire_scanf_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PsppireScanf *scanf = PSPPIRE_SCANF (object);
+
+ switch (prop_id)
+ {
+ case PROP_FORMAT:
+ g_value_set_string (value, scanf->format);
+ break;
+ case PROP_NCONV:
+ g_value_set_int (value, scanf->d.count);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ };
+}
+
+
+static GObjectClass *parent_class = NULL;
+
+static void
+psppire_scanf_dispose (GObject *obj)
+{
+ PsppireScanf *w = (PsppireScanf *)obj;
+
+ if (w->dispose_has_run)
+ return;
+
+ /* Make sure dispose does not run twice. */
+ w->dispose_has_run = TRUE;
+
+
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+psppire_scanf_finalize (GObject *obj)
+{
+ PsppireScanf *w = PSPPIRE_SCANF (obj);
+
+ free (w->widgets);
+
+ if (w->d.dir != w->d.direct_alloc_dir)
+ free (w->d.dir);
+
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+psppire_scanf_class_init (PsppireScanfClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ GParamSpec *format_spec =
+ g_param_spec_string ("format",
+ "Format",
+ "A Scanf style format string",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+
+ GParamSpec *nconv_spec =
+ g_param_spec_int ("n-conv",
+ "Conversions",
+ "The number of conversions in the format string",
+ 0, G_MAXINT, 0,
+ G_PARAM_READABLE);
+
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->dispose = psppire_scanf_dispose;
+ object_class->finalize = psppire_scanf_finalize;
+
+ object_class->set_property = psppire_scanf_set_property;
+ object_class->get_property = psppire_scanf_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_NCONV,
+ nconv_spec);
+
+ g_object_class_install_property (object_class,
+ PROP_FORMAT,
+ format_spec);
+
+}
+
+
+
+static void
+psppire_scanf_init (PsppireScanf *w)
+{
+}
+
+gchar
+psppire_get_conversion_char (PsppireScanf *w, gint n)
+{
+ 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);
+ return w->widgets[n];
+}
+
+
+/*
+ This widget is a GtkHBox 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 **,
+ 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 *
+psppire_scanf_new (const gchar *fmt, ...)
+{
+ gint n, i;
+ va_list ap;
+
+ GtkWidget *w = GTK_WIDGET (g_object_new (psppire_scanf_get_type (),
+ "format", fmt, NULL));
+
+ g_object_get (w, "n-conv", &n, NULL);
+
+ va_start (ap, fmt);
+
+ for (i = 0 ; i < n ; ++i )
+ {
+ GtkWidget **field;
+
+ if ( psppire_get_conversion_char (PSPPIRE_SCANF (w), i) == '%')
+ continue;
+
+ field = va_arg (ap, GtkWidget **);
+
+ *field = psppire_scanf_get_child (PSPPIRE_SCANF (w), i);
+ }
+ va_end (ap);
+
+ return w;
+}
--- /dev/null
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ 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/>. */
+
+
+#ifndef __PSPPIRE_SCANF_H__
+#define __PSPPIRE_SCANF_H__
+
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <gl/printf-parse.h>
+
+
+G_BEGIN_DECLS
+
+#define PSPPIRE_SCANF_TYPE (psppire_scanf_get_type ())
+#define PSPPIRE_SCANF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_SCANF_TYPE, PsppireScanf))
+#define PSPPIRE_SCANF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PSPPIRE_SCANF_TYPE, PsppireScanfClass))
+#define PSPPIRE_IS_SCANF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_SCANF_TYPE))
+#define PSPPIRE_IS_SCANF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_SCANF_TYPE))
+
+
+typedef struct _PsppireScanf PsppireScanf;
+typedef struct _PsppireScanfClass PsppireScanfClass;
+
+/* All members are private. */
+struct _PsppireScanf
+{
+ GtkHBox parent;
+ const gchar *format;
+
+ GtkWidget **widgets;
+ char_directives d;
+
+ gboolean dispose_has_run;
+};
+
+
+struct _PsppireScanfClass
+{
+ GtkHBoxClass parent_class;
+};
+
+
+GType psppire_scanf_get_type (void);
+GtkWidget* psppire_scanf_new (const gchar *fmt, ...);
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_SCANF_H__ */
#include "dict-display.h"
#include "dialog-common.h"
#include "widget-io.h"
+#include "psppire-scanf.h"
#include "helper.h"
#include <xalloc.h>
if ( ! scd->hbox1 )
{
- scd->hbox1 = widget_scanf (gettext (label1), &scd->spinbutton);
+ scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
gtk_widget_show (scd->hbox1);
if ( ! scd->hbox2 )
{
scd->hbox2 =
- widget_scanf (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
+ psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
1, case_count);
#include "t-test-options.h"
#include "widget-io.h"
+#include "psppire-scanf.h"
#include <gettext.h>
#define _(msgid) gettext (msgid)
tto->xml = builder_new ("t-test.ui");
tto->confidence =
- widget_scanf (_("Confidence Interval: %2d %%"),
- &tto->conf_percent);
+ psppire_scanf_new (_("Confidence Interval: %2d %%"), &tto->conf_percent);
tto->dialog = get_widget_assert (tto->xml, "options-dialog");
#include "ui/gui/psppire-dialog.h"
#include "ui/gui/psppire-var-sheet.h"
#include "ui/gui/psppire-var-store.h"
-#include "ui/gui/widget-io.h"
+#include "ui/gui/psppire-scanf.h"
#include "ui/syntax-gen.h"
#include "gl/error.h"
p->n_cases_spin = gtk_spin_button_new_with_range (0, INT_MAX, 100);
- hbox_n_cases = widget_scanf (_("Only the first %4d cases"), &p->n_cases_spin);
+ hbox_n_cases = psppire_scanf_new (_("Only the first %4d cases"), &p->n_cases_spin);
table = get_widget_assert (builder, "button-table");
p->percent_spin = gtk_spin_button_new_with_range (0, 100, 10);
- hbox_percent = widget_scanf (_("Only the first %3d %% of file (approximately)"), &p->percent_spin);
+ hbox_percent = psppire_scanf_new (_("Only the first %3d %% of file (approximately)"), &p->percent_spin);
gtk_table_attach_defaults (GTK_TABLE (table), hbox_percent,
1, 2,
#include "xalloc.h"
-/* Create a GtkLabel and pack it into BOX.
- The label is created using part of the string at S, and the directives
- at DIRS[DIR_IDX] and subsequent.
-
- After this function returns, *S points to the first unused character.
-*/
-static void
-ship_label (GtkBox *box, const char **s,
- const char_directives *dirs, size_t dir_idx)
-{
- GtkWidget *label ;
- GString *str = g_string_new (*s);
-
- if ( dirs)
- {
- char_directive dir = dirs->dir[dir_idx];
- int n = 0;
-
- while (dir_idx < dirs->count && dir.conversion == '%' )
- {
- g_string_erase (str, dir.dir_start - *s, 1);
- dir = dirs->dir[++dir_idx];
- n++;
- }
-
- g_string_truncate (str, dir.dir_start - *s - n);
-
- if ( dir_idx >= dirs->count)
- *s = NULL;
- else
- *s = dir.dir_end;
- }
-
- label = gtk_label_new (str->str);
-
- g_string_free (str, TRUE);
-
- 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
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;
-
- if (a.arg != a.direct_alloc_arg)
- 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, &d, i);
-
- if ( dir.conversion == '%')
- {
- if (s) 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 && *s )
- ship_label (GTK_BOX (hbox), &s, NULL, 0);
-
-
-
- g_free (widgets);
-
- if (d.dir != d.direct_alloc_dir)
- free (d.dir);
-
- return hbox;
-}
The returned string should be freed when no longer required.
*/
gchar * widget_printf (const gchar *fmt, ...);
-
-/*
- 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, ...);