pcb 4.1.1
An interactive printed circuit board layout editor.

ghid-coord-entry.c

Go to the documentation of this file.
00001 
00013 #include <glib.h>
00014 #include <glib-object.h>
00015 #include <gtk/gtk.h>
00016 
00017 #include "gtkhid.h"
00018 #include "gui.h"
00019 #include "pcb-printf.h"
00020 
00021 #include "ghid-coord-entry.h"
00022 
00023 enum {
00024   UNIT_CHANGE_SIGNAL,
00025   LAST_SIGNAL
00026 };
00027 
00028 static guint ghid_coord_entry_signals[LAST_SIGNAL] = { 0 };
00029 
00030 struct _GHidCoordEntry
00031 {
00032   GtkSpinButton parent;
00033 
00034   Coord min_value;
00035   Coord max_value;
00036   Coord value;
00037 
00038   enum ce_step_size step_size;
00039   const Unit *unit;
00040 };
00041 
00042 struct _GHidCoordEntryClass
00043 {
00044   GtkSpinButtonClass parent_class;
00045 
00046   void (* change_unit) (GHidCoordEntry *, const Unit *);
00047 };
00048 
00049 /* SIGNAL HANDLERS */
00051 static void
00052 menu_item_activate_cb (GtkMenuItem *item, GHidCoordEntry *ce)
00053 {
00054   const char *text = gtk_menu_item_get_label (item);
00055   const Unit *unit = get_unit_struct (text);
00056   
00057   g_signal_emit (ce, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, unit);
00058 }
00059 
00061 static void
00062 ghid_coord_entry_popup_cb (GHidCoordEntry *ce, GtkMenu *menu, gpointer data)
00063 {
00064   int i, n;
00065   const Unit *unit_list;
00066   GtkWidget *menu_item, *submenu;
00067 
00068   /* Build submenu */
00069   n = get_n_units ();
00070   unit_list = get_unit_list ();
00071 
00072   submenu = gtk_menu_new ();
00073   for (i = 0; i < n; ++i)
00074     {
00075       menu_item = gtk_menu_item_new_with_label (unit_list[i].suffix);
00076       g_signal_connect (G_OBJECT (menu_item), "activate",
00077                         G_CALLBACK (menu_item_activate_cb), ce);
00078       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu_item);
00079       gtk_widget_show (menu_item);
00080     }
00081 
00082   /* Add submenu to menu */
00083   menu_item = gtk_separator_menu_item_new ();
00084   gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
00085   gtk_widget_show (menu_item);
00086 
00087   menu_item = gtk_menu_item_new_with_label (_("Change Units"));
00088   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
00089   gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
00090   gtk_widget_show (menu_item);
00091 }
00092 
00094 static gboolean
00095 ghid_coord_entry_output_cb (GHidCoordEntry *ce, gpointer data)
00096 {
00097   GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
00098   double value = gtk_adjustment_get_value (adj);
00099   gchar *text;
00100 
00101   text = pcb_g_strdup_printf ("%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
00102   gtk_entry_set_text (GTK_ENTRY (ce), text);
00103   g_free (text);
00104    
00105   return TRUE;
00106 }
00107 
00109 static gboolean
00110 ghid_coord_text_changed_cb (GHidCoordEntry *entry, gpointer data)
00111 {
00112   const char *text;
00113   char *suffix;
00114   const Unit *new_unit;
00115   double value;
00116 
00117   /* Check if units have changed */
00118   text = gtk_entry_get_text (GTK_ENTRY (entry));
00119   value = strtod (text, &suffix);
00120   new_unit = get_unit_struct (suffix);
00121   if (new_unit && new_unit != entry->unit)
00122     {
00123       entry->value = unit_to_coord (new_unit, value);
00124       g_signal_emit (entry, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, new_unit);
00125     }
00126 
00127   return FALSE;
00128 }
00129 
00131 static gboolean
00132 ghid_coord_value_changed_cb (GHidCoordEntry *ce, gpointer data)
00133 {
00134   GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
00135 
00136   /* Re-calculate internal value */
00137   double value = gtk_adjustment_get_value (adj);
00138   ce->value = unit_to_coord (ce->unit, value);
00139   /* Handle potential unit changes */
00140   ghid_coord_text_changed_cb (ce, data);
00141 
00142   return FALSE;
00143 }
00144 
00150 static void
00151 ghid_coord_entry_change_unit (GHidCoordEntry *ce, const Unit *new_unit)
00152 {
00153   double climb_rate = 0.0;
00154   GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
00155 
00156   ce->unit = new_unit;
00157   /* Re-calculate min/max values for spinbox */
00158   gtk_adjustment_configure (adj, coord_to_unit (new_unit, ce->value),
00159                                  coord_to_unit (new_unit, ce->min_value),
00160                                  coord_to_unit (new_unit, ce->max_value),
00161                                  ce->unit->step_small,
00162                                  ce->unit->step_medium,
00163                                  0.0);
00164 
00165   switch (ce->step_size)
00166     {
00167     case CE_TINY: climb_rate = new_unit->step_tiny; break;
00168     case CE_SMALL: climb_rate = new_unit->step_small; break;
00169     case CE_MEDIUM: climb_rate = new_unit->step_medium; break;
00170     case CE_LARGE: climb_rate = new_unit->step_large; break;
00171     }
00172   gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, climb_rate,
00173                              new_unit->default_prec + strlen (new_unit->suffix));
00174 }
00175 
00176 /* CONSTRUCTOR */
00177 static void
00178 ghid_coord_entry_init (GHidCoordEntry *ce)
00179 {
00180   /* Hookup signal handlers */
00181   g_signal_connect (G_OBJECT (ce), "focus_out_event",
00182                     G_CALLBACK (ghid_coord_text_changed_cb), NULL);
00183   g_signal_connect (G_OBJECT (ce), "value_changed",
00184                     G_CALLBACK (ghid_coord_value_changed_cb), NULL);
00185   g_signal_connect (G_OBJECT (ce), "populate_popup",
00186                     G_CALLBACK (ghid_coord_entry_popup_cb), NULL);
00187   g_signal_connect (G_OBJECT (ce), "output",
00188                     G_CALLBACK (ghid_coord_entry_output_cb), NULL);
00189 }
00190 
00191 static void
00192 ghid_coord_entry_class_init (GHidCoordEntryClass *klass)
00193 {
00194   klass->change_unit = ghid_coord_entry_change_unit;
00195 
00196   /* GtkAutoComplete *ce : the object acted on */
00197   /* const Unit *new_unit: the new unit that was set */
00198   ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL] =
00199     g_signal_new ("change-unit",
00200                   G_TYPE_FROM_CLASS (klass),
00201                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
00202                   G_STRUCT_OFFSET (GHidCoordEntryClass, change_unit),
00203                   NULL, NULL,
00204                   g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE,
00205                   1, G_TYPE_POINTER);
00206 
00207 }
00208 
00209 /* PUBLIC FUNCTIONS */
00210 GType
00211 ghid_coord_entry_get_type (void)
00212 {
00213   static GType ce_type = 0;
00214 
00215   if (!ce_type)
00216     {
00217       const GTypeInfo ce_info =
00218       {
00219         sizeof (GHidCoordEntryClass),
00220         NULL, /* base_init */
00221         NULL, /* base_finalize */
00222         (GClassInitFunc) ghid_coord_entry_class_init,
00223         NULL, /* class_finalize */
00224         NULL, /* class_data */
00225         sizeof (GHidCoordEntry),
00226         0,    /* n_preallocs */
00227         (GInstanceInitFunc) ghid_coord_entry_init,
00228       };
00229 
00230       ce_type = g_type_register_static (GTK_TYPE_SPIN_BUTTON,
00231                                         "GHidCoordEntry",
00232                                         &ce_info,
00233                                         0);
00234     }
00235 
00236   return ce_type;
00237 }
00238 
00249 GtkWidget *
00250 ghid_coord_entry_new (Coord min_val, Coord max_val, Coord value,
00251                          const Unit *unit, enum ce_step_size step_size)
00252 {
00253   /* Setup spinbox min/max values */
00254   double small_step, big_step;
00255   GtkAdjustment *adj;
00256   GHidCoordEntry *ce = g_object_new (GHID_COORD_ENTRY_TYPE, NULL);
00257 
00258   ce->unit = unit;
00259   ce->min_value = min_val;
00260   ce->max_value = max_val;
00261   ce->value = value;
00262 
00263   ce->step_size = step_size;
00264   switch (step_size)
00265     {
00266     case CE_TINY:
00267       small_step = unit->step_tiny;
00268       big_step   = unit->step_small;
00269       break;
00270     case CE_SMALL:
00271       small_step = unit->step_small;
00272       big_step   = unit->step_medium;
00273       break;
00274     case CE_MEDIUM:
00275       small_step = unit->step_medium;
00276       big_step   = unit->step_large;
00277       break;
00278     case CE_LARGE:
00279       small_step = unit->step_large;
00280       big_step   = unit->step_huge;
00281       break;
00282     default:
00283       small_step = big_step = 0;
00284       break;
00285     }
00286 
00287   adj = GTK_ADJUSTMENT (gtk_adjustment_new (coord_to_unit (unit, value),
00288                                             coord_to_unit (unit, min_val),
00289                                             coord_to_unit (unit, max_val),
00290                                             small_step, big_step, 0.0));
00291   gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, small_step,
00292                              unit->default_prec + strlen (unit->suffix));
00293   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (ce), FALSE);
00294 
00295   return GTK_WIDGET (ce);
00296 }
00297 
00299 Coord
00300 ghid_coord_entry_get_value (GHidCoordEntry *ce)
00301 {
00302   return ce->value;
00303 }
00304 
00306 void
00307 ghid_coord_entry_set_value (GHidCoordEntry *ce, Coord val)
00308 {
00309   gtk_spin_button_set_value (GTK_SPIN_BUTTON (ce),
00310                              coord_to_unit (ce->unit, val));
00311 }
00312