1 /*
2 * Copyright (C) 2004 2006 2009, Magnus Hjorth
3 *
4 * This file is part of mhWaveEdit.
5 *
6 * mhWaveEdit 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.
10 *
11 * mhWaveEdit 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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with mhWaveEdit; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21
22 #include <config.h>
23
24 #include "combo.h"
25
26 enum { CHANGED_SIGNAL, LAST_SIGNAL };
27 static guint combo_signals[LAST_SIGNAL] = { 0 };
28
29 static gboolean updating_flag = FALSE;
30
31 static GtkObjectClass *parent_class;
32
combo_size_request(GtkWidget * widget,GtkRequisition * req)33 static void combo_size_request(GtkWidget *widget, GtkRequisition *req)
34 {
35 Combo *obj = COMBO(widget);
36 GTK_WIDGET_CLASS(parent_class)->size_request(widget,req);
37 if (obj->max_request_width >= 0 && req->width > obj->max_request_width)
38 req->width = obj->max_request_width;
39 }
40
41 #ifdef COMBO_OLDSCHOOL
42
combo_class_init(GtkObjectClass * klass)43 static void combo_class_init(GtkObjectClass *klass)
44 {
45 parent_class = gtk_type_class(COMBO_PARENT_TYPE_FUNC());
46 COMBO_CLASS(klass)->selection_changed = NULL;
47 combo_signals[CHANGED_SIGNAL] =
48 gtk_signal_new("selection_changed",GTK_RUN_LAST,
49 GTK_CLASS_TYPE(klass),
50 GTK_SIGNAL_OFFSET(ComboClass,selection_changed),
51 gtk_marshal_NONE__NONE,GTK_TYPE_NONE,0);
52 gtk_object_class_add_signals(klass,combo_signals,LAST_SIGNAL);
53 GTK_WIDGET_CLASS(klass)->size_request = combo_size_request;
54 }
55
56
hide_popup(GtkWidget * widget,Combo * combo)57 static void hide_popup(GtkWidget *widget, Combo *combo)
58 {
59 int i = combo->next_chosen_index;
60 if (i >= 0) {
61 combo->next_chosen_index = -1;
62 combo_set_selection(combo,i);
63 }
64 }
65
list_select_child(GtkList * list,GtkWidget * child,gpointer user_data)66 static void list_select_child(GtkList *list, GtkWidget *child,
67 gpointer user_data)
68 {
69 Combo *combo = COMBO(user_data);
70 int idx;
71 if (updating_flag) return;
72 idx = gtk_list_child_position(list,child);
73 if (GTK_WIDGET_VISIBLE(GTK_COMBO(combo)->popwin)) {
74 combo->next_chosen_index = idx;
75 return;
76 }
77 combo->chosen_index = idx;
78 gtk_signal_emit(GTK_OBJECT(combo),combo_signals[CHANGED_SIGNAL]);
79 }
80
list_motion_notify(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)81 static gboolean list_motion_notify(GtkWidget *widget, GdkEventMotion *event,
82 gpointer user_data)
83 {
84 gint mx,my;
85 gint wx,wy,ww,wh;
86
87 gdk_window_get_root_origin(widget->window,&wx,&wy);
88 gdk_window_get_size(widget->window,&ww,&wh);
89 mx = (gint) (event->x_root);
90 my = (gint) (event->y_root);
91
92 /*printf("mouse: <%d,%d>, window: <%d,%d>+<%d,%d>\n",mx,my,wx,wy,ww,wh);*/
93 if (mx < wx || mx > wx+ww || my < wy || my > wy+wh)
94 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget),
95 "motion-notify-event");
96 return FALSE;
97 }
98
combo_init(GtkObject * obj)99 static void combo_init(GtkObject *obj)
100 {
101 GtkCombo *cbo = GTK_COMBO(obj);
102 COMBO(obj)->chosen_index = 0;
103 COMBO(obj)->next_chosen_index = -1;
104 COMBO(obj)->max_request_width = -1;
105 gtk_editable_set_editable(GTK_EDITABLE(cbo->entry),FALSE);
106 gtk_signal_connect(GTK_OBJECT(cbo->list),"select_child",list_select_child,
107 obj);
108 gtk_signal_connect(GTK_OBJECT(cbo->list),"motion-notify-event",
109 GTK_SIGNAL_FUNC(list_motion_notify),obj);
110 gtk_signal_connect_after(GTK_OBJECT(GTK_COMBO(cbo)->popwin),"hide",
111 GTK_SIGNAL_FUNC(hide_popup),cbo);
112 }
113
combo_set_items(Combo * combo,GList * item_strings,int default_index)114 void combo_set_items(Combo *combo, GList *item_strings, int default_index)
115 {
116 updating_flag = TRUE;
117 gtk_combo_set_popdown_strings(GTK_COMBO(combo),item_strings);
118 if (default_index < g_list_length(item_strings) && default_index >= 0) {
119 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry),
120 (gchar *)g_list_nth_data(item_strings,
121 default_index));
122 combo->chosen_index = default_index;
123 } else
124 combo->chosen_index = 0;
125 updating_flag = FALSE;
126 gtk_signal_emit(GTK_OBJECT(combo),combo_signals[CHANGED_SIGNAL]);
127 }
128
combo_set_selection(Combo * combo,int item_index)129 void combo_set_selection(Combo *combo, int item_index)
130 {
131 gtk_list_select_item(GTK_LIST(GTK_COMBO(combo)->list),item_index);
132 }
133
combo_selected_index(Combo * combo)134 int combo_selected_index(Combo *combo)
135 {
136 return combo->chosen_index;
137 }
138
combo_selected_string(Combo * combo)139 char *combo_selected_string(Combo *combo)
140 {
141 return g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry)));
142 }
143
combo_remove_item(Combo * combo,int item_index)144 void combo_remove_item(Combo *combo, int item_index)
145 {
146 g_assert(item_index != combo->chosen_index);
147 gtk_list_clear_items(GTK_LIST(GTK_COMBO(combo)->list),item_index,
148 item_index+1);
149 if (item_index < combo->chosen_index) combo->chosen_index--;
150 }
151
152 #else
153
154
155
combo_destroy(GtkObject * obj)156 static void combo_destroy(GtkObject *obj)
157 {
158 Combo *combo = COMBO(obj);
159 if (combo->strings) {
160 g_list_foreach(combo->strings, (GFunc)g_free, NULL);
161 g_list_free(combo->strings);
162 combo->strings = NULL;
163 }
164 parent_class->destroy(obj);
165 }
166
combo_changed(GtkComboBox * combo)167 static void combo_changed(GtkComboBox *combo)
168 {
169 if (!updating_flag)
170 gtk_signal_emit(GTK_OBJECT(combo),combo_signals[CHANGED_SIGNAL]);
171 if (GTK_COMBO_BOX_CLASS(parent_class)->changed)
172 GTK_COMBO_BOX_CLASS(parent_class)->changed(combo);
173 }
174
combo_class_init(GtkObjectClass * klass)175 static void combo_class_init(GtkObjectClass *klass)
176 {
177 parent_class = gtk_type_class(COMBO_PARENT_TYPE_FUNC());
178 klass->destroy = combo_destroy;
179 GTK_COMBO_BOX_CLASS(klass)->changed = combo_changed;
180 COMBO_CLASS(klass)->selection_changed = NULL;
181 GTK_WIDGET_CLASS(klass)->size_request = combo_size_request;
182 combo_signals[CHANGED_SIGNAL] =
183 gtk_signal_new("selection_changed",GTK_RUN_LAST,
184 GTK_CLASS_TYPE(klass),
185 GTK_SIGNAL_OFFSET(ComboClass,selection_changed),
186 gtk_marshal_NONE__NONE,GTK_TYPE_NONE,0);
187 gtk_object_class_add_signals(klass,combo_signals,LAST_SIGNAL);
188 }
189
190
combo_init(GtkObject * obj)191 static void combo_init(GtkObject *obj)
192 {
193 /* Most of this was taken from the code for gtk_combo_box_new_text in
194 * GTK+ 2.4.13 */
195 GtkWidget *combo_box = GTK_WIDGET(obj);
196 GtkCellRenderer *cell;
197 GtkListStore *store;
198
199 store = gtk_list_store_new (1, G_TYPE_STRING);
200 gtk_combo_box_set_model (GTK_COMBO_BOX(combo_box),GTK_TREE_MODEL (store));
201 g_object_unref (store);
202
203 cell = gtk_cell_renderer_text_new ();
204 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
205 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
206 "text", 0,
207 NULL);
208
209 COMBO(obj)->strings = NULL;
210 COMBO(obj)->max_request_width = -1;
211 }
212
combo_set_items(Combo * combo,GList * item_strings,int default_index)213 void combo_set_items(Combo *combo, GList *item_strings, int default_index)
214 {
215 GList *l;
216 gchar *c;
217 int len;
218 updating_flag = TRUE;
219 for (l=combo->strings; l!=NULL; l=l->next) {
220 g_free(l->data);
221 gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),0);
222 }
223 g_list_free(combo->strings);
224 combo->strings = NULL;
225 for (l=item_strings,len=0; l!=NULL; l=l->next,len++) {
226 c = (gchar *)l->data;
227 gtk_combo_box_append_text(GTK_COMBO_BOX(combo),c);
228 combo->strings = g_list_append(combo->strings,g_strdup(c));
229 }
230 if (default_index >= len || default_index < 0) default_index = 0;
231 gtk_combo_box_set_active(GTK_COMBO_BOX(combo),default_index);
232 updating_flag = FALSE;
233 gtk_signal_emit(GTK_OBJECT(combo),combo_signals[CHANGED_SIGNAL]);
234 }
235
combo_set_selection(Combo * combo,int item_index)236 void combo_set_selection(Combo *combo, int item_index)
237 {
238 gtk_combo_box_set_active(GTK_COMBO_BOX(combo),item_index);
239 }
240
combo_selected_index(Combo * combo)241 int combo_selected_index(Combo *combo)
242 {
243 return gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
244 }
245
combo_selected_string(Combo * combo)246 char *combo_selected_string(Combo *combo)
247 {
248 int i;
249 char *c;
250 i = combo_selected_index(combo);
251 /* j = g_list_length(combo->strings);
252 printf("combo_selected_string: i=%d, len=%d\n",i,j); */
253 c = g_strdup(g_list_nth_data(combo->strings,i));
254 /* printf(" c=%s\n",c); */
255 return c;
256 }
257
combo_remove_item(Combo * combo,int item_index)258 void combo_remove_item(Combo *combo, int item_index)
259 {
260 int i;
261 gchar *c;
262 i = combo_selected_index(combo);
263 g_assert(i != item_index);
264 gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),item_index);
265 c = (gchar *)g_list_nth_data(combo->strings,item_index);
266 /* printf("Removing: selected_index %d, string %s\n",i,c); */
267 combo->strings = g_list_remove(combo->strings,c);
268 g_free(c);
269 }
270
271 #endif
272
273
274
275
276
combo_get_type(void)277 GtkType combo_get_type(void)
278 {
279 static GtkType id = 0;
280 if (!id) {
281 GtkTypeInfo info = {
282 "Combo",
283 sizeof(Combo),
284 sizeof(ComboClass),
285 (GtkClassInitFunc)combo_class_init,
286 (GtkObjectInitFunc)combo_init
287 };
288 id = gtk_type_unique(COMBO_PARENT_TYPE_FUNC(),&info);
289 }
290 return id;
291 }
292
combo_new(void)293 GtkWidget *combo_new(void)
294 {
295 return (GtkWidget *)gtk_type_new(combo_get_type());
296 }
297
combo_set_max_request_width(Combo * c,int width)298 void combo_set_max_request_width(Combo *c, int width)
299 {
300 c->max_request_width = width;
301 }
302