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