1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  *
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.
10  *
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.
15  *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <glib.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtk.h>
30 
31 #include <sweep/sweep_i18n.h>
32 #include <sweep/sweep_undo.h>
33 #include <sweep/sweep_sample.h>
34 #include <sweep/sweep_sounddata.h>
35 #include <sweep/sweep_selection.h>
36 
37 #include "sweep_app.h"
38 #include "edit.h"
39 #include "interface.h"
40 #include "callbacks.h"
41 
42 #include "../pixmaps/undo.xpm"
43 #include "../pixmaps/redo.xpm"
44 #include "../pixmaps/done.xpm"
45 
46 /*#define DEBUG*/
47 
48 static GtkWidget * undo_dialog = NULL;
49 static GtkWidget * undo_clist = NULL;
50 static GtkWidget * combo;
51 static GtkWidget * undo_button, * redo_button, * revert_button;
52 static sw_sample * ud_sample = NULL;
53 
54 static void
undo_dialog_destroy(void)55 undo_dialog_destroy (void)
56 {
57   undo_dialog = NULL;
58 }
59 
60 #if 0
61 static void
62 undo_dialog_ok_cb (GtkWidget * widget, gpointer data)
63 {
64   GtkWidget * dialog;
65 
66   dialog = gtk_widget_get_toplevel (widget);
67   gtk_widget_hide (dialog);
68 }
69 #endif
70 
71 static void
undo_dialog_cancel_cb(GtkWidget * widget,gpointer data)72 undo_dialog_cancel_cb (GtkWidget * widget, gpointer data)
73 {
74   GtkWidget * dialog;
75 
76   dialog = gtk_widget_get_toplevel (widget);
77   gtk_widget_hide (dialog);
78 }
79 
80 /*
81  * Must be called with sample->edit_mutex held
82  */
83 void
undo_dialog_refresh_edit_mode(sw_sample * sample)84 undo_dialog_refresh_edit_mode (sw_sample * sample)
85 {
86   if (sample != ud_sample) return;
87 
88   if (undo_dialog == NULL) return;
89 
90   switch (sample->edit_mode) {
91   case SWEEP_EDIT_MODE_READY:
92     gtk_widget_set_sensitive (undo_button, TRUE);
93     gtk_widget_set_sensitive (redo_button, TRUE);
94     gtk_widget_set_sensitive (undo_clist, TRUE);
95     gtk_widget_set_sensitive (revert_button, TRUE);
96     break;
97   case SWEEP_EDIT_MODE_META:
98   case SWEEP_EDIT_MODE_FILTER:
99     gtk_widget_set_sensitive (undo_button, FALSE);
100     gtk_widget_set_sensitive (redo_button, FALSE);
101     gtk_widget_set_sensitive (undo_clist, FALSE);
102     gtk_widget_set_sensitive (revert_button, FALSE);
103     break;
104   case SWEEP_EDIT_MODE_ALLOC:
105     gtk_widget_set_sensitive (undo_button, FALSE);
106     gtk_widget_set_sensitive (redo_button, FALSE);
107     gtk_widget_set_sensitive (undo_clist, FALSE);
108     gtk_widget_set_sensitive (revert_button, FALSE);
109     break;
110   default:
111     g_assert_not_reached ();
112   }
113 }
114 
115 static void
_undo_dialog_set_sample(sw_sample * sample,gboolean select_current)116 _undo_dialog_set_sample (sw_sample * sample, gboolean select_current)
117 {
118   GtkCList * clist;
119   GList * gl;
120   sw_op_instance * inst;
121   gint i = 0;
122   gchar * list_item[] = { "" };
123   GdkColormap * colormap;
124   GdkPixmap * pixmap_data;
125   GdkBitmap * mask;
126   gboolean done = FALSE;
127 
128   g_mutex_lock (sample->ops_mutex);
129 
130   clist = GTK_CLIST(undo_clist);
131 
132   colormap = gtk_widget_get_default_colormap ();
133   pixmap_data =
134     gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask,
135 					     NULL, done_xpm);
136   gtk_clist_freeze (clist);
137 
138   gtk_clist_clear (clist);
139 
140   for (gl = g_list_last (sample->registered_ops); gl; gl = gl->prev) {
141     inst = (sw_op_instance *)gl->data;
142 
143     gtk_clist_append (clist, list_item);
144     gtk_clist_set_text (clist, i, 1, _(inst->description));
145 
146     if (gl == sample->current_undo) {
147       done = TRUE;
148       gtk_clist_moveto (clist, i, 0, 0.5, -1);
149       if (select_current) gtk_clist_select_row (clist, i, 1);
150     }
151 
152     if (done)
153       gtk_clist_set_pixmap (clist, i, 0, pixmap_data, mask);
154 
155     i++;
156   }
157 
158   gtk_clist_append (clist, list_item);
159   gtk_clist_set_text (clist, i, 1, _("Original data"));
160   gtk_clist_set_pixmap (clist, i, 0, pixmap_data, mask);
161 
162   if (sample->current_undo == NULL) {
163     gtk_clist_moveto (clist, i, 0, 0.5, -1);
164     if (select_current) gtk_clist_select_row (clist, i, 1);
165   }
166 
167   gtk_clist_thaw (clist);
168 
169   g_mutex_unlock (sample->ops_mutex);
170 
171   ud_sample = sample;
172   gtk_entry_set_text (GTK_ENTRY(GTK_COMBO(combo)->entry),
173 		      g_basename(sample->pathname));
174 
175   g_mutex_lock (ud_sample->edit_mutex);
176   undo_dialog_refresh_edit_mode (ud_sample);
177   g_mutex_unlock (ud_sample->edit_mutex);
178 }
179 
180 void
undo_dialog_set_sample(sw_sample * sample)181 undo_dialog_set_sample (sw_sample * sample)
182 {
183   if (sample == NULL) return;
184 
185   if (undo_dialog == NULL || !GTK_WIDGET_VISIBLE(undo_dialog))
186     return;
187 
188   _undo_dialog_set_sample (sample, (sample != ud_sample));
189 }
190 
191 void
undo_dialog_refresh_history(sw_sample * sample)192 undo_dialog_refresh_history (sw_sample * sample)
193 {
194   if (sample != ud_sample)
195     return;
196 
197   if (undo_dialog == NULL || !GTK_WIDGET_VISIBLE(undo_dialog))
198     return;
199 
200   _undo_dialog_set_sample (sample, FALSE);
201 }
202 
203 void
undo_dialog_refresh_sample_list(void)204 undo_dialog_refresh_sample_list (void)
205 {
206   GList * cbitems = NULL;
207 
208   if (undo_dialog == NULL)
209     return;
210 
211   if ((cbitems = sample_bank_list_names ()) != NULL)
212     gtk_combo_set_popdown_strings (GTK_COMBO(combo), cbitems);
213 
214   g_list_free (cbitems);
215 }
216 
217 static void
undo_dialog_entry_changed_cb(GtkWidget * widget,gpointer data)218 undo_dialog_entry_changed_cb (GtkWidget * widget, gpointer data)
219 {
220   GtkEntry * entry;
221   gchar * new_text;
222   sw_sample * sample;
223 
224   entry = GTK_ENTRY(GTK_COMBO(combo)->entry);
225   new_text = (gchar *)gtk_entry_get_text (entry);
226 
227   sample = sample_bank_find_byname (new_text);
228 
229   if (sample == NULL) return;
230 
231   gtk_signal_handler_block_by_data (GTK_OBJECT(entry), NULL);
232   _undo_dialog_set_sample (sample, TRUE);
233   gtk_signal_handler_unblock_by_data (GTK_OBJECT(entry), NULL);
234 }
235 
236 static void
undo_dialog_revert_cb(GtkWidget * widget,gpointer data)237 undo_dialog_revert_cb (GtkWidget * widget, gpointer data)
238 {
239   GList * gl, * sel_gl = NULL;
240   /*  sw_op_instance * inst;*/
241   gint i = 0, s;
242   /*  gboolean need_undo = FALSE;*/
243 
244   s = GPOINTER_TO_INT((GTK_CLIST(undo_clist)->selection)->data);
245 
246   g_mutex_lock (ud_sample->ops_mutex);
247 
248   for (gl = g_list_last (ud_sample->registered_ops); gl; gl = gl->prev) {
249 #if 0
250     inst = (sw_op_instance *)gl->data;
251 
252     if (gl == ud_sample->current_undo) {
253       need_undo = TRUE;
254     }
255 #endif
256 
257     if (i == s) {
258       sel_gl = gl;
259       break;
260     }
261 
262     i++;
263   }
264 
265   g_mutex_unlock (ud_sample->ops_mutex);
266 
267 #if 0
268   if (need_undo) {
269     while (ud_sample->current_undo != sel_gl)
270       undo_current (ud_sample);
271   } else {
272     while (ud_sample->current_undo != sel_gl)
273       redo_current (ud_sample);
274   }
275 #endif
276 
277   revert_op (ud_sample, sel_gl);
278 }
279 
280 static void
ud_undo_cb(GtkWidget * widget,gpointer data)281 ud_undo_cb (GtkWidget * widget, gpointer data)
282 {
283   undo_current (ud_sample);
284 }
285 
286 static void
ud_redo_cb(GtkWidget * widget,gpointer data)287 ud_redo_cb (GtkWidget * widget, gpointer data)
288 {
289   redo_current (ud_sample);
290 }
291 
292 static GtkWidget *
ud_create_pixmap_button(GtkWidget * widget,gchar ** xpm_data,const gchar * label_text,const gchar * tip_text,GCallback clicked)293 ud_create_pixmap_button (GtkWidget * widget, gchar ** xpm_data,
294 			 const gchar * label_text, const gchar * tip_text,
295 			 GCallback clicked)
296 {
297   GtkWidget * hbox;
298   GtkWidget * label;
299   GtkWidget * pixmap;
300   GtkWidget * button;
301   GtkTooltips * tooltips;
302 
303   button = gtk_button_new ();
304 
305   hbox = gtk_hbox_new (FALSE, 2);
306   gtk_container_add (GTK_CONTAINER(button), hbox);
307   gtk_container_set_border_width (GTK_CONTAINER(button), 8);
308   gtk_widget_show (hbox);
309 
310   if (xpm_data != NULL) {
311     pixmap = create_widget_from_xpm (widget, xpm_data);
312     gtk_box_pack_start (GTK_BOX(hbox), pixmap, FALSE, FALSE, 8);
313     gtk_widget_show (pixmap);
314   }
315 
316   if (label_text != NULL) {
317     label = gtk_label_new (label_text);
318     gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 8);
319     gtk_widget_show (label);
320   }
321 
322   if (tip_text != NULL) {
323     tooltips = gtk_tooltips_new ();
324     gtk_tooltips_set_tip (tooltips, button, tip_text, NULL);
325   }
326 
327   if (clicked != NULL) {
328     g_signal_connect (G_OBJECT (button), "clicked",
329 			G_CALLBACK(clicked), NULL);
330   }
331 
332   return button;
333 }
334 
335 void
undo_dialog_create(sw_sample * sample)336 undo_dialog_create (sw_sample * sample)
337 {
338   GtkWidget * vbox;
339   GtkWidget * hbox /* , *button_hbox */;
340   GtkWidget * label;
341   /*  GtkWidget * ok_button;*/
342   GtkWidget * button;
343   GtkWidget * scrolled;
344   gchar * titles[] = { "", N_("Action") };
345   GClosure *gclosure;
346   GtkAccelGroup * accel_group;
347 
348   if (undo_dialog == NULL) {
349     undo_dialog = gtk_dialog_new ();
350     gtk_window_set_wmclass(GTK_WINDOW(undo_dialog), "undo_dialog", "Sweep");
351     gtk_window_set_title(GTK_WINDOW(undo_dialog), _("Sweep: History"));
352     gtk_window_set_resizable (GTK_WINDOW(undo_dialog), FALSE);
353     gtk_window_set_position (GTK_WINDOW(undo_dialog), GTK_WIN_POS_MOUSE);
354     gtk_container_set_border_width  (GTK_CONTAINER(undo_dialog), 8);
355 
356     accel_group = gtk_accel_group_new ();
357     gtk_window_add_accel_group (GTK_WINDOW(undo_dialog), accel_group);
358 
359     g_signal_connect (G_OBJECT(undo_dialog), "destroy",
360 		      G_CALLBACK(undo_dialog_destroy), NULL);
361 
362 
363    gclosure = g_cclosure_new  ((GCallback)hide_window_cb, NULL, NULL);
364    gtk_accel_group_connect (accel_group,
365                                              GDK_w,
366                                              GDK_CONTROL_MASK,
367                                              0, /* non of the GtkAccelFlags seem suitable? */
368                                              gclosure);
369 
370     vbox = GTK_DIALOG(undo_dialog)->vbox;
371 
372     hbox = gtk_hbox_new (FALSE, 8);
373     gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 8);
374     gtk_widget_show (hbox);
375 
376     label = gtk_label_new (_("File:"));
377     gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
378     gtk_widget_show (label);
379 
380     combo = gtk_combo_new ();
381     gtk_box_pack_start (GTK_BOX(hbox), combo, TRUE, TRUE, 0);
382     gtk_widget_show (combo);
383 
384     gtk_entry_set_editable (GTK_ENTRY(GTK_COMBO(combo)->entry), FALSE);
385 
386     g_signal_connect (G_OBJECT(GTK_COMBO(combo)->entry), "changed",
387 			G_CALLBACK(undo_dialog_entry_changed_cb), NULL);
388 
389     hbox = gtk_hbox_new (TRUE, 8);
390     gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
391     gtk_widget_show (hbox);
392 
393     button = ud_create_pixmap_button (undo_dialog, undo_xpm, _("Undo"), _("Undo"),
394 				   G_CALLBACK (ud_undo_cb));
395     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
396     gtk_widget_show (button);
397     gtk_widget_add_accelerator (button, "clicked", accel_group,
398 				GDK_z, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
399     undo_button = button;
400 
401     button = ud_create_pixmap_button (undo_dialog, redo_xpm, _("Redo"), _("Redo"),
402 				   G_CALLBACK (ud_redo_cb));
403     gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
404     gtk_widget_show (button);
405     gtk_widget_add_accelerator (button, "clicked", accel_group,
406 				GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
407     redo_button = button;
408 
409     scrolled = gtk_scrolled_window_new (NULL, NULL);
410     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled),
411 				    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
412     gtk_box_pack_start (GTK_BOX(GTK_DIALOG(undo_dialog)->vbox), scrolled,
413 			FALSE, FALSE, 0);
414     gtk_widget_set_usize (scrolled, 360, 240);
415     gtk_widget_show (scrolled);
416 
417     undo_clist = gtk_clist_new_with_titles (2, titles);
418     gtk_clist_set_column_width (GTK_CLIST(undo_clist), 0, 20);
419     gtk_clist_set_selection_mode (GTK_CLIST(undo_clist), GTK_SELECTION_BROWSE);
420     gtk_clist_column_titles_passive (GTK_CLIST(undo_clist));
421     /* set title actively for i18n */
422     gtk_clist_set_column_title(GTK_CLIST(undo_clist), 1, _(titles[1]));
423     gtk_container_add (GTK_CONTAINER(scrolled), undo_clist);
424     gtk_widget_show (undo_clist);
425 
426     button = gtk_button_new_with_label (_("Revert to selected state"));
427     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
428     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(undo_dialog)->action_area),
429 			button, TRUE, TRUE, 0);
430     gtk_widget_show (button);
431     g_signal_connect (G_OBJECT(button), "clicked",
432 			G_CALLBACK (undo_dialog_revert_cb),
433 			NULL);
434     revert_button = button;
435 
436 #if 0
437 
438     /* OK */
439 
440     ok_button = gtk_button_new_with_label (_("OK"));
441     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
442     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(undo_dialog)->action_area),
443 			ok_button, TRUE, TRUE, 0);
444     gtk_widget_show (ok_button);
445     g_signal_connect (G_OBJECT(ok_button), "clicked",
446 			G_CALLBACK (undo_dialog_ok_cb),
447 			NULL);
448 #endif
449 
450     /* Cancel */
451 
452     button = gtk_button_new_with_label (_("Close"));
453     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
454     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(undo_dialog)->action_area),
455 			button, FALSE, FALSE, 0);
456     gtk_widget_show (button);
457     g_signal_connect (G_OBJECT(button), "clicked",
458 			G_CALLBACK (undo_dialog_cancel_cb),
459 			NULL);
460 
461     gtk_widget_grab_default (button);
462 
463 #if 0
464     gtk_widget_grab_default (ok_button);
465 #endif
466 
467 
468   }
469 
470   undo_dialog_refresh_sample_list ();
471   _undo_dialog_set_sample (sample, TRUE);
472 
473   if (!GTK_WIDGET_VISIBLE(undo_dialog)) {
474     gtk_widget_show (undo_dialog);
475   } else {
476     gdk_window_raise (undo_dialog->window);
477   }
478 }
479