/* This is -*- C -*- */ /* $Id: guppi-metric-entry.c,v 1.11 2002/01/14 05:01:23 trow Exp $ */ /* * guppi-metric-entry.c * * Copyright (C) 2000 EMC Capital Management, Inc. * Copyright (C) 2001 The Free Software Foundation * * Developed by Jon Trowbridge and * Havoc Pennington . * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include "guppi-metric-entry.h" #include #include #include #include #include #include #include #include #include #include #include "guppi-defaults.h" #include "guppi-memory.h" static GtkObjectClass *parent_class = NULL; enum { CHANGED_VALUE, CHANGED_UNITS, LAST_SIGNAL }; guint me_signals[LAST_SIGNAL] = { 0 }; static void guppi_metric_entry_destroy (GtkObject *obj) { if (parent_class->destroy) parent_class->destroy (obj); } static void guppi_metric_entry_finalize (GtkObject *obj) { if (parent_class->finalize) parent_class->finalize (obj); } /**********************************************************************/ static void read_value (GtkEditable *editable, gpointer data) { GuppiMetricEntry *me = GUPPI_METRIC_ENTRY (data); gchar *txt = gtk_editable_get_chars (editable, 0, -1); double x = atof (txt); guppi_metric_entry_set_pt_value (me, guppi_to_pt (x, me->displayed_units)); guppi_free (txt); } static void write_value (GuppiMetricEntry *me) { double x = guppi_from_pt (guppi_metric_entry_pt_value (me), me->displayed_units); gchar *str = g_strdup_printf ("%g", x); gint pos = 0; gtk_editable_delete_text (GTK_EDITABLE (me->entry), 0, -1); gtk_editable_insert_text (GTK_EDITABLE (me->entry), str, strlen (str), &pos); g_free (str); } static void changed_units (GuppiMetricEntry *me) { gchar *str; double new_pt_val; new_pt_val = guppi_from_pt (me->pt_val, me->displayed_units); str = guppi_strdup_printf ("%g", new_pt_val); gtk_entry_set_text (GTK_ENTRY (me->entry), str); guppi_free (str); } /**********************************************************************/ static void guppi_metric_entry_class_init (GuppiMetricEntryClass *klass) { GtkObjectClass *object_class = (GtkObjectClass *) klass; parent_class = gtk_type_class (GTK_TYPE_HBOX); object_class->destroy = guppi_metric_entry_destroy; object_class->finalize = guppi_metric_entry_finalize; klass->changed_units = changed_units; me_signals[CHANGED_VALUE] = gtk_signal_new ("changed_value", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GuppiMetricEntryClass, changed_value), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); me_signals[CHANGED_UNITS] = gtk_signal_new ("changed_units", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET (GuppiMetricEntryClass, changed_units), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); gtk_object_class_add_signals (object_class, me_signals, LAST_SIGNAL); } static void guppi_metric_entry_init (GuppiMetricEntry *obj) { } GtkType guppi_metric_entry_get_type (void) { static GtkType guppi_metric_entry_type = 0; if (!guppi_metric_entry_type) { static const GtkTypeInfo guppi_metric_entry_info = { "GuppiMetricEntry", sizeof (GuppiMetricEntry), sizeof (GuppiMetricEntryClass), (GtkClassInitFunc) guppi_metric_entry_class_init, (GtkObjectInitFunc) guppi_metric_entry_init, NULL, NULL, (GtkClassInitFunc) NULL }; guppi_metric_entry_type = gtk_type_unique (GTK_TYPE_HBOX, &guppi_metric_entry_info); } return guppi_metric_entry_type; } static void unit_select_cb (GtkWidget *w, gpointer ptr) { GuppiMetricEntry *me = GUPPI_METRIC_ENTRY (ptr); guppi_metric_t units; /* Make sure that what appears in the entry is actually what we have stored as the point value. */ read_value (GTK_EDITABLE (me->entry), me); units = (guppi_metric_t) GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (w), "units")); guppi_metric_entry_set_displayed_units (me, units); } static gboolean valid_number (GuppiMetricEntry *me, const gchar *str) { gchar *end_ptr; gint len = strlen (str); double x; if (len == 1 && *str == '-' && !me->no_negatives) return TRUE; if (len == 1 && *str == '.') return TRUE; x = strtod (str, &end_ptr); if (end_ptr == NULL) return FALSE; if (*end_ptr != '\0') return FALSE; if (me->no_negatives && x < 0) return FALSE; if (me->no_zero && x == 0) return FALSE; return TRUE; } static void insert_text_handler (GtkEditable *editable, const gchar *text, gint length, gint *position, gpointer data) { GuppiMetricEntry *me = GUPPI_METRIC_ENTRY (data); gint i, j; gchar *result = guppi_new (gchar, length); gchar *pre_insert_text; gchar *post_insert_text; gint saved_pos; /* Filter out any characters that couldn't possibly be part of a number. */ j = 0; for (i = 0; i < length; i++) if (isdigit ((guchar)text[i]) || text[i] == '.' || text[i] == ',' || text[i] == '-') { result[j] = text[i]; ++j; } gtk_signal_handler_block_by_func (GTK_OBJECT (editable), GTK_SIGNAL_FUNC (insert_text_handler), data); pre_insert_text = gtk_editable_get_chars (editable, 0, -1); saved_pos = gtk_editable_get_position (editable); gtk_editable_insert_text (editable, result, j, position); post_insert_text = gtk_editable_get_chars (editable, 0, -1); /* Check that our entry is a valid number. If not, we undo the insert. */ if (!valid_number (me, post_insert_text)) { gint pos = 0; gtk_editable_delete_text (editable, 0, -1); gtk_editable_insert_text (editable, pre_insert_text, strlen (pre_insert_text), &pos); /* This doesn't seem to work... */ gtk_editable_set_position (editable, saved_pos); } else { read_value (editable, me); } gtk_signal_handler_unblock_by_func (GTK_OBJECT (editable), GTK_SIGNAL_FUNC (insert_text_handler), data); gtk_signal_emit_stop_by_name (GTK_OBJECT (editable), "insert_text"); guppi_free (result); guppi_free (pre_insert_text); guppi_free (post_insert_text); } static void delete_text_handler (GtkEditable *editable, gint start_pos, gint end_pos, gpointer user_data) { read_value (editable, GUPPI_METRIC_ENTRY (user_data)); } static void focus_out (GtkEditable *editable, GdkEventFocus *ev, gpointer data) { read_value (editable, data); } void guppi_metric_entry_construct (GuppiMetricEntry *me) { const guppi_metric_t units[] = { GUPPI_PT, GUPPI_IN, GUPPI_CM, GUPPI_MM, GUPPI_PX, GUPPI_INVALID_METRIC }; gint i, j = 0; GtkWidget *menu; g_return_if_fail (me != NULL && GUPPI_IS_METRIC_ENTRY (me)); me->pt_val = 0; me->displayed_units = guppi_default_units (); me->entry = gtk_entry_new (); gtk_signal_connect (GTK_OBJECT (me->entry), "insert_text", GTK_SIGNAL_FUNC (insert_text_handler), me); gtk_signal_connect (GTK_OBJECT (me->entry), "delete_text", GTK_SIGNAL_FUNC (delete_text_handler), me); gtk_signal_connect (GTK_OBJECT (me->entry), "activate", GTK_SIGNAL_FUNC (read_value), me); gtk_signal_connect (GTK_OBJECT (me->entry), "focus_out_event", GTK_SIGNAL_FUNC (focus_out), me); gtk_widget_show (me->entry); menu = gtk_menu_new (); for (i = 0; units[i] != GUPPI_INVALID_METRIC; ++i) { GtkWidget *mi; if (units[i] == me->displayed_units) j = i; mi = gtk_menu_item_new_with_label (guppi_metric_name (units[i])); gtk_object_set_data (GTK_OBJECT (mi), "units", GINT_TO_POINTER (units[i])); gtk_signal_connect (GTK_OBJECT (mi), "activate", GTK_SIGNAL_FUNC (unit_select_cb), me); gtk_widget_show (mi); gtk_menu_append (GTK_MENU (menu), mi); } me->units_opt = gtk_option_menu_new (); gtk_option_menu_set_menu (GTK_OPTION_MENU (me->units_opt), menu); gtk_option_menu_set_history (GTK_OPTION_MENU (me->units_opt), j); gtk_widget_show (menu); gtk_widget_show (me->units_opt); gtk_box_pack_start (GTK_BOX (me), me->entry, TRUE, TRUE, 0); gtk_box_pack_end (GTK_BOX (me), me->units_opt, FALSE, FALSE, 0); } GtkWidget * guppi_metric_entry_new (void) { GtkObject *obj = guppi_type_new (guppi_metric_entry_get_type ()); guppi_metric_entry_construct (GUPPI_METRIC_ENTRY (obj)); return GTK_WIDGET (obj); } double guppi_metric_entry_pt_value (GuppiMetricEntry *me) { g_return_val_if_fail (me != NULL && GUPPI_IS_METRIC_ENTRY (me), 0); return me->pt_val; } void guppi_metric_entry_set_pt_value (GuppiMetricEntry *me, double x) { g_return_if_fail (me != NULL && GUPPI_IS_METRIC_ENTRY (me)); if (me->no_negatives) g_return_if_fail (x >= 0); if (me->no_zero) g_return_if_fail (x != 0); if (x != me->pt_val) { me->pt_val = x; gtk_signal_emit (GTK_OBJECT (me), me_signals[CHANGED_VALUE]); write_value (me); } } guppi_metric_t guppi_metric_entry_displayed_units (GuppiMetricEntry *me) { g_return_val_if_fail (me != NULL && GUPPI_IS_METRIC_ENTRY (me), GUPPI_INVALID_METRIC); return me->displayed_units; } void guppi_metric_entry_set_displayed_units (GuppiMetricEntry *me, guppi_metric_t units) { g_return_if_fail (me != NULL && GUPPI_IS_METRIC_ENTRY (me)); g_return_if_fail (units != GUPPI_INVALID_METRIC); if (me->displayed_units != units) { me->displayed_units = units; gtk_signal_emit (GTK_OBJECT (me), me_signals[CHANGED_UNITS]); } } /* $Id: guppi-metric-entry.c,v 1.11 2002/01/14 05:01:23 trow Exp $ */