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