missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / gschem_integer_combo_box.c
blob2a69432866a2ed104825d1d1843244c848dddc9e
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /*! \file gschem_integer_combo_box.c
22 * \brief A GtkComboBox with and entry for integer values.
24 * This widget allows the user to type in an integer values or select a common
25 * integer value from a drop down menu.
27 #include <config.h>
29 #ifdef HAVE_ERRNO_H
30 #include <errno.h>
31 #endif
32 #include <stdio.h>
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
40 #include "gschem.h"
44 static void
45 add_widget (GschemIntegerComboBox *combo, GtkWidget *widget, gpointer unused);
47 static gboolean
48 focus_out_event (GtkEntry *entry, GdkEvent *event, GschemIntegerComboBox *combo);
50 static void
51 gschem_integer_combo_box_class_init (GschemIntegerComboBoxClass *klass);
53 static void
54 gschem_integer_combo_box_init (GschemIntegerComboBox *combo);
56 static void
57 notify_active (GschemIntegerComboBox *combo, GParamSpec *pspec, gpointer unused);
59 static void
60 remove_widget (GschemIntegerComboBox *combo, GtkWidget *widget, gpointer unused);
62 static void
63 value_changed (GschemIntegerComboBox *combo, gpointer unused);
67 /*! \brief The entry widget is added to the combo box.
69 * The combo box must keep a signal handler connected for the focus
70 * out event for the instant apply functionality.
72 * \param [in] combo This combo box
73 * \param [in] widget The entry widget added to the combo box
74 * \param [in] unused
76 static void
77 add_widget (GschemIntegerComboBox *combo, GtkWidget *widget, gpointer unused)
79 g_return_if_fail (combo != NULL);
80 g_return_if_fail (widget != NULL);
82 g_signal_connect(G_OBJECT (widget),
83 "focus-out-event",
84 G_CALLBACK (focus_out_event),
85 combo);
90 /*! \brief The entry widget inside the combo box lost focus.
92 * \param [in] entry The entry inside the combo box
93 * \param [in] event The focus out event
94 * \param [in] combo The combo box
96 static gboolean
97 focus_out_event (GtkEntry *entry, GdkEvent *event, GschemIntegerComboBox *combo)
99 g_return_val_if_fail (entry != NULL, FALSE);
100 g_return_val_if_fail (combo != NULL, FALSE);
102 if (combo->changed) {
103 g_signal_emit_by_name (combo, "apply");
104 combo->changed = FALSE;
107 return FALSE;
112 /*! \brief Initialize GschemIntegerComboBoxClass class
114 * \param [in] klass The class for the GschemIntegerComboBoxClass
116 static void
117 gschem_integer_combo_box_class_init (GschemIntegerComboBoxClass *klass)
119 g_return_if_fail (klass != NULL);
121 g_signal_new ("apply", /* signal_name */
122 G_OBJECT_CLASS_TYPE (klass), /* itype */
123 0, /* signal_flags */
124 0, /* class_offset */
125 NULL, /* accumulator */
126 NULL, /* accu_data */
127 g_cclosure_marshal_VOID__VOID, /* c_marshaller */
128 G_TYPE_NONE, /* return_type */
129 0 /* n_params */
135 /*! \brief Get the GschemIntegerComboBox type
137 * \return The GschemIntegerComboBox type
139 GType
140 gschem_integer_combo_box_get_type()
142 static GType type = 0;
144 if (type == 0) {
145 static const GTypeInfo info = {
146 sizeof(GschemIntegerComboBoxClass),
147 NULL, /* base_init */
148 NULL, /* base_finalize */
149 (GClassInitFunc) gschem_integer_combo_box_class_init,
150 NULL, /* class_finalize */
151 NULL, /* class_data */
152 sizeof(GschemIntegerComboBox),
153 0, /* n_preallocs */
154 (GInstanceInitFunc) gschem_integer_combo_box_init,
157 #if GTK_CHECK_VERSION (2, 24, 0)
158 type = g_type_register_static (GTK_TYPE_COMBO_BOX, "GschemIntegerComboBox", &info, 0);
159 #else
160 type = g_type_register_static (GTK_TYPE_COMBO_BOX_ENTRY, "GschemIntegerComboBox", &info, 0);
161 #endif
164 return type;
168 /*! \brief Get the entry associated with this combo box
170 * \param [in] widget The integer combo box
171 * \return The entry
173 GtkEntry*
174 gschem_integer_combo_box_get_entry (GtkWidget *widget)
176 g_return_val_if_fail (widget != NULL, NULL);
178 return GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget)));
182 /*! \brief Get the integer value
184 * \param [in,out] widget The integer combo box
185 * \return The integer. If the value is invalid, this function returns -1.
188 gschem_integer_combo_box_get_value (GtkWidget *widget)
190 GtkWidget *entry = GTK_WIDGET (gschem_integer_combo_box_get_entry (widget));
191 int size = -1;
192 const char *text0 = gtk_entry_get_text (GTK_ENTRY (entry));
194 if (text0 != NULL)
196 long temp;
197 char *text1;
199 errno = 0;
201 temp = strtol (text0, &text1, 0);
203 if ((errno == 0) && (text1 != NULL) && (*text1 == '\0') && (temp >= 0)) {
204 size = temp;
208 return size;
213 /*! \brief Initialize a GschemIntegerComboBox
215 * \param [in] klass The instance of a GschemIntegerComboBox
217 static void
218 gschem_integer_combo_box_init (GschemIntegerComboBox *combo)
220 g_return_if_fail (combo != NULL);
222 combo->changed = FALSE;
224 g_signal_connect(G_OBJECT (combo),
225 "notify::active",
226 G_CALLBACK (notify_active),
227 NULL);
229 g_signal_connect(G_OBJECT (combo),
230 "add",
231 G_CALLBACK (add_widget),
232 NULL);
234 g_signal_connect(G_OBJECT (combo),
235 "changed",
236 G_CALLBACK (value_changed),
237 NULL);
239 g_signal_connect(G_OBJECT (combo),
240 "remove",
241 G_CALLBACK (remove_widget),
242 NULL);
247 /*! \brief Create a ComboBox with an entry for integer values.
249 * \return A GtkWidget for entering integer values
251 GtkWidget*
252 gschem_integer_combo_box_new ()
254 #if GTK_CHECK_VERSION (2, 24, 0)
255 return GTK_WIDGET (g_object_new (GSCHEM_TYPE_INTEGER_COMBO_BOX, "has-entry", TRUE, NULL));
256 #else
257 return GTK_WIDGET (g_object_new (GSCHEM_TYPE_INTEGER_COMBO_BOX, NULL));
258 #endif
263 /*! \brief Set the list store containing the common values
265 * \param [in,out] widget The integer combo box
266 * \param [in] store The list containing the common values
268 void
269 gschem_integer_combo_box_set_model (GtkWidget *widget, GtkListStore *store)
271 g_return_if_fail (widget != NULL);
273 gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
275 if (store != NULL) {
276 #if GTK_CHECK_VERSION (2, 24, 0)
277 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), x_integerls_get_value_column ());
278 #else
279 gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (widget), x_integerls_get_value_column ());
280 #endif
286 /*! \brief Set the integer value
288 * \param [in,out] widget The integer combo box
289 * \param [in] size The value
291 void
292 gschem_integer_combo_box_set_value (GtkWidget *widget, int value)
294 GtkWidget *entry;
295 g_return_if_fail (widget != NULL);
296 entry = gtk_bin_get_child (GTK_BIN (widget));
297 g_return_if_fail (entry != NULL);
299 if (value >= 0) {
300 GString *string;
302 string = g_string_new (NULL);
303 g_string_printf (string, "%d", value);
304 gtk_entry_set_text (GTK_ENTRY (entry), string->str);
306 g_string_free (string, TRUE);
307 } else {
308 gtk_entry_set_text (GTK_ENTRY (entry), "");
313 /*! \brief The active item in the combo box has changed
315 static void
316 notify_active (GschemIntegerComboBox *combo, GParamSpec *pspec, gpointer unused)
318 g_return_if_fail (combo != NULL);
320 g_signal_emit_by_name (combo, "apply");
321 combo->changed = FALSE;
326 /*! \brief The entry widget is removed from the combo box.
328 * The combo box must keep a signal handler connected for the focus
329 * out event for the instant apply functionality.
331 * \param [in] combo This combo box
332 * \param [in] widget The netry widget added to the combo box
333 * \param [in] unused
335 static void
336 remove_widget (GschemIntegerComboBox *combo, GtkWidget *widget, gpointer unused)
338 g_return_if_fail (combo != NULL);
339 g_return_if_fail (widget != NULL);
341 g_signal_handlers_disconnect_by_func(G_OBJECT (widget),
342 G_CALLBACK (focus_out_event),
343 combo);
348 /*! \brief Respond to a change in the value
350 * The function checks the focus to determine the source of the event.
351 * If the entry has focus, the user changed the value, possibly by one
352 * keystroke, and the dialog box should not update the selection. If the
353 * entry does not have focus, the user changed the value in the dropdown
354 * menu, and the dialog box must update the selection.
356 * \param [in] combo This widget
357 * \param [in] unused
359 static void
360 value_changed (GschemIntegerComboBox *combo, gpointer unused)
362 g_return_if_fail (combo != NULL);
364 if (gtk_widget_is_focus (GTK_WIDGET (gschem_integer_combo_box_get_entry (GTK_WIDGET (combo))))) {
365 combo->changed = TRUE;
368 /* This code was getting called before the value changed. The signal handler
369 * was fetching data from one selection in the past.
371 * This code is here in case of compatibility issues pre and post 2.24, that
372 * there will be some info for addressing the issue.
375 #if 0
376 else {
377 g_signal_emit_by_name (combo, "apply");
378 combo->changed = FALSE;
380 #endif