From 1abba60b3018ce7eb3d85930ad591e4d6ad39813 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Wed, 10 Oct 2007 10:22:28 +0000 Subject: [PATCH] Added the Independent Samples T Test dialog --- src/ui/gui/automake.mk | 9 +- src/ui/gui/data-editor.c | 21 + src/ui/gui/data-editor.glade | 2 +- src/ui/gui/data-editor.h | 3 + src/ui/gui/psppire-selector.c | 3 + .../gui/t-test-independent-samples-dialog.c | 335 +++++++++++++++ .../gui/t-test-independent-samples-dialog.h | 6 + src/ui/gui/t-test.glade | 403 ++++++++++++++++++ src/ui/gui/widget-io.c | 45 +- 9 files changed, 812 insertions(+), 15 deletions(-) create mode 100644 src/ui/gui/t-test-independent-samples-dialog.c create mode 100644 src/ui/gui/t-test-independent-samples-dialog.h create mode 100644 src/ui/gui/t-test.glade diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index b580e289..02a53524 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -47,11 +47,12 @@ src_ui_gui_psppire_LDADD = \ src_ui_gui_psppiredir = $(pkgdatadir) dist_src_ui_gui_psppire_DATA = \ - $(top_srcdir)/src/ui/gui/psppire.glade \ - $(top_srcdir)/src/ui/gui/syntax-editor.glade \ $(top_srcdir)/src/ui/gui/data-editor.glade \ - $(top_srcdir)/src/ui/gui/output-viewer.glade \ $(top_srcdir)/src/ui/gui/descriptives-dialog.glade \ + $(top_srcdir)/src/ui/gui/output-viewer.glade \ + $(top_srcdir)/src/ui/gui/psppire.glade \ + $(top_srcdir)/src/ui/gui/syntax-editor.glade \ + $(top_srcdir)/src/ui/gui/t-test.glade \ $(top_srcdir)/src/ui/gui/psppicon.png \ $(top_srcdir)/src/ui/gui/pspplogo.png \ $(top_srcdir)/src/ui/gui/icons/value-labels.png \ @@ -138,6 +139,8 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/syntax-editor-source.h \ src/ui/gui/transpose-dialog.c \ src/ui/gui/transpose-dialog.h \ + src/ui/gui/t-test-independent-samples-dialog.c \ + src/ui/gui/t-test-independent-samples-dialog.h \ src/ui/gui/val-labs-dialog.c \ src/ui/gui/val-labs-dialog.h \ src/ui/gui/var-display.c \ diff --git a/src/ui/gui/data-editor.c b/src/ui/gui/data-editor.c index 0a968663..bfb05b5f 100644 --- a/src/ui/gui/data-editor.c +++ b/src/ui/gui/data-editor.c @@ -43,6 +43,9 @@ #include "dict-display.h" #include "clipboard.h" +#include "t-test-independent-samples-dialog.h" + + #define _(msgid) gettext (msgid) #define N_(msgid) msgid @@ -586,6 +589,18 @@ new_data_editor (void) g_signal_connect (de->invoke_compute_dialog, "activate", G_CALLBACK (compute_dialog), de); + + + de->invoke_t_test_independent_samples_dialog = + gtk_action_new ("t-test-independent-samples", + _("_Independent Samples T Test"), + _("Calculate T Test for samples from independent groups"), + NULL); + + g_signal_connect (de->invoke_t_test_independent_samples_dialog, "activate", + G_CALLBACK (t_test_independent_samples_dialog), de); + + de->invoke_comments_dialog = gtk_action_new ("commments-dialog", _("Data File Comments"), @@ -731,6 +746,12 @@ new_data_editor (void) get_widget_assert (de->xml, "transform_compute") ); + gtk_action_connect_proxy (de->invoke_t_test_independent_samples_dialog, + get_widget_assert (de->xml, + "indep-t-test") + ); + + gtk_action_connect_proxy (de->invoke_comments_dialog, get_widget_assert (de->xml, "utilities_comments") ); diff --git a/src/ui/gui/data-editor.glade b/src/ui/gui/data-editor.glade index 96e31ade..bc6e65da 100644 --- a/src/ui/gui/data-editor.glade +++ b/src/ui/gui/data-editor.glade @@ -494,7 +494,7 @@ - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK One Way _ANOVA diff --git a/src/ui/gui/data-editor.h b/src/ui/gui/data-editor.h index 6ebc2ec6..a97930af 100644 --- a/src/ui/gui/data-editor.h +++ b/src/ui/gui/data-editor.h @@ -44,6 +44,9 @@ struct data_editor GtkAction *invoke_find_dialog; GtkAction *invoke_descriptives_dialog; + GtkAction *invoke_t_test_independent_samples_dialog; + + /* Actions which do things */ GtkAction *insert_variable; GtkAction *insert_case; diff --git a/src/ui/gui/psppire-selector.c b/src/ui/gui/psppire-selector.c index dcaac0ce..5ec051bb 100644 --- a/src/ui/gui/psppire-selector.c +++ b/src/ui/gui/psppire-selector.c @@ -727,6 +727,9 @@ set_entry_dest (PsppireSelector *selector, g_signal_connect_swapped (dest, "activate", G_CALLBACK (refilter), selector); + g_signal_connect_swapped (dest, "changed", G_CALLBACK (refilter), + selector); + g_signal_connect (dest, "focus-in-event", G_CALLBACK (on_entry_dest_select), selector); diff --git a/src/ui/gui/t-test-independent-samples-dialog.c b/src/ui/gui/t-test-independent-samples-dialog.c new file mode 100644 index 00000000..1e514930 --- /dev/null +++ b/src/ui/gui/t-test-independent-samples-dialog.c @@ -0,0 +1,335 @@ +/* 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 . +*/ + + +#include +#include +#include "t-test-independent-samples-dialog.h" +#include "psppire-dict.h" +#include "psppire-var-store.h" +#include "helper.h" +#include +#include "data-editor.h" +#include "psppire-dialog.h" +#include "dialog-common.h" +#include "dict-display.h" +#include "widget-io.h" + +#include +#include "syntax-editor.h" + +#include +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + + +struct tt_indep_samples_dialog +{ + GladeXML *xml; /* The xml that generated the widgets */ + PsppireDict *dict; + gboolean groups_defined; + gboolean non_default_options; + gdouble confidence_interval; +}; + + +static gchar * +generate_syntax (const struct tt_indep_samples_dialog *d) +{ + gchar *text; + GtkWidget *entry = + get_widget_assert (d->xml, "indep-samples-t-test-entry"); + + GtkWidget *tv = + get_widget_assert (d->xml, "indep-samples-t-test-treeview2"); + + GString *str = g_string_new ("T-TEST /VARIABLES="); + + append_variable_names (str, d->dict, GTK_TREE_VIEW (tv)); + + g_string_append (str, "\n\t/GROUPS="); + + g_string_append (str, gtk_entry_get_text (GTK_ENTRY (entry))); + + if ( d->groups_defined ) + { + GtkWidget *entry1 = get_widget_assert (d->xml, "group1-entry"); + GtkWidget *entry2 = get_widget_assert (d->xml, "group2-entry"); + + g_string_append (str, "("); + g_string_append (str, gtk_entry_get_text (GTK_ENTRY (entry1))); + g_string_append (str, ","); + g_string_append (str, gtk_entry_get_text (GTK_ENTRY (entry2))); + g_string_append (str, ")"); + } + + if ( d->non_default_options ) + { + GtkToggleButton *analysis = + GTK_TOGGLE_BUTTON (get_widget_assert (d->xml, "radiobutton1")); + + g_string_append (str, "\n\t"); + g_string_append_printf (str, "/CRITERIA=CIN(%g)", + d->confidence_interval/100.0); + + + g_string_append (str, "\n\t"); + g_string_append_printf (str, "/MISSING=%s", + gtk_toggle_button_get_active (analysis) ? + "ANALYSIS" : "LISTWISE"); + } + + g_string_append (str, ".\n"); + + text = str->str; + + g_string_free (str, FALSE); + + return text; +} + + + +static void +refresh (GladeXML *xml) +{ + GtkWidget *entry = + get_widget_assert (xml, "indep-samples-t-test-entry"); + + GtkWidget *tv = + get_widget_assert (xml, "indep-samples-t-test-treeview2"); + + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tv)); + + gtk_entry_set_text (GTK_ENTRY (entry), ""); + + gtk_list_store_clear (GTK_LIST_STORE (model)); +} + + +static gboolean +define_groups_state_valid (gpointer data) +{ + struct tt_indep_samples_dialog *d = data; + + GtkWidget *entry1 = get_widget_assert (d->xml, "group1-entry"); + GtkWidget *entry2 = get_widget_assert (d->xml, "group2-entry"); + + if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry1)))) + return FALSE; + + if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry2)))) + return FALSE; + + return TRUE; +} + +static void +run_define_groups (struct tt_indep_samples_dialog *ttd) +{ + gint response; + GtkWidget *dialog = + get_widget_assert (ttd->xml, "define-groups-dialog"); + + + psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog), + define_groups_state_valid, ttd); + + response = psppire_dialog_run (PSPPIRE_DIALOG (dialog)); + + ttd->groups_defined = (response == PSPPIRE_RESPONSE_CONTINUE); +} + + +static void +run_options (struct tt_indep_samples_dialog *ttd) +{ + gint response; + GtkWidget *dialog = + get_widget_assert (ttd->xml, "options-dialog"); + + GtkWidget *box = + get_widget_assert (ttd->xml, "vbox1"); + + GtkSpinButton *conf_percent = NULL; + + GtkWidget *confidence = + widget_scanf (_("Confidence Interval: %2d %%"), + &conf_percent); + + gtk_spin_button_set_value (conf_percent, ttd->confidence_interval); + + gtk_widget_show (confidence); + + gtk_box_pack_start_defaults (GTK_BOX (box), confidence); + + response = psppire_dialog_run (PSPPIRE_DIALOG (dialog)); + + if ( response == PSPPIRE_RESPONSE_CONTINUE) + { + ttd->non_default_options = TRUE; + ttd->confidence_interval = gtk_spin_button_get_value (conf_percent); + } + + gtk_container_remove (GTK_CONTAINER (box), confidence); +} + + + + +static gboolean +dialog_state_valid (gpointer data) +{ + struct tt_indep_samples_dialog *tt_d = data; + + GtkWidget *entry = + get_widget_assert (tt_d->xml, "indep-samples-t-test-entry"); + + GtkWidget *tv_vars = + get_widget_assert (tt_d->xml, "indep-samples-t-test-treeview2"); + + GtkTreeModel *vars = gtk_tree_view_get_model (GTK_TREE_VIEW (tv_vars)); + + GtkTreeIter notused; + + if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry)))) + return FALSE; + + + if ( 0 == gtk_tree_model_get_iter_first (vars, ¬used)) + return FALSE; + + return TRUE; +} + + +/* Pops up the dialog box */ +void +t_test_independent_samples_dialog (GObject *o, gpointer data) +{ + struct tt_indep_samples_dialog tt_d; + gint response; + struct data_editor *de = data; + + PsppireVarStore *vs; + + GladeXML *xml = XML_NEW ("t-test.glade"); + + GtkWidget *dialog = get_widget_assert (xml, + "t-test-independent-samples-dialog"); + + GtkSheet *var_sheet = + GTK_SHEET (get_widget_assert (de->xml, "variable_sheet")); + + GtkWidget *dict_view = + get_widget_assert (xml, "indep-samples-t-test-treeview1"); + + GtkWidget *test_variables_treeview = + get_widget_assert (xml, "indep-samples-t-test-treeview2"); + + GtkWidget *selector2 = + get_widget_assert (xml, "indep-samples-t-test-selector2"); + + GtkWidget *selector1 = + get_widget_assert (xml, "indep-samples-t-test-selector1"); + + + GtkWidget *entry = + get_widget_assert (xml, "indep-samples-t-test-entry"); + + GtkWidget *define_groups_button = + get_widget_assert (xml, "define-groups-button"); + + GtkWidget *options_button = + get_widget_assert (xml, "options-button"); + + vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet)); + + tt_d.xml = xml; + tt_d.dict = vs->dict; + tt_d.groups_defined = FALSE; + tt_d.non_default_options = FALSE; + tt_d.confidence_interval = 95.0; + + gtk_window_set_transient_for (GTK_WINDOW (dialog), de->parent.window); + + attach_dictionary_to_treeview (GTK_TREE_VIEW (dict_view), + vs->dict, + GTK_SELECTION_MULTIPLE, NULL); + + set_dest_model (GTK_TREE_VIEW (test_variables_treeview), vs->dict); + + + psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector1), + dict_view, test_variables_treeview, + insert_source_row_into_tree_view, + NULL); + + + psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector2), + dict_view, entry, + insert_source_row_into_entry, + is_currently_in_entry); + + g_signal_connect_swapped (define_groups_button, "clicked", + G_CALLBACK (run_define_groups), &tt_d); + + + g_signal_connect_swapped (options_button, "clicked", + G_CALLBACK (run_options), &tt_d); + + + g_signal_connect_swapped (dialog, "refresh", G_CALLBACK (refresh), xml); + + + psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog), + dialog_state_valid, &tt_d); + + response = psppire_dialog_run (PSPPIRE_DIALOG (dialog)); + + switch (response) + { + case GTK_RESPONSE_OK: + { + gchar *syntax = generate_syntax (&tt_d); + struct getl_interface *sss = create_syntax_string_source (syntax); + execute_syntax (sss); + + g_free (syntax); + } + break; + case PSPPIRE_RESPONSE_PASTE: + { + gchar *syntax = generate_syntax (&tt_d); + + struct syntax_editor *se = + (struct syntax_editor *) window_create (WINDOW_SYNTAX, NULL); + + gtk_text_buffer_insert_at_cursor (se->buffer, syntax, -1); + + g_free (syntax); + } + break; + default: + break; + } + + + g_object_unref (xml); +} + + diff --git a/src/ui/gui/t-test-independent-samples-dialog.h b/src/ui/gui/t-test-independent-samples-dialog.h new file mode 100644 index 00000000..175cbfd6 --- /dev/null +++ b/src/ui/gui/t-test-independent-samples-dialog.h @@ -0,0 +1,6 @@ +#ifndef T_TEST_INDEPENDENT_SAMPLES_DIALOG +#define T_TEST_INDEPENDENT_SAMPLES_DIALOG + +void t_test_independent_samples_dialog (GObject *, gpointer) ; + +#endif diff --git a/src/ui/gui/t-test.glade b/src/ui/gui/t-test.glade new file mode 100644 index 00000000..c5119ef0 --- /dev/null +++ b/src/ui/gui/t-test.glade @@ -0,0 +1,403 @@ + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Independent-Samples T Test + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 3 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_SPREAD + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Define Groups + 0 + + + False + False + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Options... + 0 + + + False + False + 1 + + + + + 2 + 2 + 3 + GTK_FILL + 5 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + + GTK_EXPAND + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + 1 + 2 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Test Variable(s): + + + False + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + + + 1 + + + + + 1 + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Grouping Variable: + + + False + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + + + + + 1 + 2 + 1 + 2 + + + + + + 1 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + False + False + GTK_PACK_END + 1 + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Define Groups + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + 2 + 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Group_2 value: + True + + + 1 + 2 + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Group_1 value: + True + + + + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + 1 + 2 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + 1 + 2 + + + + + 5 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + PSPPIRE_BUTTON_CONTINUE_MASK | PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK + + + False + False + GTK_PACK_END + 1 + + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Options + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_SPREAD + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Exclude cases _analysis by analysis + True + 0 + True + True + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Exclude cases _listwise + True + 0 + True + True + radiobutton1 + + + 1 + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Missing Values + True + + + label_item + + + + + GTK_PACK_END + 1 + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + True + PSPPIRE_BUTTON_CONTINUE_MASK | PSPPIRE_BUTTON_CANCEL_MASK | PSPPIRE_BUTTON_HELP_MASK + + + False + False + GTK_PACK_END + 1 + + + + + + diff --git a/src/ui/gui/widget-io.c b/src/ui/gui/widget-io.c index 81ffd731..e6471990 100644 --- a/src/ui/gui/widget-io.c +++ b/src/ui/gui/widget-io.c @@ -27,21 +27,42 @@ #include +/* 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_directive *dir) +ship_label (GtkBox *box, const char **s, + const char_directives *dirs, size_t dir_idx) { GtkWidget *label ; - gchar *text = g_strdup (*s); + GString *str = g_string_new (*s); - if ( dir ) + if ( dirs) { - text [ dir->dir_start - *s ] = '\0'; - *s = dir->dir_end; + 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 (text); - g_free (text); + label = gtk_label_new (str->str); + + g_string_free (str, TRUE); gtk_box_pack_start (box, label, FALSE, FALSE, 0); gtk_widget_show (label); @@ -158,6 +179,7 @@ widget_scanf (const gchar *fmt, ...) va_end (ap); + for (i = 0 ; i < d.count ; ++i ) { char_directive dir = d.dir[i]; @@ -173,11 +195,11 @@ widget_scanf (const gchar *fmt, ...) width = strtol (dir.width_start, (char **) &dir.width_end, 10); if ( dir.dir_start > s ) - ship_label (GTK_BOX (hbox), &s, &dir); + ship_label (GTK_BOX (hbox), &s, &d, i); if ( dir.conversion == '%') { - s++; + if (s) s++; continue; } @@ -202,8 +224,9 @@ widget_scanf (const gchar *fmt, ...) gtk_widget_show (*w); } - if ( *s ) - ship_label (GTK_BOX (hbox), &s, NULL); + if ( s && *s ) + ship_label (GTK_BOX (hbox), &s, NULL, 0); + g_free (widgets); -- 2.30.2