diff --git a/ChangeLog b/ChangeLog index ba7294cce8..deb45809be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2002-05-27 Derek Atkins + + * dialog-options.c: implement a radiobutton option type. + * options.scm: implement a radiobutton option type. + * app-utils.scm: export the new radiobutton option creators + * prefs.scm: change the Account Separator to a radiobutton; move + to its own page + 2002-05-26 Derek Atkins * src/gnome-util/dialog-options.[ch]: Create an option-type diff --git a/src/app-utils/app-utils.scm b/src/app-utils/app-utils.scm index 1ec72ac74c..ea35c97b86 100644 --- a/src/app-utils/app-utils.scm +++ b/src/app-utils/app-utils.scm @@ -62,6 +62,8 @@ (export gnc:multichoice-list-lookup) (export gnc:make-multichoice-option) (export gnc:make-multichoice-callback-option) +(export gnc:make-radiobutton-option) +(export gnc:make-radiobutton-callback-option) (export gnc:make-list-option) (export gnc:make-number-range-option) diff --git a/src/app-utils/options.scm b/src/app-utils/options.scm index 281fa3b07b..be8eecab1b 100644 --- a/src/app-utils/options.scm +++ b/src/app-utils/options.scm @@ -613,6 +613,87 @@ (lambda (x) (option-widget-changed-cb x)))))) +;; radiobutton options use the option-data as a list of vectors. +;; Each vector contains a permissible value (scheme symbol), a +;; name, and a description string. +(define (gnc:make-radiobutton-option + section + name + sort-tag + documentation-string + default-value + ok-values) + (gnc:make-radiobutton-callback-option section + name + sort-tag + documentation-string + default-value + ok-values + #f + #f)) + +;; The radiobutton-option with callback function is the same as the +;; usual radiobutton options (see above), with the addition of two +;; function arguments. (If both of them are #f, you have exactly a +;; radiobutton-option.) Both functions should expect one argument. +;; When the option's value is changed, the function +;; option-widget-changed-cb will be called with the new option value +;; at the time that the GUI widget representing the option is changed, +;; and the function setter-function-called-cb will be called when the +;; option's setter is called (that is, when the user selects "OK" or +;; "Apply"). +(define (gnc:make-radiobutton-callback-option + section + name + sort-tag + documentation-string + default-value + ok-values + setter-function-called-cb + option-widget-changed-cb) + (define (radiobutton-legal val p-vals) + (cond ((null? p-vals) #f) + ((eq? val (vector-ref (car p-vals) 0)) #t) + (else (radiobutton-legal val (cdr p-vals))))) + + (define (radiobutton-strings p-vals) + (if (null? p-vals) + () + (cons (vector-ref (car p-vals) 1) + (cons (vector-ref (car p-vals) 2) + (radiobutton-strings (cdr p-vals)))))) + + (let* ((value default-value) + (value->string (lambda () + (string-append "'" (gnc:value->string value))))) + (gnc:make-option + section name sort-tag 'radiobutton documentation-string + (lambda () value) + (lambda (x) + (if (radiobutton-legal x ok-values) + (begin + (set! value x) + (if (procedure? setter-function-called-cb) + (setter-function-called-cb x))) + (gnc:error "Illegal Radiobutton option set"))) + (lambda () default-value) + (gnc:restore-form-generator value->string) + (lambda (x) + (if (radiobutton-legal x ok-values) + (list #t x) + (list #f "radiobutton-option: illegal choice"))) + ok-values + (vector (lambda () (length ok-values)) + (lambda (x) (vector-ref (list-ref ok-values x) 0)) + (lambda (x) (vector-ref (list-ref ok-values x) 1)) + (lambda (x) (vector-ref (list-ref ok-values x) 2)) + (lambda (x) + (gnc:multichoice-list-lookup ok-values x))) + (lambda () (radiobutton-strings ok-values)) + (and option-widget-changed-cb + (lambda (x) (option-widget-changed-cb x)))))) + + ;; list options use the option-data in the same way as multichoice ;; options. List options allow the user to select more than one option. (define (gnc:make-list-option diff --git a/src/app-utils/prefs.scm b/src/app-utils/prefs.scm index 29585744c9..234429f07b 100644 --- a/src/app-utils/prefs.scm +++ b/src/app-utils/prefs.scm @@ -417,8 +417,8 @@ through Window menu)"))) Control Center")))))) (gnc:register-configuration-option - (gnc:make-multichoice-option - (N_ "General") (N_ "Account Separator") + (gnc:make-radiobutton-option + (N_ "Accounts") (N_ "Account Separator") "c" (N_ "The character used to separate fully-qualified account names") 'colon (list (list->vector @@ -444,7 +444,7 @@ Control Center")))))) (gnc:register-configuration-option (gnc:make-multichoice-option - (N_ "General") (N_ "Reversed-balance account types") + (N_ "Accounts") (N_ "Reversed-balance account types") "d" (N_ "The types of accounts for which balances are sign-reversed") 'credit (list (list->vector @@ -463,7 +463,7 @@ Accounts"))) (gnc:register-configuration-option (gnc:make-simple-boolean-option - (N_ "General") (N_ "Use accounting labels") + (N_ "Accounts") (N_ "Use accounting labels") "e" (N_ "Only use 'debit' and 'credit' instead of informal synonyms") #f)) (gnc:register-configuration-option diff --git a/src/gnome-utils/dialog-options.c b/src/gnome-utils/dialog-options.c index 9e01fe7c03..456bb3f3df 100644 --- a/src/gnome-utils/dialog-options.c +++ b/src/gnome-utils/dialog-options.c @@ -390,6 +390,33 @@ gnc_option_multichoice_cb(GtkWidget *w, gint index, gpointer data) gnc_options_dialog_changed_internal (omenu); } +static void +gnc_option_radiobutton_cb(GtkWidget *w, gpointer data) +{ + GNCOption *option = data; + GtkWidget *widget; + gpointer _current, _new_value; + gint current, new_value; + + widget = gnc_option_get_widget (option); + + _current = gtk_object_get_data(GTK_OBJECT(widget), "gnc_radiobutton_index"); + current = GPOINTER_TO_INT (_current); + + _new_value = gtk_object_get_data (GTK_OBJECT(w), "gnc_radiobutton_index"); + new_value = GPOINTER_TO_INT (_new_value); + + if (current == new_value) + return; + + gtk_object_set_data (GTK_OBJECT(widget), "gnc_radiobutton_index", + GINT_TO_POINTER(new_value)); + + gnc_option_set_changed (option, TRUE); + gnc_option_call_option_widget_changed_proc(option); + gnc_options_dialog_changed_internal (widget); +} + static void gnc_option_rd_combo_cb(GtkWidget *w, gint index, gpointer data) { @@ -599,6 +626,71 @@ gnc_option_create_multichoice_widget(GNCOption *option) return widget; } +static void +radiobutton_destroy_cb (GtkObject *obj, gpointer data) +{ + GtkTooltips *tips = data; + + gtk_object_unref (GTK_OBJECT (tips)); +} + +static GtkWidget * +gnc_option_create_radiobutton_widget(char *name, GNCOption *option) +{ + GtkTooltips *tooltips; + GtkWidget *frame, *box; + GtkWidget *widget = NULL; + int num_values; + char *label; + char *tip; + int i; + + num_values = gnc_option_num_permissible_values(option); + + g_return_val_if_fail(num_values >= 0, NULL); + + /* Create our button frame */ + frame = gtk_frame_new (name); + + /* Create the button box */ + box = gtk_vbutton_box_new (); + gtk_container_add (GTK_CONTAINER (frame), box); + + /* Create the tooltips */ + tooltips = gtk_tooltips_new (); + gtk_object_ref (GTK_OBJECT (tooltips)); + gtk_object_sink (GTK_OBJECT (tooltips)); + + /* Iterate over the options and create a radio button for each one */ + for (i = 0; i < num_values; i++) + { + label = gnc_option_permissible_value_name(option, i); + tip = gnc_option_permissible_value_description(option, i); + + widget = + gtk_radio_button_new_with_label_from_widget (widget ? + GTK_RADIO_BUTTON (widget) : + NULL, + label ? _(label) : ""); + gtk_object_set_data (GTK_OBJECT (widget), "gnc_radiobutton_index", + GINT_TO_POINTER (i)); + gtk_tooltips_set_tip(tooltips, widget, tip ? _(tip) : "", NULL); + gtk_signal_connect(GTK_OBJECT(widget), "toggled", + GTK_SIGNAL_FUNC(gnc_option_radiobutton_cb), option); + gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0); + + if (label) + free (label); + if (tip) + free (tip); + } + + gtk_signal_connect (GTK_OBJECT (frame), "destroy", + GTK_SIGNAL_FUNC (radiobutton_destroy_cb), tooltips); + + return frame; +} + static void gnc_option_account_cb(GNCAccountTree *tree, Account * account, gpointer data) { @@ -1885,6 +1977,29 @@ gnc_option_set_ui_widget_pixmap (GNCOption *option, GtkBox *page_box, return value; } +static GtkWidget * +gnc_option_set_ui_widget_radiobutton (GNCOption *option, GtkBox *page_box, + GtkTooltips *tooltips, + char *name, char *documentation, + /* Return values */ + GtkWidget **enclosing, gboolean *packed) +{ + GtkWidget *value; + + *enclosing = gtk_hbox_new(FALSE, 5); + + value = gnc_option_create_radiobutton_widget(name, option); + gnc_option_set_widget (option, value); + + gnc_option_set_ui_value(option, FALSE); + gtk_box_pack_start(GTK_BOX(*enclosing), value, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(*enclosing), + gnc_option_create_default_button(option, tooltips), + FALSE, FALSE, 0); + gtk_widget_show_all(*enclosing); + return value; +} + /* SET VALUE */ static gboolean @@ -2210,6 +2325,41 @@ gnc_option_set_ui_value_pixmap (GNCOption *option, gboolean use_default, return TRUE; } +static gboolean +gnc_option_set_ui_value_radiobutton (GNCOption *option, gboolean use_default, + GtkWidget *widget, SCM value) +{ + int index; + + index = gnc_option_permissible_value_index(option, value); + if (index < 0) + return TRUE; + else + { + GtkWidget *box, *button; + GList *list; + int i; + gpointer val; + + list = gtk_container_children (GTK_CONTAINER (widget)); + box = list->data; + + list = gtk_container_children (GTK_CONTAINER (box)); + for (i = 0; i < index && list; i++) + list = list->next; + g_return_val_if_fail (list, TRUE); + + button = list->data; + val = gtk_object_get_data (GTK_OBJECT (button), "gnc_radiobutton_index"); + g_return_val_if_fail (GPOINTER_TO_INT (val) == index, TRUE); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + // gtk_object_set_data(GTK_OBJECT(widget), "gnc_radiobutton_index", + // GINT_TO_POINTER(index)); + return FALSE; + } +} + /* GET VALUE */ static SCM @@ -2428,6 +2578,18 @@ gnc_option_get_ui_value_pixmap (GNCOption *option, GtkWidget *widget) return (gh_str02scm(string ? string : "")); } +static SCM +gnc_option_get_ui_value_radiobutton (GNCOption *option, GtkWidget *widget) +{ + gpointer _index; + int index; + + _index = gtk_object_get_data(GTK_OBJECT(widget), "gnc_radiobutton_index"); + index = GPOINTER_TO_INT(_index); + + return (gnc_option_permissible_value(option, index)); +} + /* INITIALIZATION */ static void gnc_options_initialize_options (void) @@ -2459,6 +2621,8 @@ static void gnc_options_initialize_options (void) gnc_option_set_ui_value_font, gnc_option_get_ui_value_font }, { "pixmap", gnc_option_set_ui_widget_pixmap, gnc_option_set_ui_value_pixmap, gnc_option_get_ui_value_pixmap }, + { "radiobutton", gnc_option_set_ui_widget_radiobutton, + gnc_option_set_ui_value_radiobutton, gnc_option_get_ui_value_radiobutton }, { NULL, NULL, NULL, NULL } }; int i;