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