1 /*
2  * Copyright (C) 2002 2003 2004 2005 2006 2008 2011 2012, 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 <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <gtk/gtk.h>
29 #include "um.h"
30 #include "main.h"
31 #include "mainloop.h"
32 #include "gettext.h"
33 
34 gboolean um_use_gtk = FALSE;
35 
36 int user_message_flag=0;
37 static int modal_result;
38 static const int mr_yes=MR_YES,mr_no=MR_NO,mr_cancel=MR_CANCEL,mr_ok=MR_OK;
39 
modal_callback(GtkWidget * widget,gpointer data)40 static void modal_callback(GtkWidget *widget, gpointer data)
41 {
42      modal_result=*((int *)data);
43 }
44 
45 /* Output each line of msg with "mhWaveEdit: " in front of it. */
console_message(const char * msg)46 void console_message(const char *msg)
47 {
48      char *b,*c,*d;
49      b = c = g_strdup(msg);
50      while (1) {
51 	  fputs(_("mhWaveEdit: "),stderr);
52 	  d = strchr(c,'\n');
53 	  if (d != NULL) *d = 0;
54 	  fputs(c,stderr);
55 	  fputs("\n",stderr);
56 	  if (d != NULL) c = d+1;
57 	  else break;
58      }
59      g_free(b);
60 }
61 
console_perror(const char * msg)62 void console_perror(const char *msg)
63 {
64      fprintf(stderr,_("mhWaveEdit: %s: %s\n"),msg,strerror(errno));
65 }
66 
user_perror(const char * msg)67 void user_perror(const char *msg){
68      char *d;
69      d = g_strdup_printf("%s: %s",msg,strerror(errno));
70      user_error(d);
71      g_free(d);
72 }
73 
74 #if GTK_MAJOR_VERSION == 1
75 
76 static GtkWidget *wnd = NULL;
77 
window_destroy(GtkWidget * widget,gpointer user_data)78 static void window_destroy(GtkWidget *widget, gpointer user_data)
79 {
80      wnd = NULL;
81      // puts("window_destroy!");
82 }
83 
do_user_message(char * msg,int type,gboolean block)84 int do_user_message(char *msg, int type, gboolean block)
85 {
86      GtkWidget *l,*b;
87      /* If we're called recursively with UM_OK it's probably some kind of error
88       * message so spit it out to stderr... */
89      if (!um_use_gtk || (user_message_flag && type==UM_OK)) {
90 	  g_assert(type == UM_OK);
91 	  console_message(msg);
92 	  return MR_OK;
93      }
94      g_assert(!user_message_flag);
95      g_assert(block || type==UM_OK);
96      wnd=gtk_dialog_new();
97      gtk_window_set_title(GTK_WINDOW(wnd),_("Message"));
98      gtk_window_set_modal(GTK_WINDOW(wnd),TRUE);
99      gtk_window_set_position(GTK_WINDOW(wnd),GTK_WIN_POS_CENTER);
100      /*gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(wnd)->vbox),10);*/
101      gtk_container_set_border_width(GTK_CONTAINER(wnd),10);
102      if (block) gtk_signal_connect(GTK_OBJECT(wnd),"destroy",GTK_SIGNAL_FUNC(window_destroy),NULL);
103      l = gtk_label_new(msg);
104      gtk_label_set_line_wrap(GTK_LABEL(l),TRUE);
105      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->vbox),l,TRUE,FALSE,8);
106      gtk_widget_show(l);
107      switch (type) {
108      case UM_OK:
109 	  b=gtk_button_new_with_label(_("OK"));
110 	  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->action_area),b,FALSE,FALSE,0);
111 	  if (block) gtk_signal_connect(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(modal_callback),(gpointer)&mr_ok);
112 	  gtk_signal_connect_object(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(wnd));
113 	  gtk_widget_show(b);
114 	  modal_result=MR_OK;
115 	  break;
116      case UM_YESNOCANCEL:
117 	  b=gtk_button_new_with_label(_("Yes"));
118 	  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->action_area),b,
119 			     FALSE,FALSE,0);
120 	  gtk_signal_connect(GTK_OBJECT(b),"clicked",
121 			     GTK_SIGNAL_FUNC(modal_callback),
122 			     (gpointer)&mr_yes);
123 	  gtk_signal_connect_object(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(wnd));
124 	  gtk_widget_show(b);
125 	  b=gtk_button_new_with_label(_("No"));
126 	  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->action_area),b,
127 			     FALSE,FALSE,0);
128 	  gtk_signal_connect(GTK_OBJECT(b),"clicked",
129 			     GTK_SIGNAL_FUNC(modal_callback),
130 			     (gpointer)&mr_no);
131 	  gtk_signal_connect_object(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(wnd));
132 	  gtk_widget_show(b);
133 	  b=gtk_button_new_with_label(_("Cancel"));
134 	  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->action_area),b,
135 			     FALSE,FALSE,0);
136 	  gtk_signal_connect(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(modal_callback),(gpointer)&mr_cancel);
137 	  gtk_signal_connect_object(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(wnd));
138 	  gtk_widget_show(b);
139 	  modal_result=MR_CANCEL;
140 	  break;
141      case UM_OKCANCEL:
142 	  b=gtk_button_new_with_label(_("OK"));
143 	  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->action_area),b,
144 			     FALSE,FALSE,0);
145 	  gtk_signal_connect(GTK_OBJECT(b),"clicked",
146 			     GTK_SIGNAL_FUNC(modal_callback),
147 			     (gpointer)&mr_ok);
148 	  gtk_signal_connect_object(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(wnd));
149 	  gtk_widget_show(b);
150 	  b=gtk_button_new_with_label(_("Cancel"));
151 	  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(wnd)->action_area),b,
152 			     FALSE,FALSE,0);
153 	  gtk_signal_connect(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(modal_callback),(gpointer)&mr_cancel);
154 	  gtk_signal_connect_object(GTK_OBJECT(b),"clicked",GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(wnd));
155 	  gtk_widget_show(b);
156 	  modal_result=MR_CANCEL;
157 	  break;
158      }
159      gtk_widget_show(wnd);
160      if (block) {
161 	  user_message_flag++;
162 	  while (wnd)
163 	       mainloop();
164 	  user_message_flag--;
165 	  // puts("Out!");
166 	  return modal_result;
167      } else return MR_OK;
168 }
169 
user_message(char * msg,int type)170 int user_message(char *msg, int type)
171 {
172      return do_user_message(msg,type,TRUE);
173 }
174 
user_info(char * msg)175 void user_info(char *msg)
176 {
177      user_message(msg,UM_OK);
178 }
179 
user_error(char * msg)180 void user_error(char *msg)
181 {
182      user_message(msg,UM_OK);
183 }
184 
popup_error(char * msg)185 void popup_error(char *msg)
186 {
187      do_user_message(msg,UM_OK,FALSE);
188 }
189 
user_warning(char * msg)190 void user_warning(char *msg)
191 {
192      user_message(msg,UM_OK);
193 }
194 
195 #else
196 
197 static gboolean responded = FALSE;
198 static gint r;
199 
response(GtkDialog * dialog,gint arg1,gpointer user_data)200 static void response(GtkDialog *dialog, gint arg1, gpointer user_data)
201 {
202      responded = TRUE;
203      r = arg1;
204 }
205 
nonblock_response(GtkDialog * dialog,gint arg1,gpointer user_data)206 static void nonblock_response(GtkDialog *dialog, gint arg1, gpointer user_data)
207 {
208      if (arg1 != GTK_RESPONSE_DELETE_EVENT)
209 	  gtk_widget_destroy(GTK_WIDGET(dialog));
210 }
211 
showdlg(GtkMessageType mt,GtkButtonsType bt,char * msg,gboolean block)212 static int showdlg(GtkMessageType mt, GtkButtonsType bt, char *msg,
213 		   gboolean block)
214 {
215      GtkWidget *w;
216      g_assert(block || bt == GTK_BUTTONS_OK);
217      if (!um_use_gtk) {
218 	  g_assert(bt == GTK_BUTTONS_OK);
219 	  console_message(msg);
220 	  return MR_OK;
221      }
222      w = gtk_message_dialog_new(NULL,GTK_DIALOG_MODAL,mt,bt,"%s",msg);
223      if (bt == GTK_BUTTONS_NONE)
224 	  gtk_dialog_add_buttons(GTK_DIALOG(w),GTK_STOCK_YES,GTK_RESPONSE_YES,
225 				 GTK_STOCK_NO,GTK_RESPONSE_NO,GTK_STOCK_CANCEL,
226 				 GTK_RESPONSE_CANCEL,NULL);
227      if (block) {
228 	  gtk_signal_connect(GTK_OBJECT(w),"response",
229 			     GTK_SIGNAL_FUNC(response),NULL);
230 	  responded = FALSE;
231      } else
232 	  gtk_signal_connect(GTK_OBJECT(w),"response",
233 			     GTK_SIGNAL_FUNC(nonblock_response),NULL);
234      gtk_window_set_position(GTK_WINDOW(w),GTK_WIN_POS_CENTER);
235      gtk_widget_show(w);
236      if (block)
237 	  while (!responded)
238 	       mainloop();
239      else
240 	  return MR_OK;
241      if (r != GTK_RESPONSE_DELETE_EVENT) gtk_widget_destroy(w);
242      if (r == GTK_RESPONSE_OK) return MR_OK;
243      if (r == GTK_RESPONSE_CANCEL) return MR_CANCEL;
244      if (r == GTK_RESPONSE_YES) return MR_YES;
245      if (r == GTK_RESPONSE_NO) return MR_NO;
246      if (bt == GTK_BUTTONS_OK) return MR_OK;
247      return MR_CANCEL;
248 }
249 
user_message(char * msg,int type)250 int user_message(char *msg, int type)
251 {
252      if (type == UM_YESNOCANCEL)
253 	  return showdlg(GTK_MESSAGE_QUESTION,GTK_BUTTONS_NONE,msg,TRUE);
254      if (type == UM_OKCANCEL)
255 	  return showdlg(GTK_MESSAGE_WARNING,GTK_BUTTONS_OK_CANCEL,msg,TRUE);
256      return showdlg(GTK_MESSAGE_INFO,GTK_BUTTONS_OK,msg,TRUE);
257 }
258 
user_info(char * msg)259 void user_info(char *msg)
260 {
261      showdlg(GTK_MESSAGE_INFO,GTK_BUTTONS_OK,msg,TRUE);
262 }
263 
user_error(char * msg)264 void user_error(char *msg)
265 {
266      showdlg(GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,msg,TRUE);
267 }
268 
popup_error(char * msg)269 void popup_error(char *msg)
270 {
271      showdlg(GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,msg,FALSE);
272 }
273 
user_warning(char * msg)274 void user_warning(char *msg)
275 {
276      showdlg(GTK_MESSAGE_WARNING,GTK_BUTTONS_OK,msg,TRUE);
277 }
278 
279 
280 #endif
281 
282 struct user_input_data {
283      gboolean (*validator)(gchar *c);
284      GtkWidget *entry,*window;
285      gchar *result;
286 };
287 
288 static gboolean user_input_quitflag;
289 
user_input_destroy(void)290 static void user_input_destroy(void)
291 {
292      user_input_quitflag=TRUE;
293 }
294 
user_input_ok(GtkButton * button,gpointer user_data)295 static void user_input_ok(GtkButton *button, gpointer user_data)
296 {
297      gchar *c;
298      struct user_input_data *uid = user_data;
299      c = (gchar *)gtk_entry_get_text(GTK_ENTRY(uid->entry));
300      if (uid->validator(c)) {
301 	  uid->result = g_strdup(c);
302 	  modal_result = MR_OK;
303 	  gtk_widget_destroy(uid->window);
304      }
305 }
306 
user_input(gchar * label,gchar * title,gchar * defvalue,gboolean (* validator)(gchar * c),GtkWindow * below)307 gchar *user_input(gchar *label, gchar *title, gchar *defvalue,
308 		  gboolean (*validator)(gchar *c), GtkWindow *below)
309 {
310      GtkWidget *a,*b,*c,*d,*ent;
311      struct user_input_data uid;
312      a = gtk_window_new(GTK_WINDOW_DIALOG);
313      if (below != NULL) {
314 	  gtk_window_set_transient_for(GTK_WINDOW(a),below);
315 	  gtk_window_set_position(GTK_WINDOW(a),GTK_WIN_POS_CENTER_ON_PARENT);
316      } else
317 	  gtk_window_set_position(GTK_WINDOW(a),GTK_WIN_POS_CENTER);
318      gtk_window_set_title(GTK_WINDOW(a),title?title:_("Input"));
319      gtk_window_set_modal(GTK_WINDOW(a),TRUE);
320      gtk_container_set_border_width(GTK_CONTAINER(a),5);
321      gtk_signal_connect(GTK_OBJECT(a),"destroy",
322 			GTK_SIGNAL_FUNC(user_input_destroy),NULL);
323      b = gtk_vbox_new(FALSE,3);
324      gtk_container_add(GTK_CONTAINER(a),b);
325      c = gtk_hbox_new(FALSE,2);
326      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
327      if (label) {
328 	  d = gtk_label_new(label);
329 	  gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
330      }
331      ent = gtk_entry_new();
332      gtk_entry_set_text(GTK_ENTRY(ent),defvalue);
333 #if GTK_MAJOR_VERSION > 1
334      gtk_entry_set_activates_default(GTK_ENTRY(ent),TRUE);
335 #endif
336      gtk_box_pack_start(GTK_BOX(b),ent,FALSE,FALSE,0);
337      c = gtk_hseparator_new();
338      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,3);
339      c = gtk_hbutton_box_new();
340      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
341      d = gtk_button_new_with_label(_("OK"));
342      gtk_signal_connect(GTK_OBJECT(d),"clicked",
343 			GTK_SIGNAL_FUNC(user_input_ok),&uid);
344      gtk_container_add(GTK_CONTAINER(c),d);
345      GTK_WIDGET_SET_FLAGS(d,GTK_CAN_DEFAULT);
346      gtk_widget_grab_default(d);
347      d = gtk_button_new_with_label(_("Cancel"));
348      gtk_signal_connect(GTK_OBJECT(d),"clicked",GTK_SIGNAL_FUNC(modal_callback),
349 			(gpointer)&mr_cancel);
350      gtk_signal_connect_object(GTK_OBJECT(d),"clicked",
351 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
352 			       GTK_OBJECT(a));
353      gtk_container_add(GTK_CONTAINER(c),d);
354      gtk_widget_show_all(a);
355      uid.window = a;
356      uid.validator = validator;
357      uid.entry = ent;
358      modal_result = MR_CANCEL;
359      user_input_quitflag = FALSE;
360      while (!user_input_quitflag)
361 	  mainloop();
362      if (modal_result == MR_CANCEL) return NULL;
363      else return uid.result;
364 }
365 
user_input_float_validator(gchar * c)366 static gboolean user_input_float_validator(gchar *c)
367 {
368      gchar *d;
369      errno = 0;
370      strtod(c,&d);
371      return (errno == 0 && *d == 0);
372 }
373 
user_input_float(gchar * label,gchar * title,gfloat defvalue,GtkWindow * below,gfloat * result)374 gboolean user_input_float(gchar *label, gchar *title, gfloat defvalue,
375 			  GtkWindow *below, gfloat *result)
376 {
377      gchar *c,d[128],*e;
378      format_float(defvalue, d, sizeof(d));
379      c = user_input(label,title,d,user_input_float_validator,below);
380      if (!c) return TRUE;
381      *result = (gfloat)strtod(c,&e);
382      g_assert(*e == 0);
383      g_free(c);
384      return FALSE;
385 }
386 
387 static gpointer user_choice_choice;
388 
echo_func(GtkWidget * widget,GdkEvent * event,gpointer user_data)389 static gboolean echo_func(GtkWidget *widget, GdkEvent *event, gpointer user_data)
390 {
391      return *((int *)user_data) == MR_OK;
392 }
393 
user_choice_select_child(GtkList * list,GtkWidget * widget,gpointer user_data)394 static void user_choice_select_child(GtkList *list, GtkWidget *widget,
395 				     gpointer user_data)
396 {
397      user_choice_choice = gtk_object_get_data(GTK_OBJECT(widget),"choice");
398 }
399 
user_choice(gchar ** choices,guint def,gchar * windowtitle,gchar * windowtext,gboolean allow_cancel)400 gint user_choice(gchar **choices, guint def, gchar *windowtitle,
401 		 gchar *windowtext, gboolean allow_cancel)
402 {
403      GtkWidget *a,*b,*c,*d,*list=NULL,*w;
404      guint i;
405      a = gtk_window_new(GTK_WINDOW_DIALOG);
406      gtk_window_set_modal(GTK_WINDOW(a),TRUE);
407      gtk_window_set_title(GTK_WINDOW(a), windowtitle?windowtitle:_("Choice"));
408      gtk_container_set_border_width(GTK_CONTAINER(a),5);
409      if (allow_cancel)
410 	  gtk_signal_connect(GTK_OBJECT(a),"delete_event",
411 			     GTK_SIGNAL_FUNC(echo_func),(gpointer)&mr_cancel);
412      else
413 	  gtk_signal_connect(GTK_OBJECT(a),"delete_event",
414 			     GTK_SIGNAL_FUNC(echo_func),(gpointer)&mr_ok);
415      gtk_signal_connect(GTK_OBJECT(a),"destroy",
416 			GTK_SIGNAL_FUNC(user_input_destroy),NULL);
417      b = gtk_vbox_new(FALSE,5);
418      gtk_container_add(GTK_CONTAINER(a),b);
419      if (windowtext) {
420 	  c = gtk_label_new(windowtext);
421 	  gtk_label_set_line_wrap(GTK_LABEL(c),TRUE);
422 	  gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
423 	  c = gtk_hseparator_new();
424 	  gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
425      }
426      c = gtk_scrolled_window_new(NULL,NULL);
427      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c),
428 				    GTK_POLICY_NEVER,
429 				    GTK_POLICY_AUTOMATIC);
430      gtk_widget_set_usize(GTK_WIDGET(c),-1,300);
431      gtk_box_pack_start(GTK_BOX(b),c,TRUE,TRUE,0);
432      d = list = gtk_list_new();
433      gtk_list_set_selection_mode(GTK_LIST(list),GTK_SELECTION_SINGLE);
434      for (i=0; choices[i]!=NULL; i++) {
435 	  w = gtk_list_item_new_with_label(choices[i]);
436 	  gtk_object_set_data(GTK_OBJECT(w),"choice",choices+i);
437 	  gtk_container_add(GTK_CONTAINER(list),w);
438 	  if (i == def) gtk_list_select_child(GTK_LIST(list),w);
439      }
440      gtk_signal_connect(GTK_OBJECT(list),"select_child",
441 			(GtkSignalFunc)user_choice_select_child,NULL);
442      gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(c),d);
443      c = gtk_hseparator_new();
444      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
445 
446      c = gtk_hbutton_box_new();
447      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
448 
449      d = gtk_button_new_with_label(_("OK"));
450      gtk_signal_connect(GTK_OBJECT(d),"clicked",GTK_SIGNAL_FUNC(modal_callback),
451 			(gpointer)&mr_ok);
452      gtk_signal_connect_object(GTK_OBJECT(d),"clicked",
453 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
454 			       GTK_OBJECT(a));
455      gtk_container_add(GTK_CONTAINER(c),d);
456 
457      if (allow_cancel) {
458 	  d = gtk_button_new_with_label(_("Cancel"));
459 	  gtk_signal_connect(GTK_OBJECT(d),"clicked",
460 			     GTK_SIGNAL_FUNC(modal_callback),
461 			     (gpointer)&mr_cancel);
462 	  gtk_signal_connect_object(GTK_OBJECT(d),"clicked",
463 				    GTK_SIGNAL_FUNC(gtk_widget_destroy),
464 				    GTK_OBJECT(a));
465 	  gtk_container_add(GTK_CONTAINER(c),d);
466      }
467 
468      user_choice_choice = choices+def;
469      modal_result = MR_CANCEL;
470      gtk_widget_show_all(a);
471 
472      user_input_quitflag = FALSE;
473      while (!user_input_quitflag)
474 	  mainloop();
475 
476      g_assert(modal_result==MR_OK || allow_cancel);
477 
478      if (modal_result==MR_CANCEL) return -1;
479      else return (guint) (((gchar **)user_choice_choice)-choices);
480 }
481 
482