/* 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 . */ #include #include #include "psppire-scanf.h" #include #include #include #include #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_BOX) /* Properties */ enum { PROP_0, PROP_FORMAT, PROP_NCONV, PROP_USE_UNDERLINE, PROP_MNEMONIC_WIDGET }; /* 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 (PsppireScanf *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 (GTK_BOX (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 (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) { GtkWidget **w; char_directive dir = scanf->d.dir[i]; int precision = 0; int width = 0; 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 = g_ascii_strtoll (dir.width_start, (char **) &dir.width_end, 10); if (dir.dir_start> s) ship_label (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 (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, 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; 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; }; } 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; 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; }; } static GObjectClass *parent_class = NULL; static void psppire_scanf_dispose (GObject *obj) { PsppireScanf *w = PSPPIRE_SCANF (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); 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; 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); 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); } static void psppire_scanf_init (PsppireScanf *w) { w->dispose_has_run = FALSE; gtk_orientable_set_orientation (GTK_ORIENTABLE (w), GTK_ORIENTATION_HORIZONTAL); } static 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 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 **, 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; }

AltStyle によって変換されたページ (->オリジナル) /