1 /*
2 * Copyright (C) 2003 2004 2007 2009 2011, 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 #include <gdk/gdkkeysyms.h>
24
25 #include <string.h>
26 #include "effectbrowser.h"
27 #include "volumedialog.h"
28 #include "speeddialog.h"
29 #include "sampleratedialog.h"
30 #include "samplesizedialog.h"
31 #include "combinechannelsdialog.h"
32 #include "pipedialog.h"
33 #include "inifile.h"
34 #include "documentlist.h"
35 #include "um.h"
36 #include "gettext.h"
37 #include "mapchannelsdialog.h"
38 #include "sandwichdialog.h"
39
40 struct source {
41 gchar tag;
42 gchar *name;
43 effect_register_rebuild_func rebuild_func;
44 effect_register_get_func get_func;
45 gpointer rebuild_func_data,get_func_data;
46 int is_new;
47 };
48
49 struct effect {
50 gchar *name,*title,*location,*author,source_tag;
51 gboolean process_tag;
52 };
53
54 static ListObject *effect_list = NULL;
55 static GSList *sources = NULL;
56
57 static GSList *geometry_stack = NULL;
58 static gboolean geometry_stack_inited = FALSE;
59
60 static GtkObjectClass *parent_class;
61
62 static void list_widget_rebuild(gpointer dummy, gpointer dummy2,
63 EffectBrowser *eb);
64
effect_register_add_source(gchar * name,gchar tag,effect_register_rebuild_func rebuild_func,gpointer rebuild_func_data,effect_register_get_func get_func,gpointer get_func_data)65 void effect_register_add_source(gchar *name, gchar tag,
66 effect_register_rebuild_func rebuild_func,
67 gpointer rebuild_func_data,
68 effect_register_get_func get_func,
69 gpointer get_func_data)
70 {
71 struct source *s;
72 s = g_malloc(sizeof(*s));
73 s->tag = tag;
74 s->name = name;
75 s->rebuild_func = rebuild_func;
76 s->rebuild_func_data = rebuild_func_data;
77 s->get_func = get_func;
78 s->get_func_data = get_func_data;
79 s->is_new = TRUE;
80 sources = g_slist_append(sources,s);
81 }
82
effect_register_add_effect(gchar source_tag,const gchar * name,const gchar * title,const gchar * author,const gchar * location)83 void effect_register_add_effect(gchar source_tag, const gchar *name,
84 const gchar *title, const gchar *author,
85 const gchar *location)
86 {
87 struct effect *e;
88 e = g_malloc(sizeof(*e));
89 e->source_tag = source_tag;
90 e->name = g_strdup(name);
91 e->title = g_strdup(title);
92 e->author = g_strdup(author);
93 e->location = g_strdup(location);
94 list_object_add(effect_list, e);
95 }
96
builtin_rebuild_func(gchar source_tag,gpointer user_data)97 static void builtin_rebuild_func(gchar source_tag, gpointer user_data)
98 {
99 gchar *author = _("Built-in");
100 static const gchar loc[] = "";
101
102 effect_register_add_effect(source_tag,"volume",_("Volume adjust/fade"),
103 author,loc);
104 effect_register_add_effect(source_tag,"srate",_("Convert samplerate"),
105 author,loc);
106 effect_register_add_effect(source_tag,"ssize",_("Convert sample format"),
107 author,loc);
108 effect_register_add_effect(source_tag,"mapchannels",_("Map channels"),
109 author,loc);
110 effect_register_add_effect(source_tag,"combine",_("Combine channels"),
111 author,loc);
112 effect_register_add_effect(source_tag,"sandwich",
113 _("Add channels from other file"),author,loc);
114 effect_register_add_effect(source_tag,"speed",_("Speed"),author,loc);
115 effect_register_add_effect(source_tag,"pipe",_("Pipe through program"),
116 author,loc);
117 }
118
builtin_get_func(gchar * name,gchar source_tag,gpointer user_data)119 static EffectDialog *builtin_get_func(gchar *name, gchar source_tag,
120 gpointer user_data)
121 {
122 GtkType type = -1;
123 if (!strcmp(name,"volume")) type = volume_dialog_get_type();
124 else if (!strcmp(name,"srate")) type = samplerate_dialog_get_type();
125 else if (!strcmp(name,"ssize")) type = samplesize_dialog_get_type();
126 else if (!strcmp(name,"mapchannels"))
127 type = map_channels_dialog_get_type();
128 else if (!strcmp(name,"combine"))
129 type = combine_channels_dialog_get_type();
130 else if (!strcmp(name,"speed")) type = speed_dialog_get_type();
131 else if (!strcmp(name,"pipe")) type = pipe_dialog_get_type();
132 else if (!strcmp(name,"sandwich")) type = sandwich_dialog_get_type();
133 if (type >= 0)
134 return EFFECT_DIALOG(gtk_type_new(type));
135 else
136 return NULL;
137 }
138
effect_register_init(void)139 void effect_register_init(void)
140 {
141 /* Add built-in effects source */
142 effect_register_add_source("Built-in",'B',builtin_rebuild_func,NULL,
143 builtin_get_func,NULL);
144 }
145
effect_register_update_list(void)146 static void effect_register_update_list(void)
147 {
148 GSList *s;
149 struct source *src;
150 gboolean b = FALSE;
151
152 if (effect_list == NULL)
153 effect_list = list_object_new(FALSE);
154
155 for (s=sources; s!=NULL; s=s->next) {
156 src = (struct source *)s->data;
157 if (src -> is_new) {
158 /* TODO: Cache instead of requesting from source each time */
159 src->rebuild_func(src->tag, src->rebuild_func_data);
160 src->is_new = FALSE;
161 b = TRUE;
162 }
163 }
164
165 if (b) list_object_notify(effect_list,NULL);
166 }
167
free_effect(struct effect * e)168 void free_effect(struct effect *e)
169 {
170 g_free(e->name);
171 g_free(e->title);
172 g_free(e->location);
173 g_free(e->author);
174 g_free(e);
175 }
176
effect_register_rebuild(void)177 void effect_register_rebuild(void)
178 {
179 GSList *s;
180 struct source *src;
181 list_object_foreach(effect_list,(GFunc)free_effect,NULL);
182 list_object_clear(effect_list,FALSE);
183 for (s=sources; s!=NULL; s=s->next) {
184 src = (struct source *)s->data;
185 src->is_new = TRUE;
186 }
187 effect_register_update_list();
188 }
189
effect_browser_remove_effect(EffectBrowser * eb)190 static void effect_browser_remove_effect(EffectBrowser *eb)
191 {
192 if (eb->current_dialog >= 0)
193 gtk_container_remove
194 (GTK_CONTAINER(eb->dialog_container),
195 GTK_WIDGET(eb->dialogs[eb->current_dialog]));
196 eb->current_dialog = -1;
197 }
198
effect_browser_destroy(GtkObject * obj)199 static void effect_browser_destroy(GtkObject *obj)
200 {
201 EffectBrowser *eb = EFFECT_BROWSER(obj);
202 guint i;
203 effect_browser_remove_effect(eb);
204 for (i=0; i<EFFECT_BROWSER_CACHE_SIZE; i++) {
205 if (eb->dialogs[i] != NULL) {
206 gtk_widget_unref(GTK_WIDGET(eb->dialogs[i]));
207 eb->dialogs[i] = NULL;
208 }
209 }
210 if (parent_class->destroy) parent_class->destroy(obj);
211 }
212
geom_push(EffectBrowser * eb)213 static void geom_push(EffectBrowser *eb)
214 {
215 gchar *c;
216 guint pos;
217 /* This seems to be the only way to find out handle position */
218 pos = GTK_WIDGET(eb->effect_list_container)->allocation.width;
219 c = g_strdup_printf("%d",pos);
220 geometry_stack_push(GTK_WINDOW(eb),c,&geometry_stack);
221 g_free(c);
222 }
223
effect_browser_delete_event(GtkWidget * widget,GdkEventAny * event)224 static gint effect_browser_delete_event(GtkWidget *widget, GdkEventAny *event)
225 {
226 geom_push(EFFECT_BROWSER(widget));
227 if (GTK_WIDGET_CLASS(parent_class)->delete_event)
228 return GTK_WIDGET_CLASS(parent_class)->delete_event(widget,event);
229 else
230 return FALSE;
231 }
232
effect_browser_class_init(GtkObjectClass * klass)233 static void effect_browser_class_init(GtkObjectClass *klass)
234 {
235 parent_class = gtk_type_class(gtk_window_get_type());
236 klass->destroy = effect_browser_destroy;
237 GTK_WIDGET_CLASS(klass)->delete_event = effect_browser_delete_event;
238 }
239
effect_browser_close(EffectBrowser * eb)240 static void effect_browser_close(EffectBrowser *eb)
241 {
242 geom_push(eb);
243 gtk_widget_destroy(GTK_WIDGET(eb));
244 }
245
apply_click(GtkWidget * widget,EffectBrowser * eb)246 static void apply_click(GtkWidget *widget, EffectBrowser *eb)
247 {
248 gboolean ca,b,mwf;
249 if (eb->dl->selected == NULL) {
250 user_error(_("You have no open file to apply the effect to!"));
251 return;
252 }
253
254 ca = gtk_toggle_button_get_active(eb->close_after);
255 mwf = inifile_get_gboolean("mainwinFront",TRUE);
256
257 if (ca) gtk_widget_hide(GTK_WIDGET(eb));
258
259 b = effect_dialog_apply(eb->dialogs[eb->current_dialog]);
260
261 if (ca) {
262 if (b)
263 gtk_widget_show(GTK_WIDGET(eb));
264 else
265 effect_browser_close(eb);
266 } else if (!mwf)
267 gdk_window_raise(GTK_WIDGET(eb)->window);
268 }
269
get_effect_missing_dialog(gchar * name,gchar source_tag)270 static EffectDialog *get_effect_missing_dialog(gchar *name, gchar source_tag)
271 {
272 EffectDialog *ed;
273 GtkWidget *w;
274 ed = gtk_type_new(effect_dialog_get_type());
275 w = gtk_label_new(_("This effect could not be loaded."));
276 gtk_container_add(ed->input_area,w);
277 gtk_widget_show(w);
278 return ed;
279 }
280
effect_browser_set_effect_main(EffectBrowser * eb,struct effect * e)281 static void effect_browser_set_effect_main(EffectBrowser *eb, struct effect *e)
282 {
283 int i;
284 EffectDialog *ed;
285 GSList *s;
286 struct source *src;
287 gchar *c;
288
289 effect_browser_remove_effect(eb);
290
291 /* Check dialog cache */
292 for (i=0; i<EFFECT_BROWSER_CACHE_SIZE; i++) {
293 if (eb->dialog_effects[i] == e) break;
294 }
295
296 if (i >= EFFECT_BROWSER_CACHE_SIZE) {
297 /* Dialog not in cache */
298
299 /* Make room in top of cache */
300 for (i=0; i<EFFECT_BROWSER_CACHE_SIZE; i++) {
301 if (eb->dialog_effects[i] == NULL) break;
302 }
303 if (i >= EFFECT_BROWSER_CACHE_SIZE) {
304 /* No room in cache, throw out last element */
305 i = EFFECT_BROWSER_CACHE_SIZE-1;
306 gtk_object_unref(GTK_OBJECT(eb->dialogs[i]));
307 eb->dialogs[i] = NULL;
308 eb->dialog_effects[i] = NULL;
309 }
310 for (; i>0; i--) {
311 eb->dialogs[i] = eb->dialogs[i-1];
312 eb->dialog_effects[i] = eb->dialog_effects[i-1];
313 }
314
315 /* Get the new dialog */
316
317 ed = NULL;
318 for (s=sources; s!=NULL; s=s->next) {
319 src = (struct source *)s->data;
320 if (src->tag == e->source_tag) {
321 ed = src->get_func(e->name, e->source_tag,
322 src->get_func_data);
323 effect_dialog_setup(ed, e->name, eb);
324 break;
325 }
326 }
327
328 if (ed == NULL)
329 ed = get_effect_missing_dialog(e->name,e->source_tag);
330
331 g_assert(i == 0);
332 eb->dialogs[i] = ed;
333 gtk_object_ref(GTK_OBJECT(ed));
334 gtk_object_sink(GTK_OBJECT(ed));
335 eb->dialog_effects[i] = e;
336 }
337
338 eb->current_dialog = i;
339
340 gtk_container_add(eb->dialog_container,
341 GTK_WIDGET(eb->dialogs[i]));
342 gtk_widget_show(GTK_WIDGET(eb->dialogs[i]));
343
344 c = g_strdup_printf("%c%s",e->source_tag,e->name);
345 inifile_set("lastEffect",c);
346 g_free(c);
347 }
348
effect_browser_invalidate_effect(EffectBrowser * eb,gchar * effect_name,gchar source_tag)349 void effect_browser_invalidate_effect(EffectBrowser *eb, gchar *effect_name,
350 gchar source_tag)
351 {
352 gboolean displayed = FALSE;
353 struct effect *e;
354 gint i=0;
355
356 /* Search the cache for the effect */
357 for (i=0; i<EFFECT_BROWSER_CACHE_SIZE; i++) {
358 e = eb->dialog_effects[i];
359 if (e != NULL && e->source_tag == source_tag &&
360 !strcmp(e->name, effect_name))
361 break;
362 }
363
364 if (i >= EFFECT_BROWSER_CACHE_SIZE) return; /* Not found */
365
366 displayed = (i == eb->current_dialog);
367 if (displayed) effect_browser_remove_effect(eb);
368 gtk_object_unref(GTK_OBJECT(eb->dialogs[i]));
369 eb->dialogs[i] = NULL;
370 eb->dialog_effects[i] = NULL;
371 if (displayed) effect_browser_set_effect_main(eb,e);
372 }
373
effect_browser_select_child(GtkList * list,GtkWidget * widget,gpointer user_data)374 static void effect_browser_select_child(GtkList *list, GtkWidget *widget,
375 gpointer user_data)
376 {
377 EffectBrowser *eb = EFFECT_BROWSER(user_data);
378 struct effect *effect;
379
380 effect = gtk_object_get_data(GTK_OBJECT(widget),"effectptr");
381 g_assert(effect != NULL);
382 effect_browser_set_effect_main(eb,effect);
383 eb->list_widget_sel = GTK_LIST_ITEM(widget);
384 }
385
save_effect_order(EffectBrowser * eb)386 static void save_effect_order(EffectBrowser *eb)
387 {
388 GList *l;
389 gint i;
390 gchar *c,*d;
391 struct effect *effect;
392 l = gtk_container_get_children(GTK_CONTAINER(eb->list_widget));
393 for (i=0; l!=NULL; l=l->next,i++) {
394 c = g_strdup_printf("effectBrowserOrder%d",i);
395 effect = gtk_object_get_data(GTK_OBJECT(l->data),"effectptr");
396 d = g_strdup_printf("%c%s",effect->source_tag,effect->name);
397 inifile_set(c,d);
398 g_free(c);
399 g_free(d);
400 }
401 c = g_strdup_printf("effectBrowserOrder%d",i);
402 inifile_set(c,NULL);
403 g_free(c);
404 g_list_free(l);
405 }
406
moveup_main(EffectBrowser * eb,GtkListItem * item)407 static void moveup_main(EffectBrowser *eb, GtkListItem *item)
408 {
409 gint i;
410 GList *l;
411 i = gtk_list_child_position(GTK_LIST(eb->list_widget),
412 GTK_WIDGET(item));
413 if (i <= 0) return;
414 l = g_list_append(NULL, item);
415 gtk_list_remove_items_no_unref(GTK_LIST(eb->list_widget),l);
416 gtk_list_insert_items(GTK_LIST(eb->list_widget),l,i-1);
417 gtk_list_item_select(GTK_LIST_ITEM(eb->list_widget_sel));
418 save_effect_order(eb);
419 }
420
movedown_main(EffectBrowser * eb,GtkListItem * item)421 static void movedown_main(EffectBrowser *eb, GtkListItem *item)
422 {
423 gint i;
424 GList *l;
425 i = gtk_list_child_position(GTK_LIST(eb->list_widget),
426 GTK_WIDGET(item));
427 l = g_list_append(NULL, item);
428 gtk_list_remove_items_no_unref(GTK_LIST(eb->list_widget),l);
429 gtk_list_insert_items(GTK_LIST(eb->list_widget),l,i+1);
430 gtk_list_item_select(GTK_LIST_ITEM(eb->list_widget_sel));
431 save_effect_order(eb);
432 }
433
movetop_main(EffectBrowser * eb,GtkListItem * item)434 static void movetop_main(EffectBrowser *eb, GtkListItem *item)
435 {
436 GList *l;
437 l = g_list_append(NULL, item);
438 gtk_list_remove_items_no_unref(GTK_LIST(eb->list_widget),l);
439 gtk_list_prepend_items(GTK_LIST(eb->list_widget),l);
440 gtk_list_item_select(GTK_LIST_ITEM(eb->list_widget_sel));
441 save_effect_order(eb);
442 }
443
movebot_main(EffectBrowser * eb,GtkListItem * item)444 static void movebot_main(EffectBrowser *eb, GtkListItem *item)
445 {
446 GList *l;
447 l = g_list_append(NULL, item);
448 gtk_list_remove_items_no_unref(GTK_LIST(eb->list_widget),l);
449 gtk_list_append_items(GTK_LIST(eb->list_widget),l);
450 gtk_list_item_select(GTK_LIST_ITEM(eb->list_widget_sel));
451 save_effect_order(eb);
452 }
453
454 static EffectBrowser *clicked_eb;
455
list_item_moveup(GtkMenuItem * menuitem,gpointer user_data)456 static void list_item_moveup(GtkMenuItem *menuitem, gpointer user_data)
457 {
458 moveup_main(clicked_eb, clicked_eb->list_widget_clicked);
459 }
460
list_item_movedown(GtkMenuItem * menuitem,gpointer user_data)461 static void list_item_movedown(GtkMenuItem *menuitem, gpointer user_data)
462 {
463 movedown_main(clicked_eb, clicked_eb->list_widget_clicked);
464 }
465
list_item_movetotop(GtkMenuItem * menuitem,gpointer user_data)466 static void list_item_movetotop(GtkMenuItem *menuitem, gpointer user_data)
467 {
468 movetop_main(clicked_eb, clicked_eb->list_widget_clicked);
469 }
470
list_item_movetobottom(GtkMenuItem * menuitem,gpointer user_data)471 static void list_item_movetobottom(GtkMenuItem *menuitem, gpointer user_data)
472 {
473 movebot_main(clicked_eb, clicked_eb->list_widget_clicked);
474 }
475
list_item_sort_main(EffectBrowser * eb,GCompareFunc compfunc)476 static void list_item_sort_main(EffectBrowser *eb, GCompareFunc compfunc)
477 {
478 /* Not the quickest way, but preserves original order if compfunc
479 returns >0 when objects are equal */
480 GList *k,*l,*m=NULL;
481 gint i;
482 struct effect *e;
483 gchar *c,*d;
484 k = gtk_container_get_children(GTK_CONTAINER(eb->list_widget));
485 for (l=k; l!=NULL; l=l->next) {
486 e = gtk_object_get_data(GTK_OBJECT(l->data),"effectptr");
487 g_assert(e != NULL);
488 m = g_list_insert_sorted(m,e,compfunc);
489 }
490 g_list_free(k);
491 for (l=m,i=0; l!=NULL; l=l->next,i++) {
492 e = (struct effect *)l->data;
493 c = g_strdup_printf("effectBrowserOrder%d",i);
494 d = g_strdup_printf("%c%s",e->source_tag,e->name);
495 inifile_set(c,d);
496 g_free(d);
497 g_free(c);
498 }
499 c = g_strdup_printf("effectBrowserOrder%d",i);
500 inifile_set(c,NULL);
501 g_free(c);
502 g_list_free(m);
503 list_widget_rebuild(NULL,NULL,eb);
504 }
505
title_sort_func(gconstpointer a,gconstpointer b)506 gint title_sort_func(gconstpointer a, gconstpointer b)
507 {
508 struct effect const *ae = a, *be = b;
509 int i;
510 i = strcmp(ae->title,be->title);
511 if (i==0) return 1; else return i;
512 }
513
auth_sort_func(gconstpointer a,gconstpointer b)514 gint auth_sort_func(gconstpointer a, gconstpointer b)
515 {
516 struct effect const *ae = a, *be = b;
517 int i;
518 i = strcmp(ae->author,be->author);
519 if (i==0) return 1; else return i;
520 }
521
type_sort_func(gconstpointer a,gconstpointer b)522 gint type_sort_func(gconstpointer a, gconstpointer b)
523 {
524 struct effect const *ae = a, *be = b;
525 int i;
526 i = ae->source_tag - be->source_tag;
527 if (i==0) return 1; else return i;
528 }
529
loc_sort_func(gconstpointer a,gconstpointer b)530 gint loc_sort_func(gconstpointer a, gconstpointer b)
531 {
532 struct effect const *ae = a, *be = b;
533 int i;
534 i = strcmp(ae->location,be->location);
535 if (i==0) return 1; else return i;
536 }
537
538
list_item_sortbytitle(GtkMenuItem * menuitem,gpointer user_data)539 static void list_item_sortbytitle(GtkMenuItem *menuitem, gpointer user_data)
540 {
541 list_item_sort_main(clicked_eb, title_sort_func);
542 }
543
list_item_sortbytype(GtkMenuItem * menuitem,gpointer user_data)544 static void list_item_sortbytype(GtkMenuItem *menuitem, gpointer user_data)
545 {
546 list_item_sort_main(clicked_eb, type_sort_func);
547 }
548
list_item_sortbyloc(GtkMenuItem * menuitem,gpointer user_data)549 static void list_item_sortbyloc(GtkMenuItem *menuitem, gpointer user_data)
550 {
551 list_item_sort_main(clicked_eb, loc_sort_func);
552 }
553
list_item_sortbyauth(GtkMenuItem * menuitem,gpointer user_data)554 static void list_item_sortbyauth(GtkMenuItem *menuitem, gpointer user_data)
555 {
556 list_item_sort_main(clicked_eb, auth_sort_func);
557 }
558
list_item_unsort(GtkMenuItem * menuitem,gpointer user_data)559 static void list_item_unsort(GtkMenuItem *menuitem, gpointer user_data)
560 {
561 inifile_set("effectBrowserOrder0",NULL);
562 list_widget_rebuild(NULL,NULL,clicked_eb);
563 }
564
list_item_rebuild(GtkMenuItem * menuitem,gpointer user_data)565 static void list_item_rebuild(GtkMenuItem *menuitem, gpointer user_data)
566 {
567 effect_register_rebuild();
568 }
569
translate_menu_path(const gchar * path,gpointer func_data)570 static gchar *translate_menu_path(const gchar *path, gpointer func_data)
571 {
572 return _(path);
573 }
574
list_item_button_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)575 static gint list_item_button_press(GtkWidget *widget, GdkEventButton *event,
576 gpointer user_data)
577 {
578 EffectBrowser *eb = EFFECT_BROWSER(user_data);
579 static GtkItemFactory *item_factory = NULL;
580 GtkWidget *w;
581 static GtkItemFactoryEntry menu_items[] = {
582 { N_("/Move Up"), NULL, list_item_moveup, 0, NULL },
583 { N_("/Move Down"), NULL, list_item_movedown, 0, NULL },
584 { N_("/Move to Top"), NULL, list_item_movetotop, 0, NULL },
585 { N_("/Move to Bottom"), NULL, list_item_movetobottom,0, NULL },
586 { "/sep1", NULL, NULL, 0, "<Separator>" },
587 { N_("/Sort by Name"), NULL, list_item_sortbytitle, 0, NULL },
588 { N_("/Sort by Type"), NULL, list_item_sortbytype, 0, NULL },
589 { N_("/Sort by Location"), NULL, list_item_sortbyloc,0,NULL },
590 { N_("/Sort by Author"), NULL, list_item_sortbyauth,0, NULL },
591 { "/sep2", NULL, NULL, 0, "<Separator>" },
592 { N_("/Restore Order"), NULL, list_item_unsort, 0, NULL },
593 { N_("/Rebuild Effect List"), NULL, list_item_rebuild,0,NULL }
594 };
595
596 if (event->button == 3) {
597 if (item_factory == NULL) {
598 item_factory = gtk_item_factory_new(GTK_TYPE_MENU,"<popup>",NULL);
599 #ifdef ENABLE_NLS
600 gtk_item_factory_set_translate_func(item_factory,
601 translate_menu_path, NULL, NULL);
602 #endif
603 gtk_item_factory_create_items(item_factory,
604 ARRAY_LENGTH(menu_items),
605 menu_items,NULL);
606 }
607 clicked_eb = eb;
608 eb->list_widget_clicked = GTK_LIST_ITEM(widget);
609 w = gtk_item_factory_get_widget(item_factory,"<popup>");
610 gtk_menu_popup(GTK_MENU(w),NULL,NULL,NULL,NULL,event->button,
611 event->time);
612 }
613 return FALSE;
614 }
615
add_list_item_main(struct effect * e,GtkList * l,EffectBrowser * eb)616 static void add_list_item_main(struct effect *e, GtkList *l, EffectBrowser *eb)
617 {
618 gchar *c,*d;
619 GtkWidget *w;
620 c = g_strdup_printf("[%c] %s",e->source_tag,e->title);
621
622 /* Translate here for keeping compatibility with old translations */
623 /* New translations should translate the title without the prefix */
624 if (e->source_tag == 'B' || e->source_tag == 'S') d = _(c); else d = c;
625
626 w = gtk_list_item_new_with_label(d);
627 g_free(c);
628 gtk_object_set_data(GTK_OBJECT(w),"effectptr",e);
629 gtk_signal_connect(GTK_OBJECT(w),"button_press_event",
630 GTK_SIGNAL_FUNC(list_item_button_press),eb);
631 gtk_container_add(GTK_CONTAINER(l),w);
632 gtk_widget_show(w);
633 }
634
add_list_item(gpointer item,gpointer user_data)635 static void add_list_item(gpointer item, gpointer user_data)
636 {
637 EffectBrowser *eb = EFFECT_BROWSER(user_data);
638 struct effect *e = (struct effect *)item;
639 add_list_item_main(e,eb->list_widget,eb);
640 }
641
top_click(GtkButton * button,gpointer user_data)642 static void top_click(GtkButton *button, gpointer user_data)
643 {
644 EffectBrowser *eb = EFFECT_BROWSER(user_data);
645 movetop_main(eb,eb->list_widget_sel);
646 }
647
bottom_click(GtkButton * button,gpointer user_data)648 static void bottom_click(GtkButton *button, gpointer user_data)
649 {
650 EffectBrowser *eb = EFFECT_BROWSER(user_data);
651 movebot_main(eb,eb->list_widget_sel);
652 }
653
up_click(GtkButton * button,gpointer user_data)654 static void up_click(GtkButton *button, gpointer user_data)
655 {
656 EffectBrowser *eb = EFFECT_BROWSER(user_data);
657 moveup_main(eb, eb->list_widget_sel);
658 }
659
down_click(GtkButton * button,gpointer user_data)660 static void down_click(GtkButton *button, gpointer user_data)
661 {
662 EffectBrowser *eb = EFFECT_BROWSER(user_data);
663 movedown_main(eb, eb->list_widget_sel);
664 }
665
add_list_widget_items(GtkList * list,EffectBrowser * eb)666 static void add_list_widget_items(GtkList *list, EffectBrowser *eb)
667 {
668 gint i;
669 gchar *c,*d;
670 GList *l;
671 struct effect *e;
672 if (inifile_get("effectBrowserOrder0",NULL) == NULL) {
673 list_object_foreach(effect_list,add_list_item,eb);
674 } else {
675 for (l=effect_list->list; l!=NULL; l=l->next) {
676 e = (struct effect *)l->data;
677 e->process_tag = FALSE;
678 }
679 for (i=0; ; i++) {
680 c = g_strdup_printf("effectBrowserOrder%d",i);
681 d = inifile_get(c,NULL);
682 g_free(c);
683 if (d == NULL) break;
684 for (l=effect_list->list; l!=NULL; l=l->next) {
685 e = (struct effect *)l->data;
686 if (e->process_tag) continue;
687 if (e->source_tag != d[0] || strcmp(e->name,d+1)) continue;
688 add_list_item_main(e,list,eb);
689 e->process_tag = TRUE;
690 break;
691 }
692 }
693 for (l=effect_list->list; l!=NULL; l=l->next) {
694 e = (struct effect *)l->data;
695 if (!e->process_tag)
696 add_list_item_main(e,list,eb);
697 }
698 }
699 }
700
list_widget_rebuild(gpointer dummy,gpointer dummy2,EffectBrowser * eb)701 static void list_widget_rebuild(gpointer dummy, gpointer dummy2,
702 EffectBrowser *eb)
703 {
704 gtk_list_clear_items(eb->list_widget,0,-1);
705 add_list_widget_items(eb->list_widget, eb);
706 }
707
effect_browser_init(EffectBrowser * eb)708 static void effect_browser_init(EffectBrowser *eb)
709 {
710 GtkWidget *b,*b1,*b11,*b11w,*b12,*b121,*b122,*b123,*b124,*b2,*b21;
711 GtkWidget *b21w,*b22,*b23,*b24,*b25,*b251,*b252;
712 GtkAccelGroup* ag;
713 gchar *c,*d;
714 gint x;
715
716 eb->list_widget_sel = NULL;
717
718 ag = gtk_accel_group_new();
719
720 memset(eb->dialogs,0,sizeof(eb->dialogs));
721 memset(eb->dialog_effects,0,sizeof(eb->dialog_effects));
722 eb->current_dialog = -1;
723
724 b11w = gtk_list_new();
725 eb->list_widget = GTK_LIST(b11w);
726 gtk_list_set_selection_mode(GTK_LIST(b11w),GTK_SELECTION_SINGLE);
727
728 effect_register_update_list();
729 add_list_widget_items(eb->list_widget,eb);
730
731 gtk_signal_connect(GTK_OBJECT(effect_list),"item-notify",
732 GTK_SIGNAL_FUNC(list_widget_rebuild),eb);
733
734 b11 = gtk_scrolled_window_new(NULL,NULL);
735 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(b11),
736 GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
737 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(b11),b11w);
738 gtk_widget_set_usize(GTK_WIDGET(b11),150,150);
739 eb->effect_list_container = GTK_CONTAINER(b11);
740
741 #ifdef GTK_STOCK_GOTO_TOP
742 b121 = gtk_button_new_from_stock(GTK_STOCK_GOTO_TOP);
743 #else
744 b121 = gtk_button_new_with_label(_("Top"));
745 #endif
746 gtk_signal_connect(GTK_OBJECT(b121),"clicked",
747 GTK_SIGNAL_FUNC(top_click),eb);
748 #ifdef GTK_STOCK_GO_UP
749 b122 = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
750 #else
751 b122 = gtk_button_new_with_label(_("Up"));
752 #endif
753 gtk_signal_connect(GTK_OBJECT(b122),"clicked",
754 GTK_SIGNAL_FUNC(up_click),eb);
755 #ifdef GTK_STOCK_GO_DOWN
756 b123 = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
757 #else
758 b123 = gtk_button_new_with_label(_("Down"));
759 #endif
760 gtk_signal_connect(GTK_OBJECT(b123),"clicked",
761 GTK_SIGNAL_FUNC(down_click),eb);
762 #ifdef GTK_STOCK_GOTO_BOTTOM
763 b124 = gtk_button_new_from_stock(GTK_STOCK_GOTO_BOTTOM);
764 #else
765 b124 = gtk_button_new_with_label(_("Bottom"));
766 #endif
767 gtk_signal_connect(GTK_OBJECT(b124),"clicked",
768 GTK_SIGNAL_FUNC(bottom_click),eb);
769
770 b12 = gtk_hbox_new(FALSE,5);
771 gtk_box_pack_start(GTK_BOX(b12),b121,FALSE,FALSE,0);
772 gtk_box_pack_start(GTK_BOX(b12),b122,FALSE,FALSE,0);
773 gtk_box_pack_start(GTK_BOX(b12),b123,FALSE,FALSE,0);
774 gtk_box_pack_start(GTK_BOX(b12),b124,FALSE,FALSE,0);
775
776 b1 = gtk_vbox_new(FALSE,5);
777 gtk_box_pack_start(GTK_BOX(b1),b11,TRUE,TRUE,0);
778 gtk_box_pack_start(GTK_BOX(b1),b12,FALSE,FALSE,0);
779
780 b21w = gtk_alignment_new(0.5,0.5,1.0,1.0);
781 eb->dialog_container = GTK_CONTAINER(b21w);
782
783 b21 = gtk_scrolled_window_new(NULL,NULL);
784 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(b21),
785 GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
786 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(b21),b21w);
787
788 b22 = gtk_hseparator_new();
789
790 b23 = gtk_hbox_new(FALSE,3);
791 eb->mw_list_box = GTK_BOX(b23);
792
793 b24 = gtk_check_button_new_with_label(_("Close dialog after applying "
794 "effect"));
795 eb->close_after = GTK_TOGGLE_BUTTON(b24);
796
797 #ifdef GTK_STOCK_APPLY
798 b251 = gtk_button_new_from_stock(GTK_STOCK_APPLY);
799 #else
800 b251 = gtk_button_new_with_label(_("Apply"));
801 #endif
802 gtk_signal_connect(GTK_OBJECT(b251),"clicked",(GtkSignalFunc)apply_click,
803 eb);
804
805 #ifdef GTK_STOCK_CLOSE
806 b252 = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
807 #else
808 b252 = gtk_button_new_with_label(_("Close"));
809 #endif
810 gtk_widget_add_accelerator (b252, "clicked", ag, GDK_Escape, 0, (GtkAccelFlags) 0);
811 gtk_signal_connect_object(GTK_OBJECT(b252),"clicked",
812 (GtkSignalFunc)effect_browser_close,
813 GTK_OBJECT(eb));
814
815 b25 = gtk_hbutton_box_new();
816 gtk_box_pack_start(GTK_BOX(b25),b251,FALSE,TRUE,3);
817 gtk_box_pack_start(GTK_BOX(b25),b252,FALSE,TRUE,3);
818
819 b2 = gtk_vbox_new(FALSE,5);
820 gtk_box_pack_start(GTK_BOX(b2),b21,TRUE,TRUE,0);
821 gtk_box_pack_end(GTK_BOX(b2),b25,FALSE,FALSE,0);
822 gtk_box_pack_end(GTK_BOX(b2),b24,FALSE,FALSE,0);
823 gtk_box_pack_end(GTK_BOX(b2),b23,FALSE,TRUE,0);
824 gtk_box_pack_end(GTK_BOX(b2),b22,FALSE,TRUE,0);
825
826 b = gtk_hpaned_new();
827 gtk_paned_pack1(GTK_PANED(b),b1,FALSE,TRUE);
828 gtk_paned_pack2(GTK_PANED(b),b2,TRUE,TRUE);
829
830 gtk_window_set_title(GTK_WINDOW(eb),_("Effects"));
831 gtk_window_add_accel_group(GTK_WINDOW (eb), ag);
832 gtk_window_set_policy(GTK_WINDOW(eb),FALSE,TRUE,FALSE);
833
834 if (!geometry_stack_inited) {
835 if (inifile_get_gboolean("useGeometry",FALSE))
836 geometry_stack = geometry_stack_from_inifile("effectGeometry");
837 geometry_stack_inited = TRUE;
838 }
839 if (!geometry_stack_pop(&geometry_stack,&c,GTK_WINDOW(eb))) {
840 gtk_window_set_position (GTK_WINDOW (eb), GTK_WIN_POS_CENTER);
841 gtk_window_set_default_size(GTK_WINDOW(eb),600,300);
842 } else {
843 if (c != NULL) {
844 x = strtoul(c,&d,10);
845 if (*d == 0 && *c != 0)
846 gtk_paned_set_position(GTK_PANED(b),x);
847 g_free(c);
848 }
849 }
850 gtk_container_set_border_width(GTK_CONTAINER(eb),5);
851 gtk_container_add(GTK_CONTAINER(eb),b);
852 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(b251),GTK_CAN_DEFAULT);
853 gtk_widget_grab_default(GTK_WIDGET(b251));
854 gtk_widget_show_all(b);
855 }
856
effect_browser_get_type(void)857 GtkType effect_browser_get_type(void)
858 {
859 static GtkType id=0;
860 if (!id) {
861 GtkTypeInfo info = {
862 "EffectBrowser",
863 sizeof(EffectBrowser),
864 sizeof(EffectBrowserClass),
865 (GtkClassInitFunc)effect_browser_class_init,
866 (GtkObjectInitFunc)effect_browser_init
867 };
868 id = gtk_type_unique(gtk_window_get_type(),&info);
869 }
870 return id;
871 }
872
effect_browser_new(Document * doc)873 GtkWidget *effect_browser_new(Document *doc)
874 {
875 return effect_browser_new_with_effect(doc,"volume",'B',FALSE);
876 }
877
effect_browser_new_with_effect(Document * doc,gchar * effect,gchar source_tag,gboolean close_after)878 GtkWidget *effect_browser_new_with_effect(Document *doc, gchar *effect,
879 gchar source_tag,
880 gboolean close_after)
881 {
882 GtkWidget *w;
883 EffectBrowser *eb =
884 EFFECT_BROWSER(gtk_type_new(effect_browser_get_type()));
885 gtk_signal_connect(GTK_OBJECT(eb->list_widget),"select_child",
886 (GtkSignalFunc)effect_browser_select_child,eb);
887
888 w = document_list_new(doc);
889 gtk_box_pack_end(GTK_BOX(eb->mw_list_box),w,TRUE,TRUE,0);
890 gtk_widget_show(w);
891 eb->dl = DOCUMENT_LIST(w);
892 w = gtk_label_new(_("Apply to: "));
893 gtk_box_pack_end(GTK_BOX(eb->mw_list_box),w,FALSE,FALSE,0);
894 gtk_widget_show(w);
895
896 if (effect == NULL) {
897 effect = inifile_get("lastEffect","Bvolume");
898 source_tag = effect[0];
899 effect++;
900 }
901 effect_browser_set_effect(eb,effect,source_tag);
902 if (eb->current_dialog < 0) effect_browser_set_effect(eb,"volume",'B');
903 g_assert(eb->current_dialog >= 0);
904 gtk_toggle_button_set_active(eb->close_after,close_after);
905 return GTK_WIDGET(eb);
906 }
907
effect_browser_set_effect(EffectBrowser * eb,gchar * effect,gchar source_tag)908 void effect_browser_set_effect(EffectBrowser *eb, gchar *effect,
909 gchar source_tag)
910 {
911 struct effect *e;
912 GList *l,*w;
913 gpointer p;
914
915 for (l=effect_list->list; l!=NULL; l=l->next) {
916 e = (struct effect *)l->data;
917 if (e->source_tag == source_tag && !strcmp(e->name, effect)) {
918 /* Find the list item which points to this effect */
919 w = gtk_container_get_children(GTK_CONTAINER(eb->list_widget));
920 for (; w!=NULL; w=w->next) {
921 p = gtk_object_get_data(GTK_OBJECT(w->data),"effectptr");
922 g_assert(p != NULL);
923 if (p == e) {
924 gtk_list_select_child(eb->list_widget,
925 GTK_WIDGET(w->data));
926 return;
927 }
928 }
929 /* Effect exists but not in list, shouldn't happen */
930 g_assert_not_reached();
931 }
932 }
933 /* Effect doesn't exist - do nothing */
934 }
935
effect_browser_shutdown(void)936 void effect_browser_shutdown(void)
937 {
938 if (inifile_get_gboolean("useGeometry",FALSE))
939 geometry_stack_save_to_inifile("effectGeometry",geometry_stack);
940 }
941
942