Regenerate tests after "Make xy file output IPC 7531 compliant.".
[geda-pcb/kupson.git] / src / hid / gtk / ghid-coord-entry.c
bloba49ceca6b35a42192580eeda6b7682f396b0dab8
1 /*! \file <gtk-pcb-coord-entry.c>
2 * \brief Implementation of GHidCoordEntry widget
3 * \par Description
4 * This widget is a modified spinbox for the user to enter
5 * pcb coords. It is assigned a default unit (for display),
6 * but this can be changed by the user by typing a new one
7 * or right-clicking on the box.
9 * Internally, it keeps track of its value in pcb coords.
10 * From the user's perspective, it uses natural human units.
13 #include <glib.h>
14 #include <glib-object.h>
15 #include <gtk/gtk.h>
17 #include "gtkhid.h"
18 #include "gui.h"
19 #include "pcb-printf.h"
21 #include "ghid-coord-entry.h"
23 enum {
24 UNIT_CHANGE_SIGNAL,
25 LAST_SIGNAL
28 static guint ghid_coord_entry_signals[LAST_SIGNAL] = { 0 };
30 struct _GHidCoordEntry
32 GtkSpinButton parent;
34 Coord min_value;
35 Coord max_value;
36 Coord value;
38 enum ce_step_size step_size;
39 const Unit *unit;
42 struct _GHidCoordEntryClass
44 GtkSpinButtonClass parent_class;
46 void (* change_unit) (GHidCoordEntry *, const Unit *);
49 /* SIGNAL HANDLERS */
50 /*! \brief Callback for "Change Unit" menu click */
51 static void
52 menu_item_activate_cb (GtkMenuItem *item, GHidCoordEntry *ce)
54 const char *text = gtk_menu_item_get_label (item);
55 const Unit *unit = get_unit_struct (text);
57 g_signal_emit (ce, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, unit);
60 /*! \brief Callback for context menu creation */
61 static void
62 ghid_coord_entry_popup_cb (GHidCoordEntry *ce, GtkMenu *menu, gpointer data)
64 int i, n;
65 const Unit *unit_list;
66 GtkWidget *menu_item, *submenu;
68 /* Build submenu */
69 n = get_n_units ();
70 unit_list = get_unit_list ();
72 submenu = gtk_menu_new ();
73 for (i = 0; i < n; ++i)
75 menu_item = gtk_menu_item_new_with_label (unit_list[i].suffix);
76 g_signal_connect (G_OBJECT (menu_item), "activate",
77 G_CALLBACK (menu_item_activate_cb), ce);
78 gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu_item);
79 gtk_widget_show (menu_item);
82 /* Add submenu to menu */
83 menu_item = gtk_separator_menu_item_new ();
84 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
85 gtk_widget_show (menu_item);
87 menu_item = gtk_menu_item_new_with_label (_("Change Units"));
88 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
89 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
90 gtk_widget_show (menu_item);
93 /*! \brief Callback for user output */
94 static gboolean
95 ghid_coord_entry_output_cb (GHidCoordEntry *ce, gpointer data)
97 GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
98 double value = gtk_adjustment_get_value (adj);
99 gchar *text;
101 text = pcb_g_strdup_printf ("%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
102 gtk_entry_set_text (GTK_ENTRY (ce), text);
103 g_free (text);
105 return TRUE;
108 /*! \brief Callback for user input */
109 static gboolean
110 ghid_coord_text_changed_cb (GHidCoordEntry *entry, gpointer data)
112 const char *text;
113 char *suffix;
114 const Unit *new_unit;
115 double value;
117 /* Check if units have changed */
118 text = gtk_entry_get_text (GTK_ENTRY (entry));
119 value = strtod (text, &suffix);
120 new_unit = get_unit_struct (suffix);
121 if (new_unit && new_unit != entry->unit)
123 entry->value = unit_to_coord (new_unit, value);
124 g_signal_emit (entry, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, new_unit);
127 return FALSE;
130 /*! \brief Callback for change in value (input or ^v clicks) */
131 static gboolean
132 ghid_coord_value_changed_cb (GHidCoordEntry *ce, gpointer data)
134 GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
136 /* Re-calculate internal value */
137 double value = gtk_adjustment_get_value (adj);
138 ce->value = unit_to_coord (ce->unit, value);
139 /* Handle potential unit changes */
140 ghid_coord_text_changed_cb (ce, data);
142 return FALSE;
145 /*! \brief Change the unit used by a coord entry
147 * \param [in] ce The entry to be acted on
148 * \parin [in] new_unit The new unit to be used
150 static void
151 ghid_coord_entry_change_unit (GHidCoordEntry *ce, const Unit *new_unit)
153 double climb_rate = 0.0;
154 GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
156 ce->unit = new_unit;
157 /* Re-calculate min/max values for spinbox */
158 gtk_adjustment_configure (adj, coord_to_unit (new_unit, ce->value),
159 coord_to_unit (new_unit, ce->min_value),
160 coord_to_unit (new_unit, ce->max_value),
161 ce->unit->step_small,
162 ce->unit->step_medium,
163 0.0);
165 switch (ce->step_size)
167 case CE_TINY: climb_rate = new_unit->step_tiny; break;
168 case CE_SMALL: climb_rate = new_unit->step_small; break;
169 case CE_MEDIUM: climb_rate = new_unit->step_medium; break;
170 case CE_LARGE: climb_rate = new_unit->step_large; break;
172 gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, climb_rate,
173 new_unit->default_prec + strlen (new_unit->suffix));
176 /* CONSTRUCTOR */
177 static void
178 ghid_coord_entry_init (GHidCoordEntry *ce)
180 /* Hookup signal handlers */
181 g_signal_connect (G_OBJECT (ce), "focus_out_event",
182 G_CALLBACK (ghid_coord_text_changed_cb), NULL);
183 g_signal_connect (G_OBJECT (ce), "value_changed",
184 G_CALLBACK (ghid_coord_value_changed_cb), NULL);
185 g_signal_connect (G_OBJECT (ce), "populate_popup",
186 G_CALLBACK (ghid_coord_entry_popup_cb), NULL);
187 g_signal_connect (G_OBJECT (ce), "output",
188 G_CALLBACK (ghid_coord_entry_output_cb), NULL);
191 static void
192 ghid_coord_entry_class_init (GHidCoordEntryClass *klass)
194 klass->change_unit = ghid_coord_entry_change_unit;
196 /* GtkAutoComplete *ce : the object acted on */
197 /* const Unit *new_unit: the new unit that was set */
198 ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL] =
199 g_signal_new ("change-unit",
200 G_TYPE_FROM_CLASS (klass),
201 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
202 G_STRUCT_OFFSET (GHidCoordEntryClass, change_unit),
203 NULL, NULL,
204 g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE,
205 1, G_TYPE_POINTER);
209 /* PUBLIC FUNCTIONS */
210 GType
211 ghid_coord_entry_get_type (void)
213 static GType ce_type = 0;
215 if (!ce_type)
217 const GTypeInfo ce_info =
219 sizeof (GHidCoordEntryClass),
220 NULL, /* base_init */
221 NULL, /* base_finalize */
222 (GClassInitFunc) ghid_coord_entry_class_init,
223 NULL, /* class_finalize */
224 NULL, /* class_data */
225 sizeof (GHidCoordEntry),
226 0, /* n_preallocs */
227 (GInstanceInitFunc) ghid_coord_entry_init,
230 ce_type = g_type_register_static (GTK_TYPE_SPIN_BUTTON,
231 "GHidCoordEntry",
232 &ce_info,
236 return ce_type;
239 /*! \brief Create a new GHidCoordEntry
241 * \param [in] min_val The minimum allowed value, in pcb coords
242 * \param [in] max_val The maximum allowed value, in pcb coords
243 * \param [in] value The default value, in pcb coords
244 * \param [in] unit The default unit
245 * \param [in] step_size How large the default increments should be
247 * \return a freshly-allocated GHidCoordEntry
249 GtkWidget *
250 ghid_coord_entry_new (Coord min_val, Coord max_val, Coord value,
251 const Unit *unit, enum ce_step_size step_size)
253 /* Setup spinbox min/max values */
254 double small_step, big_step;
255 GtkAdjustment *adj;
256 GHidCoordEntry *ce = g_object_new (GHID_COORD_ENTRY_TYPE, NULL);
258 ce->unit = unit;
259 ce->min_value = min_val;
260 ce->max_value = max_val;
261 ce->value = value;
263 ce->step_size = step_size;
264 switch (step_size)
266 case CE_TINY:
267 small_step = unit->step_tiny;
268 big_step = unit->step_small;
269 break;
270 case CE_SMALL:
271 small_step = unit->step_small;
272 big_step = unit->step_medium;
273 break;
274 case CE_MEDIUM:
275 small_step = unit->step_medium;
276 big_step = unit->step_large;
277 break;
278 case CE_LARGE:
279 small_step = unit->step_large;
280 big_step = unit->step_huge;
281 break;
282 default:
283 small_step = big_step = 0;
284 break;
287 adj = GTK_ADJUSTMENT (gtk_adjustment_new (coord_to_unit (unit, value),
288 coord_to_unit (unit, min_val),
289 coord_to_unit (unit, max_val),
290 small_step, big_step, 0.0));
291 gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, small_step,
292 unit->default_prec + strlen (unit->suffix));
293 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (ce), FALSE);
295 return GTK_WIDGET (ce);
298 /*! \brief Gets a GHidCoordEntry's value, in pcb coords */
299 Coord
300 ghid_coord_entry_get_value (GHidCoordEntry *ce)
302 return ce->value;
305 /*! \brief Sets a GHidCoordEntry's value, in pcb coords */
306 void
307 ghid_coord_entry_set_value (GHidCoordEntry *ce, Coord val)
309 gtk_spin_button_set_value (GTK_SPIN_BUTTON (ce),
310 coord_to_unit (ce->unit, val));