1 /*
2 * Copyright (C) 2002 2003 2004 2005 2006 2007 2008 2009 2010, Magnus Hjorth
3 * Copyright (C) 2011 2012 2013 2018, Magnus Hjorth
4 *
5 * This file is part of mhWaveEdit.
6 *
7 * mhWaveEdit is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * mhWaveEdit is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with mhWaveEdit; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22
23 #include <config.h>
24
25 #include <string.h>
26 #include <math.h>
27 #include <sys/time.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 #include "gtkfiles.h"
31 #include "filetypes.h"
32 #include "chunkview.h"
33 #include "mainwindow.h"
34 #include "recorddialog.h"
35 #include "configdialog.h"
36 #include "gotodialog.h"
37 #include "chunk.h"
38 #include "um.h"
39 #include "main.h"
40 #include "inifile.h"
41 #include "player.h"
42 #include "sound.h"
43 #include "effectbrowser.h"
44 #include "soxdialog.h"
45 #include "help.h"
46 #include "ladspadialog.h"
47 #include "gettext.h"
48 #include "bitmap.h"
49
50 #include "button_open.xpm"
51 #include "button_save.xpm"
52 #include "button_undo.xpm"
53 #include "button_redo.xpm"
54 #include "button_cut.xpm"
55 #include "button_copy.xpm"
56 #include "button_paste.xpm"
57 #include "button_pasteover.xpm"
58 #include "button_delete.xpm"
59 #include "button_cursorstart.xpm"
60 #include "button_cursorend.xpm"
61 #include "button_play.xpm"
62 #include "button_playselection.xpm"
63 #include "button_stop.xpm"
64 #include "button_loop.xpm"
65 #include "button_follow.xpm"
66 #include "button_record.xpm"
67 #include "button_mixer.xpm"
68 #include "button_bounce.xpm"
69 #include "icon.xpm"
70 #include "vzoom.xbm"
71 #include "hzoom.xbm"
72 #include "speed.xbm"
73
74 /* #define SHOW_DEBUG_MENU */
75
76 #if GTK_MAJOR_VERSION < 2
77 #define INV_SPEED
78 #endif
79
80 #ifdef FIXED_DATE
81 #define BUILD_DATE FIXED_DATE
82 #else
83 #define BUILD_DATE __DATE__
84 #endif
85
86 #ifdef FIXED_TIME
87 #define BUILD_TIME FIXED_TIME
88 #else
89 #define BUILD_TIME __TIME__
90 #endif
91
92 ListObject *mainwindow_objects = NULL;
93
94 static gboolean window_geometry_stack_inited = FALSE;
95 static GSList *window_geometry_stack = NULL;
96 static GList *recent_filenames = NULL;
97 static GtkObjectClass *parent_class;
98 static Chunk *clipboard = NULL;
99 gboolean autoplay_mark_flag = FALSE;
100 gboolean varispeed_reset_flag = FALSE;
101
102 static Mainwindow *mainwindow_set_document(Mainwindow *w, Document *doc,
103 gchar *filename);
104 static void mainwindow_view_changed(Document *d, gpointer user_data);
105 static void mainwindow_selection_changed(Document *d, gpointer user_data);
106 static void mainwindow_cursor_changed(Document *d, gboolean rolling,
107 gpointer user_data);
108 static void mainwindow_state_changed(Document *d, gpointer user_data);
109
110
111
load_recent(void)112 static void load_recent(void)
113 {
114 guint i;
115 gchar *c,*d;
116 g_assert(recent_filenames == NULL);
117 for (i=1; ; i++) {
118 c = g_strdup_printf("recentFile%d",i);
119 d = inifile_get(c,NULL);
120 g_free(c);
121 if (d == NULL) break;
122 recent_filenames = g_list_append(recent_filenames, g_strdup(d));
123 }
124 }
125
save_recent(void)126 static void save_recent(void)
127 {
128 guint i,j;
129 GList *l;
130 gchar *c;
131 j = inifile_get_guint32("recentFiles",4);
132 if (j > MAINWINDOW_RECENT_MAX) j=4;
133 for (i=1,l=recent_filenames; i<=j && l!=NULL; i++,l=l->next) {
134 c = g_strdup_printf("recentFile%d",i);
135 inifile_set(c,l->data);
136 g_free(c);
137 }
138 }
139
update_file_recent(Mainwindow * w)140 static void update_file_recent(Mainwindow *w)
141 {
142 guint i = 1;
143 GList *l = recent_filenames;
144 GList *m = w->recent;
145 gchar *c,*d;
146 for (; m!=NULL && l!=NULL; m=m->next,l=l->next,i++) {
147 d = namepart((gchar *)l->data);
148 c = g_strdup_printf("%d. %s",i,d);
149 gtk_label_set_text(GTK_LABEL(GTK_BIN(m->data)->child),c);
150 gtk_widget_set_sensitive(GTK_WIDGET(m->data),TRUE);
151 g_free(c);
152 }
153 for (; m!=NULL; m=m->next,i++) {
154 c = g_strdup_printf("%d.",i);
155 gtk_label_set_text(GTK_LABEL(GTK_BIN(m->data)->child),c);
156 gtk_widget_set_sensitive(GTK_WIDGET(m->data),FALSE);
157 g_free(c);
158 }
159 }
160
recent_file(gchar * filename)161 static void recent_file(gchar *filename)
162 {
163 GList *l = recent_filenames;
164 /* Remove other reference to this file, if it exists */
165 while (l!=NULL) {
166 if (!strcmp((gchar *)l->data,filename)) {
167 recent_filenames = g_list_remove_link(recent_filenames,l);
168 g_free(l->data);
169 g_list_free_1(l);
170 break;
171 } else
172 l = l->next;
173 }
174 /* Put file at top */
175 recent_filenames = g_list_prepend(recent_filenames,g_strdup(filename));
176 list_object_foreach(mainwindow_objects,(GFunc)update_file_recent,NULL);
177 save_recent();
178 }
179
180 static void update_desc(Mainwindow *w);
181
set_sensitive(GList * l,gboolean s)182 static void set_sensitive(GList *l, gboolean s)
183 {
184 while (l != NULL) {
185 gtk_widget_set_sensitive(GTK_WIDGET(l->data),s);
186 l = l->next;
187 }
188 }
189
190 /* This function makes the window un-sensitive and brings it to front.*/
procstart(StatusBar * bar,gpointer user_data)191 static void procstart(StatusBar *bar, gpointer user_data)
192 {
193 Mainwindow *w = MAINWINDOW(user_data);
194 mainwindow_set_sensitive(w,FALSE);
195 w->esc_pressed_flag = FALSE;
196 #if GTK_MAJOR_VERSION > 1
197 gtk_window_present(GTK_WINDOW(w));
198 #else
199 if (GTK_WIDGET(w)->window)
200 gdk_window_raise(GTK_WIDGET(w)->window);
201 #endif
202 gtk_grab_add(GTK_WIDGET(w));
203 }
204
procend(StatusBar * bar,gpointer user_data)205 static void procend(StatusBar *bar, gpointer user_data)
206 {
207 Mainwindow *w = MAINWINDOW(user_data);
208 mainwindow_set_sensitive(w,TRUE);
209 mainwindow_update_texts();
210 gtk_grab_remove(GTK_WIDGET(w));
211 }
212
fix_title(Mainwindow * wnd)213 static void fix_title(Mainwindow *wnd)
214 {
215 gchar *c;
216 if (wnd->doc != NULL) {
217 c = g_strdup_printf ( _("mhWaveEdit: %s (%s): %d Hz, %s"),
218 wnd->doc->titlename,
219 chunk_get_time(wnd->doc->chunk,
220 wnd->doc->chunk->length,
221 NULL),
222 wnd->doc->chunk->format.samplerate,
223 sampletype_name(&(wnd->doc->chunk->format)));
224 } else
225 c = g_strdup(PROGRAM_VERSION_STRING);
226 gtk_window_set_title ( GTK_WINDOW ( wnd ), c );
227 g_free ( c );
228 }
229
update_desc(Mainwindow * w)230 static void update_desc(Mainwindow *w)
231 {
232 if (w->doc != NULL)
233 status_bar_set_info(w->statusbar,w->doc->cursorpos,
234 (playing_document==w->doc),w->doc->viewstart,
235 w->doc->viewend,w->doc->selstart,
236 w->doc->selend,
237 w->doc->chunk->format.samplerate,
238 w->doc->chunk->length);
239 else
240 status_bar_reset(w->statusbar);
241
242 }
243
typesel_changed(Combo * obj,GtkWidget * user_data)244 static void typesel_changed(Combo *obj, GtkWidget *user_data)
245 {
246 int i;
247 gchar *c;
248 i = combo_selected_index(obj);
249 if (i == 0) {
250 gtk_widget_set_sensitive(user_data,TRUE);
251 } else {
252 c = fileformat_extension(i-1);
253 get_filename_modify_extension(c);
254 if (fileformat_has_options(i-1)) {
255 gtk_widget_set_sensitive(user_data,TRUE);
256 } else {
257 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(user_data),TRUE);
258 gtk_widget_set_sensitive(user_data,FALSE);
259 }
260 }
261 }
262
mainwindow_open(Mainwindow * w,gchar * filename)263 static void mainwindow_open(Mainwindow *w, gchar *filename)
264 {
265 Document *doc;
266 doc = document_new_with_file ( filename, w->statusbar );
267 if (doc == NULL) return;
268 mainwindow_set_document ( w, doc, filename );
269 inifile_set("lastOpenFile",filename);
270 recent_file(filename);
271 }
272
get_save_filename(gchar * old_filename,gchar * title_text,gint * type_id,gboolean * use_defaults)273 static gchar *get_save_filename(gchar *old_filename, gchar *title_text,
274 gint *type_id, gboolean *use_defaults)
275 {
276 gchar *lsf,*lsd,*filename;
277 gchar *c,*d,*e;
278 GtkBox *b1,*b2;
279 GtkWidget *w,*usedef,*typesel;
280 GList *l;
281 gint i;
282
283 /* Get the lastSaveFile entry */
284 lsf = inifile_get("lastSaveFile",NULL);
285 /* If we didn't have a lastSaveFile entry, assume we want to
286 save into the same directory as we loaded from. */
287 if (lsf == NULL) lsf = inifile_get("lastOpenFile",NULL);
288 /* Get the directory part and copy into lsd */
289 if (lsf != NULL) {
290 lsd = g_strdup(lsf);
291 c = strrchr(lsd,'/');
292 if (c != NULL) c[1]=0;
293 else {
294 g_free(lsd);
295 lsd = NULL;
296 }
297 } else lsd = NULL;
298
299 /* Create the custom widget */
300 usedef = gtk_check_button_new_with_label(_("Use default settings"));
301 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(usedef),TRUE);
302 typesel = combo_new();
303
304 l = g_list_append(NULL,g_strdup(_("Auto-detect from extension")));
305 for (i=0; ; i++) {
306 c = fileformat_name(i);
307 if (c == NULL) break;
308 d = fileformat_extension(i);
309 e = g_strdup_printf("%s (%s)",c,d);
310 l = g_list_append(l,e);
311 }
312 combo_set_items(COMBO(typesel),l,0);
313 gtk_signal_connect(GTK_OBJECT(typesel),"selection-changed",
314 GTK_SIGNAL_FUNC(typesel_changed),usedef);
315 g_list_foreach(l,(GFunc)g_free,NULL);
316 g_list_free(l);
317
318 b1 = GTK_BOX(gtk_hbox_new(FALSE,0));
319 w = gtk_label_new(_("File type: "));
320 gtk_box_pack_start(b1,w,FALSE,FALSE,0);
321 gtk_box_pack_start(b1,typesel,TRUE,TRUE,0);
322 gtk_box_pack_start(b1,usedef,FALSE,FALSE,6);
323 b2 = GTK_BOX(gtk_vbox_new(FALSE,8));
324 gtk_box_pack_start(b2,GTK_WIDGET(b1),FALSE,FALSE,0);
325
326 gtk_object_ref(GTK_OBJECT(usedef));
327 gtk_object_ref(GTK_OBJECT(typesel));
328
329 gtk_widget_show_all(GTK_WIDGET(b2));
330
331 if (lsd == NULL)
332 filename = get_filename ( old_filename, "*.wav", title_text,
333 TRUE, GTK_WIDGET(b2));
334 else if (old_filename == NULL)
335 filename = get_filename (lsd, "*.wav", title_text, TRUE,
336 GTK_WIDGET(b2));
337 else {
338 c = strrchr(old_filename, '/');
339 if (!c) c=old_filename;
340 else c = c+1;
341 d = g_strjoin("/",lsd,c,NULL);
342 filename = get_filename(d, "*.wav", title_text, TRUE,
343 GTK_WIDGET(b2));
344 g_free(d);
345 }
346
347 *use_defaults = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(usedef));
348 *type_id = combo_selected_index(COMBO(typesel)) - 1;
349
350 g_free(lsd);
351 gtk_object_unref(GTK_OBJECT(typesel));
352 gtk_object_unref(GTK_OBJECT(usedef));
353 return filename;
354
355 }
356
mainwindow_save(Mainwindow * w,gchar * filename)357 static gboolean mainwindow_save ( Mainwindow *w, gchar *filename )
358 {
359 int type_id = -1;
360 gboolean use_defs = TRUE;
361 gboolean r;
362 gboolean fmal = FALSE; /* TRUE if filename should be g_free:d */
363
364 if (!document_can_undo(w->doc) && w->doc->filename != NULL)
365 if (user_message(_("The file has not changed since last save. Press OK"
366 " if you want to save it anyway?"),UM_OKCANCEL) ==
367 MR_CANCEL)
368 return FALSE;
369
370 /* If there is no filename provided, get a filename from a dialog
371 * box. Also set the fmal flag so we remember to free the
372 * filename later. */
373 if (filename == NULL) {
374 filename = get_save_filename(w->doc->filename,_("Save File"),
375 &type_id,&use_defs);
376 if (filename == NULL) return TRUE;
377 fmal = TRUE;
378 }
379
380 g_assert(filename != NULL);
381 /* Save the file */
382 r = document_save(w->doc, filename, type_id, use_defs);
383 if (r) { if (fmal) g_free(filename); return TRUE; }
384
385 inifile_set("lastSaveFile",filename);
386 recent_file(filename);
387 if (fmal) g_free(filename);
388
389 return FALSE;
390 }
391
change_check(Mainwindow * w)392 static gboolean change_check ( Mainwindow *w )
393 {
394 gint i;
395 gchar *c;
396 if (w->doc == NULL ||
397 (w->doc->filename != NULL && !document_can_undo(w->doc)))
398 return FALSE;
399 c = g_strdup_printf( _("Save changes to %s?"),
400 w->doc->titlename );
401 i = user_message ( c, UM_YESNOCANCEL );
402 switch (i) {
403 case MR_YES:
404 return mainwindow_save ( w, w->doc->filename );
405 case MR_NO:
406 return FALSE;
407 case MR_CANCEL:
408 return TRUE;
409 }
410 g_assert_not_reached();
411 return TRUE;
412 }
413
mainwindow_destroy(GtkObject * obj)414 static void mainwindow_destroy(GtkObject *obj)
415 {
416 Mainwindow *w = MAINWINDOW(obj);
417
418 list_object_remove(mainwindow_objects, obj);
419
420 if ( w->doc != NULL ) {
421 gtk_signal_disconnect_by_data(GTK_OBJECT(w->doc),obj);
422 gtk_object_unref(GTK_OBJECT(w->doc));
423 w->doc = NULL;
424 }
425
426 if (list_object_get_size(mainwindow_objects) == 0) {
427 if (clipboard) gtk_object_unref ( GTK_OBJECT(clipboard) );
428 clipboard = NULL;
429 quitflag = TRUE;
430 geometry_stack_save_to_inifile("windowGeometry",
431 window_geometry_stack);
432 }
433
434 parent_class->destroy(obj);
435 }
436
mainwindow_delete_event(GtkWidget * widget,GdkEventAny * event)437 static gint mainwindow_delete_event(GtkWidget *widget, GdkEventAny *event)
438 {
439 Mainwindow *w = MAINWINDOW ( widget );
440 GtkWidgetClass *pcw = GTK_WIDGET_CLASS(parent_class);
441 if (change_check(w)) return TRUE;
442 if (playing_document == w->doc) player_stop();
443 geometry_stack_push(GTK_WINDOW(w),NULL,&window_geometry_stack);
444 if (pcw->delete_event) return pcw->delete_event(widget,event);
445 else return FALSE;
446 }
447
mainwindow_realize(GtkWidget * widget)448 static void mainwindow_realize(GtkWidget *widget)
449 {
450 if (GTK_WIDGET_CLASS(parent_class)->realize)
451 GTK_WIDGET_CLASS(parent_class)->realize(widget);
452 if (!icon) icon = gdk_pixmap_create_from_xpm_d(widget->window,NULL,NULL,
453 icon_xpm);
454 gdk_window_set_icon(widget->window,NULL,icon,NULL);
455
456 }
457
mainwindow_toggle_mark(Mainwindow * w,gchar * label)458 static void mainwindow_toggle_mark(Mainwindow *w, gchar *label)
459 {
460 off_t u;
461 u = document_get_mark(w->doc,label);
462 if (u == w->doc->cursorpos)
463 document_set_mark(w->doc,label,DOCUMENT_BAD_MARK);
464 else
465 document_set_mark(w->doc,label,w->doc->cursorpos);
466 }
467
do_play(Mainwindow * w,off_t start,off_t end,gboolean loop)468 static void do_play(Mainwindow *w, off_t start, off_t end, gboolean loop)
469 {
470 gboolean speed_reset = FALSE;
471 if (varispeed_reset_flag &&
472 !(player_playing() && playing_document == w->doc))
473 speed_reset = TRUE;
474 if (speed_reset) document_stop(w->doc,FALSE);
475 #ifdef INV_SPEED
476 if (speed_reset) gtk_adjustment_set_value(w->speed_adj,-1.0);
477 document_play(w->doc, start, end, loop, -w->speed_adj->value);
478 #else
479 if (speed_reset) gtk_adjustment_set_value(w->speed_adj,1.0);
480 document_play(w->doc, start, end, loop, w->speed_adj->value);
481 #endif
482 update_desc(w);
483 }
484
485
mainwindow_goto_mark(Mainwindow * w,gchar * label)486 static void mainwindow_goto_mark(Mainwindow *w, gchar *label)
487 {
488 off_t u;
489 u = document_get_mark(w->doc,label);
490 if (u != DOCUMENT_BAD_MARK) {
491 if (autoplay_mark_flag)
492 do_play(w,u,w->doc->chunk->length,w->loopmode);
493 else
494 document_set_cursor(w->doc, u);
495 }
496 }
497
498 static void view_zoomin(GtkMenuItem *menu_item, gpointer user_data);
499 static void view_zoomout(GtkMenuItem *menu_item, gpointer user_data);
500 static void view_zoomtoselection(GtkMenuItem *menu_item, gpointer user_data);
501 static void view_zoomall(GtkMenuItem *menu_item, gpointer user_data);
502 static void edit_play(GtkMenuItem *menu_item, gpointer user_data);
503 static void edit_playselection(GtkMenuItem *menu_item, gpointer user_data);
504 static void edit_stop(GtkMenuItem *menu_item, gpointer user_data);
505
mainwindow_keypress(GtkWidget * widget,GdkEventKey * event)506 static gint mainwindow_keypress(GtkWidget *widget, GdkEventKey *event)
507 {
508 Mainwindow *w = MAINWINDOW(widget);
509 off_t o;
510 /* printf("%d\n",event->keyval); */
511 if (!w->sensitive) {
512 if (event->keyval == GDK_Escape)
513 status_bar_break_progress(w->statusbar);
514 return TRUE;
515 }
516 if (w->doc == NULL)
517 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget,event);
518 if ((event->state & GDK_CONTROL_MASK))
519 switch (event->keyval) {
520 case GDK_0: mainwindow_toggle_mark(w,"0"); return TRUE;
521 case GDK_1: mainwindow_toggle_mark(w,"1"); return TRUE;
522 case GDK_2: mainwindow_toggle_mark(w,"2"); return TRUE;
523 case GDK_3: mainwindow_toggle_mark(w,"3"); return TRUE;
524 case GDK_4: mainwindow_toggle_mark(w,"4"); return TRUE;
525 case GDK_5: mainwindow_toggle_mark(w,"5"); return TRUE;
526 case GDK_6: mainwindow_toggle_mark(w,"6"); return TRUE;
527 case GDK_7: mainwindow_toggle_mark(w,"7"); return TRUE;
528 case GDK_8: mainwindow_toggle_mark(w,"8"); return TRUE;
529 case GDK_9: mainwindow_toggle_mark(w,"9"); return TRUE;
530 case GDK_Left:
531 case GDK_KP_Left:
532 if (playing_document == w->doc)
533 player_nudge(-0.5);
534 else {
535 o = w->doc->cursorpos - w->doc->chunk->format.samplerate/2;
536 if (o < 0) o = 0;
537 document_set_cursor(w->doc,o);
538 }
539 return TRUE;
540 case GDK_Right:
541 case GDK_KP_Right:
542 if (playing_document == w->doc)
543 player_nudge(0.5);
544 else {
545 o = w->doc->cursorpos + w->doc->chunk->format.samplerate/2;
546 if (o > w->doc->chunk->length) o = w->doc->chunk->length;
547 document_set_cursor(w->doc,o);
548 }
549 return TRUE;
550 case GDK_Tab:
551 o = (w->doc->viewstart + w->doc->viewend) / 2;
552 document_set_cursor(w->doc,o);
553 }
554 else
555 switch (event->keyval) {
556 case GDK_0: mainwindow_goto_mark(w,"0"); return TRUE;
557 case GDK_1: mainwindow_goto_mark(w,"1"); return TRUE;
558 case GDK_2: mainwindow_goto_mark(w,"2"); return TRUE;
559 case GDK_3: mainwindow_goto_mark(w,"3"); return TRUE;
560 case GDK_4: mainwindow_goto_mark(w,"4"); return TRUE;
561 case GDK_5: mainwindow_goto_mark(w,"5"); return TRUE;
562 case GDK_6: mainwindow_goto_mark(w,"6"); return TRUE;
563 case GDK_7: mainwindow_goto_mark(w,"7"); return TRUE;
564 case GDK_8: mainwindow_goto_mark(w,"8"); return TRUE;
565 case GDK_9: mainwindow_goto_mark(w,"9"); return TRUE;
566 case GDK_plus:
567 case GDK_KP_Add:
568 case GDK_equal:
569 view_zoomin(NULL,widget); return TRUE;
570 case GDK_Down:
571 case GDK_KP_Down:
572 document_zoom(w->doc,2.0,FALSE); return TRUE;
573 case GDK_minus:
574 case GDK_KP_Subtract:
575 view_zoomout(NULL,widget); return TRUE;
576 case GDK_Up:
577 case GDK_KP_Up:
578 document_zoom(w->doc,0.5,FALSE); return TRUE;
579 case GDK_greater: view_zoomtoselection(NULL,widget); return TRUE;
580 case GDK_less: view_zoomall(NULL,widget); return TRUE;
581 case GDK_comma: edit_play(NULL,widget); return TRUE;
582 case GDK_period: edit_stop(NULL,widget); return TRUE;
583 case GDK_slash: edit_playselection(NULL, widget); return TRUE;
584 case GDK_space:
585 if ((event->state & GDK_SHIFT_MASK) != 0)
586 do_play(w,0,w->doc->chunk->length,w->loopmode);
587 else if (playing_document == w->doc)
588 document_stop(w->doc,w->bouncemode);
589 else if (w->doc != NULL)
590 do_play(w,w->doc->cursorpos,w->doc->chunk->length,
591 w->loopmode);
592 return TRUE;
593 case GDK_Left:
594 case GDK_KP_Left:
595 if (playing_document==w->doc && w->doc->followmode)
596 player_nudge(-0.5);
597 else
598 document_scroll(w->doc,
599 -(w->doc->viewend - w->doc->viewstart)/MAINWINDOW_SCROLL_DELTA_RATIO);
600 return TRUE;
601 case GDK_Right:
602 case GDK_KP_Right:
603 if (playing_document==w->doc && w->doc->followmode)
604 player_nudge(+0.5);
605 else
606 document_scroll(w->doc,
607 (w->doc->viewend - w->doc->viewstart)/MAINWINDOW_SCROLL_DELTA_RATIO);
608 return TRUE;
609 case GDK_parenleft:
610 o = 3*w->doc->chunk->format.samplerate;
611 if (w->doc->selstart == w->doc->selend) {
612 if (w->doc->chunk->length < o)
613 do_play(w,0,w->doc->chunk->length,FALSE);
614 else
615 do_play(w,0,o,FALSE);
616 } else if (w->doc->selstart+o > w->doc->selend)
617 do_play(w,w->doc->selstart,w->doc->selend,FALSE);
618 else
619 do_play(w,w->doc->selstart,w->doc->selstart+o,FALSE);
620 return TRUE;
621 case GDK_parenright:
622 o = 3*w->doc->chunk->format.samplerate;
623 if (w->doc->selstart == w->doc->selend) {
624 if (w->doc->chunk->length < o)
625 do_play(w,0,w->doc->chunk->length,FALSE);
626 else
627 do_play(w,w->doc->chunk->length-o,
628 w->doc->chunk->length,FALSE);
629 } else if (w->doc->selstart+o > w->doc->selend)
630 do_play(w,w->doc->selstart,w->doc->selend,FALSE);
631 else
632 do_play(w,w->doc->selend-o,w->doc->selend,FALSE);
633 return TRUE;
634 case GDK_Home:
635 document_set_view(w->doc,0,w->doc->viewend-w->doc->viewstart);
636 if (playing_document != w->doc || w->doc->followmode)
637 document_set_cursor(w->doc,0);
638 return TRUE;
639 case GDK_End:
640 /* Stop playback to prevent cursor jumping back to start point */
641 document_stop(w->doc,FALSE);
642 document_scroll(w->doc,w->doc->chunk->length);
643 if (playing_document != w->doc || w->doc->followmode)
644 document_set_cursor(w->doc,w->doc->chunk->length);
645 return TRUE;
646 case GDK_Tab:
647 document_scroll(w->doc,
648 w->doc->cursorpos-
649 (w->doc->viewend+w->doc->viewstart)/2);
650 return TRUE;
651 }
652 return GTK_WIDGET_CLASS(parent_class)->key_press_event(widget,event);
653 }
654
urldecode(char * str)655 static void urldecode(char *str)
656 {
657 char *s,*d;
658 int i,j;
659 s = d = str;
660 while (*s != 0) {
661 if (*s != '%' || s[1] == 0 || s[2] == 0) {
662 *d = *s;
663 d ++;
664 s ++;
665 } else {
666 i = hexval(s[1]);
667 j = hexval(s[2]);
668 if (i < 0 || j < 0) {
669 *d = *s;
670 d ++;
671 s ++;
672 continue;
673 }
674 *d = (char)(i*16+j);
675 d ++;
676 s += 3;
677 }
678
679 }
680 *d = 0;
681 }
682
mainwindow_drag_data_received(GtkWidget * widget,GdkDragContext * dc,gint x,gint y,GtkSelectionData * selection_data,guint info,guint t)683 static void mainwindow_drag_data_received(GtkWidget *widget,
684 GdkDragContext *dc, gint x, gint y,
685 GtkSelectionData *selection_data,
686 guint info, guint t)
687 {
688 gchar *c,*d,*e,*f;
689 if (selection_data->length > 0) {
690
691 /* Copy and add extra null for safety */
692 c = g_malloc(selection_data->length+1);
693 memcpy(c,selection_data->data,selection_data->length);
694 c[selection_data->length] = 0;
695
696 gtk_drag_finish(dc, TRUE, FALSE, t);
697
698 /* Split into files */
699 for (d=strtok(c,"\n\r"); d!=NULL; d=strtok(NULL,"\n\r")) {
700 e = strchr(d,':');
701 if (e == NULL) continue;
702 *e = 0;
703 if (strcmp(d,"file")) continue;
704 while (e[1] == '/') e++;
705
706 urldecode(e);
707
708 if (!file_exists(e)) {
709 f = g_strdup_printf("Silently ignoring non-esisting "
710 "file: %s\n",e);
711 console_message(f);
712 g_free(f);
713 continue;
714 }
715
716 mainwindow_open(MAINWINDOW(widget),e);
717 /* printf("Dropped: %s\n",e); */
718
719 }
720
721 g_free(c);
722
723 } else
724
725 gtk_drag_finish(dc, FALSE, FALSE, t);
726 }
727
mainwindow_class_init(GtkObjectClass * klass)728 static void mainwindow_class_init(GtkObjectClass *klass)
729 {
730 parent_class = gtk_type_class(gtk_window_get_type());
731 klass->destroy = mainwindow_destroy;
732 GTK_WIDGET_CLASS(klass)->delete_event = mainwindow_delete_event;
733 GTK_WIDGET_CLASS(klass)->realize = mainwindow_realize;
734 GTK_WIDGET_CLASS(klass)->key_press_event = mainwindow_keypress;
735 GTK_WIDGET_CLASS(klass)->drag_data_received =
736 mainwindow_drag_data_received;
737 }
738
mainwindow_set_document(Mainwindow * w,Document * d,gchar * filename)739 static Mainwindow *mainwindow_set_document(Mainwindow *w, Document *d,
740 gchar *filename)
741 {
742 if (w->doc != NULL) {
743 w = MAINWINDOW ( mainwindow_new() );
744 gtk_widget_show ( GTK_WIDGET ( w ) );
745 }
746 w->doc = d;
747 document_set_followmode(d,w->followmode);
748 gtk_object_ref(GTK_OBJECT(w->doc));
749 gtk_object_sink(GTK_OBJECT(w->doc));
750 gtk_signal_connect(GTK_OBJECT(d),"view_changed",
751 GTK_SIGNAL_FUNC(mainwindow_view_changed),w);
752 gtk_signal_connect(GTK_OBJECT(d),"selection_changed",
753 GTK_SIGNAL_FUNC(mainwindow_selection_changed),w);
754 gtk_signal_connect(GTK_OBJECT(d),"cursor_changed",
755 GTK_SIGNAL_FUNC(mainwindow_cursor_changed),w);
756 gtk_signal_connect(GTK_OBJECT(d),"state_changed",
757 GTK_SIGNAL_FUNC(mainwindow_state_changed),w);
758 chunk_view_set_document ( w->view, d );
759 document_set_status_bar(d, w->statusbar);
760 fix_title(w);
761 update_desc(w);
762 set_sensitive(w->need_chunk_items,TRUE);
763 if (!inifile_get_gboolean("varispeed",TRUE))
764 gtk_widget_set_sensitive(w->speed_slider,FALSE);
765 list_object_add(mainwindow_objects,w);
766 mainwindow_view_changed(w->doc,w);
767 return w;
768 }
769
mainwindow_set_chunk(Mainwindow * w,Chunk * c,gchar * filename)770 static Mainwindow *mainwindow_set_chunk(Mainwindow *w, Chunk *c, gchar *filename)
771 {
772 Document *d;
773 d = document_new_with_chunk(c,filename,w->statusbar);
774 return mainwindow_set_document(w,d,filename);
775 }
776
mainwindow_set_speed_sensitive(gboolean sensitive)777 void mainwindow_set_speed_sensitive(gboolean sensitive)
778 {
779 GList *l;
780 Mainwindow *w;
781 for (l=mainwindow_objects->list;l!=NULL;l=l->next) {
782 w = MAINWINDOW(l->data);
783 gtk_widget_set_sensitive(w->speed_slider,sensitive);
784 }
785 }
786
file_open(GtkMenuItem * menuitem,gpointer user_data)787 static void file_open(GtkMenuItem *menuitem, gpointer user_data)
788 {
789 gchar *c;
790 Mainwindow *w = MAINWINDOW ( user_data );
791 if (w->doc != NULL && w->doc->filename != NULL)
792 c = get_filename(w->doc->filename,"*.wav",_("Load File"),FALSE,NULL);
793 else {
794 c = inifile_get("lastOpenFile",NULL);
795 if (c == NULL) c = inifile_get("lastSaveFile",NULL);
796 c = get_filename(c,"*.wav", _("Load File"), FALSE, NULL);
797 }
798 if (!c) return;
799 mainwindow_open(w,c);
800 g_free(c);
801 }
802
file_save(GtkMenuItem * menuitem,gpointer user_data)803 static void file_save(GtkMenuItem *menuitem, gpointer user_data)
804 {
805 Mainwindow *w = MAINWINDOW ( user_data );
806 mainwindow_save ( w, w->doc->filename );
807 }
808
file_saveas(GtkMenuItem * menuitem,gpointer user_data)809 static void file_saveas(GtkMenuItem *menuitem, gpointer user_data)
810 {
811 mainwindow_save ( MAINWINDOW(user_data), NULL );
812 }
813
file_saveselection(GtkMenuItem * menuitem,gpointer user_data)814 static void file_saveselection(GtkMenuItem *menuitem, gpointer user_data)
815 {
816 gint type_id;
817 gboolean use_defs;
818 gchar *fn;
819 Chunk *c;
820 Mainwindow *w = MAINWINDOW(user_data);
821 fn = get_save_filename(NULL,_("Save selection as ..."),
822 &type_id,&use_defs);
823 if (!fn) return;
824 c = chunk_get_part(w->doc->chunk,w->doc->selstart,
825 w->doc->selend-w->doc->selstart);
826 if (!chunk_save(c,fn,type_id,use_defs,dither_editing,w->statusbar))
827 inifile_set("lastSaveFile",fn);
828 gtk_object_sink(GTK_OBJECT(c));
829 g_free(fn);
830 }
831
832
file_close(GtkMenuItem * menuitem,gpointer user_data)833 static void file_close(GtkMenuItem *menuitem, gpointer user_data)
834 {
835 Mainwindow *w = MAINWINDOW(user_data);
836 if (change_check(w)) return;
837 if (playing_document == w->doc) player_stop();
838 if (list_object_get_size(mainwindow_objects)==1 &&
839 w->doc != NULL) {
840 chunk_view_set_document(w->view, NULL);
841 gtk_signal_disconnect_by_data(GTK_OBJECT(w->doc),w);
842 gtk_object_unref(GTK_OBJECT(w->doc));
843 w->doc = NULL;
844 fix_title(w);
845 set_sensitive(w->need_chunk_items,FALSE);
846 set_sensitive(w->need_undo_items,FALSE);
847 set_sensitive(w->need_selection_items,FALSE);
848 list_object_remove(mainwindow_objects,w);
849 } else {
850 geometry_stack_push(GTK_WINDOW(w),NULL,&window_geometry_stack);
851 gtk_widget_destroy(GTK_WIDGET(w));
852 }
853 }
854
try_close(Mainwindow * w,gboolean * user_data)855 static void try_close(Mainwindow *w, gboolean *user_data)
856 {
857 if (*user_data) return;
858 *user_data = change_check(w);
859 }
860
file_exit(GtkMenuItem * menuitem,gpointer user_data)861 static void file_exit(GtkMenuItem *menuitem, gpointer user_data)
862 {
863 gboolean b = FALSE;
864 guint i;
865 GtkWidget *wid;
866 if (list_object_get_size(mainwindow_objects) == 0)
867 file_close(menuitem,user_data);
868 list_object_foreach(mainwindow_objects,(GFunc)try_close,&b);
869 if (b) return;
870 player_stop();
871 /* Reverse the list so we get the oldest windows on the top of the
872 * geometry stack */
873 i = list_object_get_size(mainwindow_objects);
874 for (; i>0; i--) {
875 wid = GTK_WIDGET(list_object_get(mainwindow_objects,i-1));
876 geometry_stack_push(GTK_WINDOW(wid),NULL,&window_geometry_stack);
877 gtk_widget_destroy(wid);
878 }
879 }
880
edit_undo(GtkMenuItem * menuitem,gpointer user_data)881 static void edit_undo(GtkMenuItem *menuitem, gpointer user_data)
882 {
883 Mainwindow *w = MAINWINDOW (user_data);
884 document_undo(w->doc);
885 }
886
edit_redo(GtkMenuItem * menuitem,gpointer user_data)887 static void edit_redo(GtkMenuItem *menuitem, gpointer user_data)
888 {
889 Mainwindow *w = MAINWINDOW (user_data);
890 document_redo(w->doc);
891 }
892
update_clipboard_items(Mainwindow * w,gpointer user_data)893 static void update_clipboard_items(Mainwindow *w, gpointer user_data)
894 {
895 set_sensitive(w->need_clipboard_items,user_data != NULL);
896 }
897
edit_cut(GtkMenuItem * menuitem,gpointer user_data)898 static void edit_cut(GtkMenuItem *menuitem, gpointer user_data)
899 {
900 Chunk *chunk, *part;
901 Mainwindow *w = MAINWINDOW(user_data);
902 g_assert (w->doc->selend != w->doc->selstart);
903 if (clipboard) gtk_object_unref(GTK_OBJECT(clipboard));
904 part = chunk_get_part( w->doc->chunk, w->doc->selstart,
905 w->doc->selend - w->doc->selstart);
906 chunk = chunk_remove_part( w->doc->chunk, w->doc->selstart,
907 w->doc->selend - w->doc->selstart);
908 clipboard = part;
909 gtk_object_ref(GTK_OBJECT(clipboard));
910 gtk_object_sink(GTK_OBJECT(clipboard));
911
912 document_update(w->doc, chunk, w->doc->selstart, -(clipboard->length));
913 list_object_foreach(mainwindow_objects, (GFunc)update_clipboard_items,
914 (gpointer)w);
915 }
916
edit_crop(GtkMenuItem * menu_item,gpointer user_data)917 static void edit_crop(GtkMenuItem *menu_item, gpointer user_data)
918 {
919 Mainwindow *w = MAINWINDOW(user_data);
920 Chunk *c;
921 c = chunk_get_part( w->doc->chunk, w->doc->selstart,
922 w->doc->selend - w->doc->selstart);
923 document_update(w->doc, c, 0, -(w->doc->selstart));
924 }
925
edit_copy(GtkMenuItem * menu_item,gpointer user_data)926 static void edit_copy(GtkMenuItem *menu_item, gpointer user_data)
927 {
928 Mainwindow *w = MAINWINDOW(user_data);
929 g_assert (w->doc->selend != w->doc->selstart);
930 if (clipboard) gtk_object_unref(GTK_OBJECT(clipboard));
931 clipboard = chunk_get_part(w->doc->chunk, w->doc->selstart,
932 w->doc->selend - w->doc->selstart);
933 gtk_object_ref(GTK_OBJECT(clipboard));
934 gtk_object_sink(GTK_OBJECT(clipboard));
935
936 list_object_foreach(mainwindow_objects, (GFunc)update_clipboard_items,
937 (gpointer)w);
938 }
939
edit_paste(GtkMenuItem * menu_item,gpointer user_data)940 static void edit_paste(GtkMenuItem *menu_item, gpointer user_data)
941 {
942 Chunk *c = clipboard, *nc;
943 Mainwindow *w = MAINWINDOW(user_data);
944 off_t cp,cl;
945 if (w->doc == NULL) {
946 mainwindow_set_chunk(w,clipboard,NULL);
947 return;
948 }
949
950 if (!dataformat_equal(&(w->doc->chunk->format),&(c->format))) {
951 c = chunk_convert(c,&(w->doc->chunk->format),dither_editing,
952 w->statusbar);
953 if (c == NULL) return;
954 }
955 cl = c->length;
956 nc = chunk_insert(w->doc->chunk,c,w->doc->cursorpos);
957 gtk_object_sink(GTK_OBJECT(c));
958
959 cp = w->doc->cursorpos;
960 document_update(w->doc, nc, cp, cl);
961 document_set_selection( w->doc, cp, cp + cl );
962 }
963
edit_pasteover(GtkMenuItem * menuitem,gpointer user_data)964 static void edit_pasteover(GtkMenuItem *menuitem, gpointer user_data)
965 {
966 Mainwindow *w = MAINWINDOW(user_data);
967 Chunk *c,*d=clipboard;
968 off_t orig_len,dl;
969 if (w->doc == NULL) {
970 mainwindow_set_chunk(w,clipboard,NULL);
971 return;
972 }
973
974 if (!dataformat_equal(&(w->doc->chunk->format),&(d->format))) {
975 d = chunk_convert(d,&(w->doc->chunk->format),dither_editing,
976 w->statusbar);
977 if (d == NULL) return;
978 }
979 dl = d->length;
980
981 orig_len = MIN(w->doc->chunk->length-w->doc->cursorpos, dl);
982 c = chunk_replace_part(w->doc->chunk, w->doc->cursorpos,
983 orig_len, d);
984 gtk_object_sink(GTK_OBJECT(d));
985
986 document_update(w->doc, c, 0, 0);
987 document_set_selection( w->doc, w->doc->cursorpos,
988 w->doc->cursorpos + dl );
989 }
990
edit_mixpaste(GtkMenuItem * menuitem,gpointer user_data)991 static void edit_mixpaste(GtkMenuItem *menuitem, gpointer user_data)
992 {
993 Mainwindow *w = MAINWINDOW(user_data);
994 Chunk *c,*p,*y,*d=clipboard;
995 off_t partlen;
996 if (w->doc == NULL) {
997 mainwindow_set_chunk(w,clipboard,NULL);
998 return;
999 }
1000
1001 if (!dataformat_equal(&(w->doc->chunk->format),&(d->format))) {
1002 d = chunk_convert(d,&(w->doc->chunk->format),dither_editing,
1003 w->statusbar);
1004 if (d == NULL) return;
1005 }
1006
1007 p = chunk_get_part(w->doc->chunk,w->doc->cursorpos,d->length);
1008 partlen = p->length;
1009 y = chunk_mix(p,d,dither_editing,w->statusbar);
1010 gtk_object_sink(GTK_OBJECT(p));
1011 if (!y) return;
1012 c = chunk_replace_part(w->doc->chunk,w->doc->cursorpos,partlen,y);
1013 gtk_object_sink(GTK_OBJECT(y));
1014 document_update(w->doc, c, 0, 0);
1015 document_set_selection( w->doc, w->doc->cursorpos,
1016 w->doc->cursorpos + d->length );
1017 gtk_object_sink(GTK_OBJECT(d));
1018 }
1019
edit_pastetonew(GtkMenuItem * menuitem,gpointer user_data)1020 static void edit_pastetonew(GtkMenuItem *menuitem, gpointer user_data)
1021 {
1022 Mainwindow *w = MAINWINDOW (user_data);
1023 mainwindow_set_chunk(w,clipboard,NULL);
1024 }
1025
edit_delete(GtkMenuItem * menuitem,gpointer user_data)1026 static void edit_delete(GtkMenuItem *menuitem, gpointer user_data)
1027 {
1028 Mainwindow *w = MAINWINDOW(user_data);
1029 Chunk *chunk;
1030 gint32 slen;
1031 slen = w->doc->selend - w->doc->selstart;
1032 chunk = chunk_remove_part(w->doc->chunk, w->doc->selstart, slen);
1033 document_update( w->doc, chunk, w->doc->selstart, -slen);
1034 }
1035
interp(Chunk * chunk,StatusBar * bar,gpointer user_data)1036 static Chunk *interp(Chunk *chunk, StatusBar *bar, gpointer user_data)
1037 {
1038 return chunk_interpolate_endpoints(chunk,TRUE,dither_editing,bar);
1039 }
1040
edit_silence(GtkMenuItem * menuitem,gpointer user_data)1041 static void edit_silence(GtkMenuItem *menuitem, gpointer user_data)
1042 {
1043 Mainwindow *w = MAINWINDOW(user_data);
1044 document_apply_cb(w->doc,interp,TRUE,NULL);
1045 }
1046
edit_selectall(GtkMenuItem * menuitem,gpointer user_data)1047 static void edit_selectall(GtkMenuItem *menuitem, gpointer user_data)
1048 {
1049 Mainwindow *w = MAINWINDOW(user_data);
1050 if (w->doc->selstart != 0 || w->doc->selend != w->doc->chunk->length)
1051 document_set_selection(w->doc,0,w->doc->chunk->length);
1052 else
1053 document_set_selection(w->doc,0,0);
1054 }
1055
edit_selectnone(GtkMenuItem * menuitem,gpointer user_data)1056 static void edit_selectnone(GtkMenuItem *menuitem, gpointer user_data)
1057 {
1058 Mainwindow *w = MAINWINDOW(user_data);
1059 document_set_selection(w->doc,0,0);
1060 }
1061
view_zoomin(GtkMenuItem * menuitem,gpointer user_data)1062 static void view_zoomin(GtkMenuItem *menuitem, gpointer user_data)
1063 {
1064 Mainwindow *w = MAINWINDOW ( user_data );
1065 document_zoom(w->doc,2.0,TRUE);
1066 }
1067
view_zoomout(GtkMenuItem * item,gpointer user_data)1068 static void view_zoomout(GtkMenuItem *item, gpointer user_data)
1069 {
1070 Mainwindow *w = MAINWINDOW ( user_data );
1071 document_zoom(w->doc,0.5,TRUE);
1072 }
1073
view_zoomtoselection(GtkMenuItem * menuitem,gpointer user_data)1074 static void view_zoomtoselection(GtkMenuItem *menuitem, gpointer user_data)
1075 {
1076 Document *d;
1077 d = MAINWINDOW(user_data)->doc;
1078 document_set_view(d,d->selstart,d->selend);
1079 }
1080
view_zoomall(GtkMenuItem * menuitem,gpointer user_data)1081 static void view_zoomall(GtkMenuItem *menuitem, gpointer user_data)
1082 {
1083 Document *d;
1084 d = MAINWINDOW(user_data)->doc;
1085 document_set_view(d,0,d->chunk->length);
1086 }
1087
1088 #ifdef SHOW_DEBUG_MENU
debug_mark(GtkMenuItem * menuitem,gpointer user_data)1089 static void debug_mark(GtkMenuItem *menuitem, gpointer user_data)
1090 {
1091 /* MAINWINDOW(user_data)->changed = TRUE; */
1092 }
1093
dummy_proc(void * in,guint sample_size,chunk_writeout_func out_func,WriteoutID id,Dataformat * format)1094 static gboolean dummy_proc(void *in, guint sample_size,
1095 chunk_writeout_func out_func, WriteoutID id,
1096 Dataformat *format)
1097 {
1098 return out_func(id,in,sample_size);
1099 }
1100
debug_dummy(GtkMenuItem * menuitem,gpointer user_data)1101 static void debug_dummy(GtkMenuItem *menuitem, gpointer user_data)
1102 {
1103 Mainwindow *w = MAINWINDOW(user_data);
1104 document_apply(w->doc,dummy_proc,NULL,CHUNK_FILTER_MANY,FALSE,"DUMMY");
1105 }
1106
debug_dummy2(GtkMenuItem * menuitem,gpointer user_data)1107 static void debug_dummy2(GtkMenuItem *menuitem, gpointer user_data)
1108 {
1109 Mainwindow *w = MAINWINDOW(user_data);
1110 document_apply(w->doc,dummy_proc,NULL,CHUNK_FILTER_MANY,TRUE,"DUMMY");
1111 }
1112
checkoc_proc(Chunk * chunk,gpointer user_data)1113 static void checkoc_proc(Chunk *chunk, gpointer user_data)
1114 {
1115 if (chunk->opencount > 0)
1116 printf(_("Chunk %p has opencount=%d\n"),chunk,chunk->opencount);
1117 }
1118
debug_checkoc(GtkMenuItem * menuitem,gpointer user_data)1119 static void debug_checkoc(GtkMenuItem *menuitem, gpointer user_data)
1120 {
1121 puts("--------");
1122 chunk_foreach((GFunc)checkoc_proc,NULL);
1123 }
1124
dump_format(Dataformat * df)1125 static void dump_format(Dataformat *df)
1126 {
1127 printf("%d Channels @ %dHz ",df->channels,df->samplerate);
1128 if (df->type == DATAFORMAT_FLOAT) {
1129 if (df->samplesize <= sizeof(float)) {
1130 puts("float");
1131 } else
1132 puts("double");
1133 } else {
1134 printf("%d%c%c\n",df->samplesize,df->sign?'S':'U',
1135 df->bigendian?'B':'L');
1136 }
1137 }
1138
dump_dp(DataPart * dp)1139 static void dump_dp(DataPart *dp)
1140 {
1141 printf(" Datasource@%p, L/S=%Ld/%Ld Format: ",dp->ds,
1142 dp->ds->length,dp->ds->bytes);
1143 dump_format(&(dp->ds->format));
1144 printf(" Usage: %Ld + %Ld\n",dp->position,dp->length);
1145 switch (dp->ds->type) {
1146 case DATASOURCE_REAL:
1147 printf(" REAL @ %p\n",dp->ds->data.real);
1148 break;
1149 case DATASOURCE_VIRTUAL:
1150 printf(" VIRTUAL @ %s:%Ld\n",dp->ds->data.virtual.filename,
1151 dp->ds->data.virtual.offset);
1152 break;
1153 case DATASOURCE_TEMPFILE:
1154 printf(" TEMPFILE @ %s:%Ld\n",dp->ds->data.virtual.filename,
1155 dp->ds->data.virtual.offset);
1156 break;
1157 case DATASOURCE_SILENCE:
1158 puts(" SILENCE");
1159 break;
1160 case DATASOURCE_SNDFILE:
1161 printf(" SNDFILE @ %s:%Ld <rr:%c>\n",
1162 dp->ds->data.sndfile.filename, dp->ds->data.sndfile.pos,
1163 dp->ds->data.sndfile.raw_readable?'T':'F');
1164 break;
1165 case DATASOURCE_SNDFILE_TEMPORARY:
1166 printf(" SNDFILE @ %s:%Ld <rr:%c>\n",
1167 dp->ds->data.sndfile.filename, dp->ds->data.sndfile.pos,
1168 dp->ds->data.sndfile.raw_readable?'T':'F');
1169 break;
1170 case DATASOURCE_REF:
1171 printf(" REF --> %p\n",dp->ds->data.clone);
1172 break;
1173 case DATASOURCE_CLONE:
1174 printf(" CLONE --> %p\n",dp->ds->data.clone);
1175 break;
1176 case DATASOURCE_BYTESWAP:
1177 printf(" BYTESWAP --> %p\n",dp->ds->data.clone);
1178 break;
1179 }
1180 }
1181
dump_chunk(Chunk * c)1182 static void dump_chunk(Chunk *c)
1183 {
1184 printf(" Chunk@%p, L/S=%Ld/%Ld, Format: ",c,c->length,c->size);
1185 dump_format(&(c->format));
1186 puts(" Used datasources:");
1187 g_list_foreach(c->parts,(GFunc)dump_dp,NULL);
1188 }
1189
indirect_dump_chunk(Chunk ** cp)1190 static void indirect_dump_chunk(Chunk **cp)
1191 {
1192 dump_chunk(*cp);
1193 }
1194
windowinfo_proc(gpointer item,gpointer user_data)1195 static void windowinfo_proc(gpointer item, gpointer user_data)
1196 {
1197 struct HistoryEntry *he;
1198 Mainwindow *w = MAINWINDOW(item);
1199 printf(_("\nWindow '%s'\n"),w->doc->filename);
1200 puts(_(" Current chunk:"));
1201 dump_chunk(w->view->doc->chunk);
1202 puts(_(" History:"));
1203 he = w->doc->history_pos;
1204 if (he == NULL) {
1205 puts(" (empty)");
1206 } else {
1207 while (he->prev != NULL) he=he->prev;
1208 while (he != NULL) {
1209 dump_chunk(he->chunk);
1210 he=he->next;
1211 }
1212 }
1213 }
1214
debug_chunkinfo(GtkMenuItem * menuitem,gpointer user_data)1215 static void debug_chunkinfo(GtkMenuItem *menuitem, gpointer user_data)
1216 {
1217 list_object_foreach(mainwindow_objects,windowinfo_proc,NULL);
1218 }
1219
1220 #endif
1221
mainwindow_show_effect_dialog(Mainwindow * mw,gchar * effect_name)1222 static void mainwindow_show_effect_dialog(Mainwindow *mw, gchar *effect_name)
1223 {
1224 EffectBrowser *eb;
1225 eb = EFFECT_BROWSER(effect_browser_new_with_effect(mw->doc,effect_name,
1226 'B',
1227 (effect_name!=NULL)));
1228 gtk_widget_show(GTK_WIDGET(eb));
1229 }
1230
effects_volume(GtkMenuItem * menuitem,gpointer user_data)1231 static void effects_volume(GtkMenuItem *menuitem, gpointer user_data)
1232 {
1233 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"volume");
1234 }
1235
effects_speed(GtkMenuItem * menuitem,gpointer user_data)1236 static void effects_speed(GtkMenuItem *menuitem, gpointer user_data)
1237 {
1238 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"speed");
1239 }
1240
effects_samplerate(GtkMenuItem * menuitem,gpointer user_data)1241 static void effects_samplerate(GtkMenuItem *menuitem, gpointer user_data)
1242 {
1243 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"srate");
1244 }
1245
effects_samplesize(GtkMenuItem * menuitem,gpointer user_data)1246 static void effects_samplesize(GtkMenuItem *menuitem, gpointer user_data)
1247 {
1248 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"ssize");
1249 }
1250
effects_mixchannels(GtkMenuItem * menuitem,gpointer user_data)1251 static void effects_mixchannels(GtkMenuItem *menuitem, gpointer user_data)
1252 {
1253 Chunk *c;
1254 Mainwindow *w = MAINWINDOW(user_data);
1255 player_stop();
1256 if (w->doc->chunk->format.channels == 1)
1257 user_info(_("There already is only one channel!"));
1258 else {
1259 c = chunk_onechannel(w->doc->chunk,dither_editing,w->statusbar);
1260 if (c) document_update(w->doc,c,0,0);
1261 }
1262 }
1263
effects_splitchannel(GtkMenuItem * menuitem,gpointer user_data)1264 static void effects_splitchannel(GtkMenuItem *menuitem, gpointer user_data)
1265 {
1266 Mainwindow *w = MAINWINDOW (user_data);
1267 Chunk *c;
1268 c = chunk_copy_channel(w->doc->chunk,0,dither_editing,w->statusbar);
1269 if (c == NULL) return;
1270 player_stop();
1271 document_update(w->doc, c, 0, 0);
1272 }
1273
effects_mapchannels(GtkMenuItem * menuitem,gpointer user_data)1274 static void effects_mapchannels(GtkMenuItem *menuitem, gpointer user_data)
1275 {
1276 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"mapchannels");
1277 }
1278
edit_stop(GtkMenuItem * menu_item,gpointer user_data)1279 static void edit_stop(GtkMenuItem *menu_item, gpointer user_data)
1280 {
1281 Mainwindow *w = MAINWINDOW(user_data);
1282 if (playing_document == NULL) {
1283 if (w->doc->cursorpos != 0 || w->doc->chunk->length == 0)
1284 document_set_cursor(w->doc,0);
1285 else
1286 document_set_cursor(w->doc,w->doc->chunk->length);
1287 } else
1288 document_stop(w->doc, w->bouncemode);
1289 }
1290
1291
mainwindow_update_caches(void)1292 gboolean mainwindow_update_caches(void)
1293 {
1294 static guint last = 0;
1295 guint i,s;
1296 Mainwindow *wnd;
1297
1298 s = list_object_get_size(mainwindow_objects);
1299 if (s == 0) return FALSE;
1300 if (last >= s) last=0;
1301 i = last+1;
1302 while (1) {
1303 if (i >= s) i = 0;
1304 wnd = MAINWINDOW(list_object_get(mainwindow_objects, i));
1305 if (chunk_view_update_cache(wnd->view)) { last = i; return TRUE; }
1306 if (i == last) return FALSE;
1307 i++;
1308 }
1309 }
1310
edit_playselection(GtkMenuItem * menuitem,gpointer user_data)1311 static void edit_playselection(GtkMenuItem *menuitem, gpointer user_data)
1312 {
1313 Mainwindow *w = MAINWINDOW (user_data);
1314 document_play_selection(w->doc,w->loopmode,
1315 varispeed_reset_flag ? 1.0 : player_get_speed());
1316 }
1317
edit_playall(GtkMenuItem * menuitem,gpointer user_data)1318 static void edit_playall(GtkMenuItem *menuitem, gpointer user_data)
1319 {
1320 Mainwindow *w = MAINWINDOW (user_data);
1321 do_play(w,0,w->doc->chunk->length,w->loopmode);
1322 }
1323
get_help_page_contents(int page)1324 static gchar *get_help_page_contents(int page)
1325 {
1326 const char **c;
1327 char *ts[128];
1328 int i,j,k,l,x;
1329 gchar *r;
1330 c = help_page_contents[page];
1331 l = 0;
1332 for (i=0; c[i]!=NULL && i<128; i++) {
1333 ts[i] = gettext(c[i]);
1334 l += strlen(ts[i]);
1335 }
1336 r = g_malloc(l+1);
1337 k = 0;
1338 for (j=0; j<i; j++) {
1339 x = strlen(ts[j]);
1340 memcpy(r+k, ts[j], x);
1341 k += x;
1342 }
1343 r[k] = 0;
1344 g_assert(k==l);
1345 return r;
1346 }
1347
help_readme(GtkMenuItem * menuitem,gpointer user_data)1348 static void help_readme(GtkMenuItem *menuitem, gpointer user_data)
1349 {
1350 GtkAccelGroup* ag;
1351 GtkWidget *window,*table,*notebook,*frame,*label,*button,*box1,*box2;
1352 int i;
1353 GtkWidget *scrolledwindow1, *viewport1, *label2;
1354 gchar *c;
1355 #if GTK_MAJOR_VERSION == 2
1356 Mainwindow *mw = MAINWINDOW(user_data);
1357 PangoFontDescription *pfd;
1358 #endif
1359 ag = gtk_accel_group_new();
1360
1361 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1362
1363 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1364 gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER); // Centre the window
1365 gtk_window_set_default_size (GTK_WINDOW (window), -1, 400); // Make readable
1366 gtk_window_set_title (GTK_WINDOW (window), _("mhWaveEdit Help"));
1367
1368 box1 = gtk_vbox_new (FALSE, 0);
1369 gtk_container_add (GTK_CONTAINER (window), box1);
1370 gtk_widget_show (box1);
1371
1372 box2 = gtk_vbox_new (FALSE, 10);
1373 gtk_container_set_border_width (GTK_CONTAINER (box2), 1);
1374 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1375 gtk_widget_show (box2);
1376
1377 table = gtk_table_new (4, 6, FALSE);
1378 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
1379
1380 notebook = gtk_notebook_new ();
1381 gtk_table_attach_defaults (GTK_TABLE (table), notebook, 0, 6, 0, 1);
1382 gtk_widget_show (notebook);
1383
1384 for (i=0; i<help_page_count; i++)
1385 {
1386 frame = gtk_frame_new (NULL);
1387 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
1388 gtk_widget_show (frame);
1389
1390 scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
1391 gtk_widget_show (scrolledwindow1);
1392 gtk_container_add (GTK_CONTAINER (frame), scrolledwindow1);
1393 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
1394 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1395
1396 viewport1 = gtk_viewport_new (NULL, NULL);
1397 gtk_widget_show (viewport1);
1398 gtk_container_add (GTK_CONTAINER (scrolledwindow1), viewport1);
1399
1400 c = get_help_page_contents(i);
1401 label2 = gtk_label_new (c);
1402 g_free(c);
1403 #if GTK_MAJOR_VERSION == 2
1404 if (i==HELP_PAGE_SHORTCUTS) // Keyboard tab only
1405 {
1406 pfd = pango_font_description_copy_static(GTK_WIDGET(mw)->style->font_desc);
1407 pango_font_description_set_family_static(pfd, "Monospace");
1408 gtk_widget_modify_font(label2, pfd);
1409 pango_font_description_free(pfd);
1410 }
1411 #endif
1412 gtk_container_add (GTK_CONTAINER (viewport1), label2);
1413 GTK_WIDGET_SET_FLAGS (label2, GTK_CAN_FOCUS);
1414 gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
1415 gtk_label_set_line_wrap (GTK_LABEL (label2), TRUE);
1416 gtk_misc_set_alignment (GTK_MISC (label2), 0, 0);
1417 gtk_misc_set_padding (GTK_MISC (label2), 5, 5);
1418 gtk_widget_show (label2);
1419
1420
1421 label = gtk_label_new (_(help_page_titles[i]));
1422 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
1423 }
1424
1425 /* Show default page (defined in help.h) */
1426 #if GTK_MAJOR_VERSION == 1
1427 gtk_notebook_set_page (GTK_NOTEBOOK (notebook), HELP_PAGE_DEFAULT);
1428 #else
1429 gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook),HELP_PAGE_DEFAULT);
1430 #endif
1431 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
1432
1433 box2 = gtk_vbox_new (FALSE, 10);
1434 gtk_container_set_border_width (GTK_CONTAINER (box2), 1);
1435 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1436 gtk_widget_show (box2);
1437
1438 button = gtk_button_new_with_label (_("Close"));
1439 gtk_widget_add_accelerator (button, "clicked", ag, GDK_KP_Enter, 0,
1440 (GtkAccelFlags) 0);
1441 gtk_widget_add_accelerator (button, "clicked", ag, GDK_Return, 0,
1442 (GtkAccelFlags) 0);
1443 gtk_widget_add_accelerator (button, "clicked", ag, GDK_Escape, 0,
1444 (GtkAccelFlags) 0);
1445 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1446 gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
1447 (GtkSignalFunc)gtk_widget_destroy,
1448 GTK_OBJECT(window));
1449 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1450 gtk_widget_show (button);
1451
1452 gtk_widget_show (table);
1453 gtk_widget_show (window);
1454 gtk_window_add_accel_group(GTK_WINDOW (window), ag);
1455 }
1456
help_about(void)1457 static void help_about(void)
1458 {
1459 GtkAccelGroup* ag;
1460 gchar *p;
1461 GtkWidget *a,*b,*c;
1462 ag = gtk_accel_group_new();
1463 a = gtk_window_new(GTK_WINDOW_DIALOG);
1464 gtk_window_set_modal(GTK_WINDOW(a),TRUE);
1465 gtk_window_set_title(GTK_WINDOW(a),_("About mhWaveEdit"));
1466 gtk_container_set_border_width(GTK_CONTAINER(a),5);
1467 gtk_window_set_position (GTK_WINDOW (a), GTK_WIN_POS_CENTER); // Centre the window
1468 b = gtk_vbox_new(FALSE,10);
1469 gtk_container_add(GTK_CONTAINER(a),b);
1470 gtk_widget_show(b);
1471 c = gtk_label_new(PROGRAM_VERSION_STRING);
1472 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1473 gtk_widget_show(c);
1474 c = gtk_hseparator_new();
1475 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1476 gtk_widget_show(c);
1477 c = gtk_label_new(_("Created by Magnus Hjorth (magnus.hjorth@home.se)\n"
1478 "Copyright 2002-2018, Magnus Hjorth"));
1479 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1480 gtk_widget_show(c);
1481 c = gtk_hseparator_new();
1482 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1483 gtk_widget_show(c);
1484 p = g_strdup_printf(_("Current sound driver: %s"),sound_driver_name());
1485 c = gtk_label_new(p);
1486 g_free(p);
1487 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1488 gtk_widget_show(c);
1489 c = gtk_hseparator_new();
1490 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1491 gtk_widget_show(c);
1492 p = g_strdup_printf(_("Compiled %s %s"), BUILD_DATE, BUILD_TIME);
1493 c = gtk_label_new(p);
1494 g_free(p);
1495 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1496 gtk_widget_show(c);
1497 #ifdef USE_DOUBLE_SAMPLES
1498 c = gtk_label_new(_("Uses double-precision math"));
1499 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1500 gtk_widget_show(c);
1501 #endif
1502 c = gtk_hseparator_new();
1503 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1504 gtk_widget_show(c);
1505 c = gtk_label_new(_("Distributed under GNU General Public License.\n"
1506 "For information, see the file COPYING"));
1507 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1508 gtk_widget_show(c);
1509 c = gtk_button_new_with_label(_("OK"));
1510 gtk_widget_add_accelerator (c, "clicked", ag, GDK_KP_Enter, 0, (GtkAccelFlags) 0);
1511 gtk_widget_add_accelerator (c, "clicked", ag, GDK_Return, 0, (GtkAccelFlags) 0);
1512 gtk_widget_add_accelerator (c, "clicked", ag, GDK_Escape, 0, (GtkAccelFlags) 0);
1513 gtk_signal_connect_object(GTK_OBJECT(c),"clicked",
1514 (GtkSignalFunc)gtk_widget_destroy,GTK_OBJECT(a));
1515 gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1516 gtk_widget_show(c);
1517
1518 gtk_widget_show(a);
1519 gtk_window_add_accel_group(GTK_WINDOW (a), ag);
1520 }
1521
edit_play(GtkMenuItem * menuitem,gpointer user_data)1522 static void edit_play(GtkMenuItem *menuitem, gpointer user_data)
1523 {
1524 Mainwindow *w = MAINWINDOW (user_data);
1525 do_play(w,w->doc->cursorpos,w->doc->chunk->length,w->loopmode);
1526 }
1527
edit_selstartcursor(GtkMenuItem * menuitem,gpointer user_data)1528 static void edit_selstartcursor(GtkMenuItem *menuitem, gpointer user_data)
1529 {
1530 Mainwindow *w = MAINWINDOW(user_data);
1531 if (w->doc->selstart == w->doc->selend)
1532 document_set_selection(w->doc,w->doc->cursorpos,
1533 w->doc->chunk->length);
1534 else
1535 document_set_selection(w->doc,w->doc->cursorpos,w->doc->selend);
1536 }
1537
edit_selendcursor(GtkMenuItem * menuitem,gpointer user_data)1538 static void edit_selendcursor(GtkMenuItem *menuitem, gpointer user_data)
1539 {
1540 Mainwindow *w = MAINWINDOW(user_data);
1541 if (w->doc->selstart == w->doc->selend)
1542 document_set_selection(w->doc,0,w->doc->cursorpos+1);
1543 else
1544 document_set_selection(w->doc,w->doc->selstart,w->doc->cursorpos);
1545 }
1546
edit_record(GtkMenuItem * menuitem,gpointer user_data)1547 static void edit_record(GtkMenuItem *menuitem, gpointer user_data)
1548 {
1549 Mainwindow *wnd = MAINWINDOW (user_data);
1550 Chunk *c;
1551 int noverruns, i;
1552 off_t overrun_locs[10];
1553 gchar s[2], *str;
1554 player_stop();
1555 c = record_dialog_execute(&noverruns, overrun_locs);
1556 if (c) {
1557 wnd = mainwindow_set_chunk(wnd,c,NULL);
1558 if (noverruns > 0) {
1559 for (i=0; i<noverruns && i<10; i++) {
1560 s[0] = '0'+i;
1561 s[1] = 0;
1562 document_set_mark(wnd->doc, s,
1563 overrun_locs[i]/c->format.samplebytes);
1564 }
1565 str = g_strdup_printf
1566 ("%d overruns where detected while recording. "
1567 "This means the recording may be damaged. The "
1568 "locations where the overruns happened have been "
1569 "indicated with markers.",noverruns);
1570 user_warning(str);
1571 g_free(str);
1572 }
1573 }
1574 }
1575
edit_preferences(GtkMenuItem * menuitem,gpointer user_data)1576 static void edit_preferences(GtkMenuItem *menuitem, gpointer user_data)
1577 {
1578 gtk_widget_show(config_dialog_new());
1579 }
1580
effects_combinechannels(GtkMenuItem * menuitem,gpointer user_data)1581 static void effects_combinechannels(GtkMenuItem *menuitem, gpointer user_data)
1582 {
1583 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"combine");
1584 }
1585
effects_sandwich(GtkMenuItem * menuitem,gpointer user_data)1586 static void effects_sandwich(GtkMenuItem *menuitem, gpointer user_data)
1587 {
1588 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"sandwich");
1589 }
1590
view_timescale(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1591 static void view_timescale(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1592 {
1593 Mainwindow *w = MAINWINDOW ( user_data );
1594 chunk_view_set_timescale(w->view, checkmenuitem->active);
1595 }
1596
view_horizoom(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1597 static void view_horizoom(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1598 {
1599 Mainwindow *w = MAINWINDOW ( user_data );
1600 if (w->hzoom_icon == NULL) return;
1601 if (checkmenuitem->active) {
1602 gtk_widget_show(w->hzoom_icon);
1603 gtk_widget_show(w->hzoom_slider);
1604 } else {
1605 gtk_widget_hide(w->hzoom_icon);
1606 gtk_widget_hide(w->hzoom_slider);
1607 }
1608 }
1609
view_vertzoom(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1610 static void view_vertzoom(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1611 {
1612 Mainwindow *w = MAINWINDOW ( user_data );
1613 if (w->vzoom_icon == NULL) return;
1614 if (checkmenuitem->active) {
1615 gtk_widget_show(w->vzoom_icon);
1616 gtk_widget_show(w->vzoom_slider);
1617 gtk_widget_show(GTK_WIDGET(w->vzoom_label));
1618 } else {
1619 gtk_widget_hide(w->vzoom_icon);
1620 gtk_widget_hide(w->vzoom_slider);
1621 gtk_widget_hide(GTK_WIDGET(w->vzoom_label));
1622 }
1623 }
1624
view_speed(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1625 static void view_speed(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1626 {
1627 Mainwindow *w = MAINWINDOW(user_data);
1628 if (w->speed_icon == NULL) return;
1629 if (checkmenuitem->active) {
1630 gtk_widget_show(w->speed_icon);
1631 gtk_widget_show(w->speed_slider);
1632 if (w->show_labels) gtk_widget_show(GTK_WIDGET(w->speed_label));
1633 } else {
1634 gtk_widget_hide(w->speed_icon);
1635 gtk_widget_hide(w->speed_slider);
1636 gtk_widget_hide(GTK_WIDGET(w->speed_label));
1637 }
1638 }
1639
view_sliderlabels(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1640 static void view_sliderlabels(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1641 {
1642 Mainwindow *w = MAINWINDOW(user_data);
1643 w->show_labels = checkmenuitem->active;
1644 if (w->vzoom_slider == NULL) return;
1645 if (w->show_labels) {
1646 if (GTK_WIDGET_VISIBLE(w->vzoom_slider))
1647 gtk_widget_show(GTK_WIDGET(w->vzoom_label));
1648 if (GTK_WIDGET_VISIBLE(w->speed_slider))
1649 gtk_widget_show(GTK_WIDGET(w->speed_label));
1650 } else {
1651 gtk_widget_hide(GTK_WIDGET(w->vzoom_label));
1652 gtk_widget_hide(GTK_WIDGET(w->speed_label));
1653 }
1654 }
1655
view_bufpos(GtkCheckMenuItem * checkmenuitem,gpointer user_data)1656 static void view_bufpos(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
1657 {
1658 Mainwindow *w = MAINWINDOW(user_data);
1659 w->view->show_bufpos = checkmenuitem->active;
1660 gtk_widget_queue_draw(GTK_WIDGET(w->view));
1661 }
1662
edit_insertsilence(GtkMenuItem * menuitem,gpointer user_data)1663 static void edit_insertsilence(GtkMenuItem *menuitem, gpointer user_data)
1664 {
1665 Mainwindow *w = MAINWINDOW ( user_data );
1666 gfloat f;
1667 off_t cp;
1668 Chunk *c,*nc;
1669 if (user_input_float(_("Seconds of silence: "),_("Insert Silence"),0.0,
1670 GTK_WINDOW(w),&f))
1671 return;
1672 if (f<=0.0) return;
1673 c = chunk_new_silent(&(w->doc->chunk->format),f);
1674 nc = chunk_insert(w->doc->chunk, c, w->doc->cursorpos);
1675 cp = w->doc->cursorpos;
1676 document_update(w->doc,nc,cp,c->length);
1677 document_set_selection( w->doc, cp, cp + c->length );
1678 gtk_object_sink(GTK_OBJECT(c));
1679 }
1680
edit_clearclipboard(GtkMenuItem * menuitem,gpointer user_data)1681 static void edit_clearclipboard(GtkMenuItem *menuitem, gpointer user_data)
1682 {
1683 gtk_object_unref(GTK_OBJECT(clipboard));
1684 clipboard = NULL;
1685 list_object_foreach(mainwindow_objects,
1686 (GFunc)update_clipboard_items, NULL);
1687 }
1688
edit_positioncursor(GtkMenuItem * menuitem,gpointer user_data)1689 static void edit_positioncursor(GtkMenuItem *menuitem, gpointer user_data)
1690 {
1691 gtk_widget_show(goto_dialog_new(MAINWINDOW(user_data)));
1692 }
1693
effects_normalize_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1694 static Chunk *effects_normalize_proc(Chunk *chunk, StatusBar *bar,
1695 gpointer user_data)
1696 {
1697 sample_t s;
1698 Chunk *c;
1699 gfloat *lp = (gfloat *)user_data;
1700 sample_t level = (lp == NULL) ? 1.0 : *lp;
1701 s = chunk_peak_level(chunk,bar);
1702 if (s < 0.0) return NULL;
1703 c = chunk_amplify(chunk,level/s,dither_editing,bar);
1704 return c;
1705 }
1706
effects_normalize(GtkMenuItem * menuitem,gpointer user_data)1707 static void effects_normalize(GtkMenuItem *menuitem, gpointer user_data)
1708 {
1709 document_apply_cb(MAINWINDOW(user_data)->doc,effects_normalize_proc,
1710 TRUE,NULL);
1711 }
1712
effects_normalizeto(GtkMenuItem * menuitem,gpointer user_data)1713 static void effects_normalizeto(GtkMenuItem *menuitem, gpointer user_data)
1714 {
1715 gboolean b;
1716 gfloat val;
1717 val = inifile_get_gfloat("lastNormLevel",1.0);
1718 b = user_input_float(_("Level: "),_("Normalize to..."),val,
1719 GTK_WINDOW(user_data),&val);
1720 if (b) return;
1721 b = document_apply_cb(MAINWINDOW(user_data)->doc,effects_normalize_proc,
1722 TRUE,&val);
1723 if (b) return;
1724 inifile_set_gfloat("lastNormLevel",val);
1725 }
1726
1727
effects_pipe(GtkMenuItem * menuitem,gpointer user_data)1728 static void effects_pipe(GtkMenuItem *menuitem, gpointer user_data)
1729 {
1730 mainwindow_show_effect_dialog(MAINWINDOW(user_data),"pipe");
1731 }
1732
cursor_moveto_beginning(GtkMenuItem * menuitem,gpointer user_data)1733 static void cursor_moveto_beginning(GtkMenuItem *menuitem, gpointer user_data)
1734 {
1735 document_set_cursor(MAINWINDOW(user_data)->doc,0);
1736 }
1737
cursor_moveto_end(GtkMenuItem * menuitem,gpointer user_data)1738 static void cursor_moveto_end(GtkMenuItem *menuitem, gpointer user_data)
1739 {
1740 Mainwindow *w = MAINWINDOW(user_data);
1741 document_set_cursor(w->doc,w->doc->chunk->length);
1742 }
1743
cursor_moveto_selstart(GtkMenuItem * menuitem,gpointer user_data)1744 static void cursor_moveto_selstart(GtkMenuItem *menuitem, gpointer user_data)
1745 {
1746 Mainwindow *w = MAINWINDOW(user_data);
1747 document_set_cursor(w->doc,w->doc->selstart);
1748 }
1749
cursor_moveto_selend(GtkMenuItem * menuitem,gpointer user_data)1750 static void cursor_moveto_selend(GtkMenuItem *menuitem, gpointer user_data)
1751 {
1752 Mainwindow *w = MAINWINDOW(user_data);
1753 document_set_cursor(w->doc,w->doc->selend);
1754 }
1755
cursor_move_left(GtkMenuItem * menuitem,gpointer user_data)1756 static void cursor_move_left(GtkMenuItem *menuitem, gpointer user_data)
1757 {
1758 off_t delta;
1759 Mainwindow *w = MAINWINDOW(user_data);
1760
1761 delta =
1762 - ((w->doc->viewend - w->doc->viewstart)/MAINWINDOW_NUDGE_DELTA_RATIO);
1763
1764 if(delta > -1) {
1765 delta = -1;
1766 }
1767
1768 document_nudge_cursor(w->doc,delta);
1769 }
1770
cursor_move_right(GtkMenuItem * menuitem,gpointer user_data)1771 static void cursor_move_right(GtkMenuItem *menuitem, gpointer user_data)
1772 {
1773 off_t delta;
1774 Mainwindow *w = MAINWINDOW(user_data);
1775
1776 delta =
1777 ((w->doc->viewend - w->doc->viewstart)/MAINWINDOW_NUDGE_DELTA_RATIO);
1778
1779 if(delta < 1) {
1780 delta = 1;
1781 }
1782
1783 document_nudge_cursor(w->doc,delta);
1784 }
1785
cursor_move_leftsample(GtkMenuItem * menuitem,gpointer user_data)1786 static void cursor_move_leftsample(GtkMenuItem *menuitem, gpointer user_data)
1787 {
1788 Mainwindow *w = MAINWINDOW(user_data);
1789 document_nudge_cursor(w->doc,-1);
1790 }
1791
cursor_move_rightsample(GtkMenuItem * menuitem,gpointer user_data)1792 static void cursor_move_rightsample(GtkMenuItem *menuitem, gpointer user_data)
1793 {
1794 Mainwindow *w = MAINWINDOW(user_data);
1795 document_nudge_cursor(w->doc,1);
1796 }
1797
cursor_findzerocrossing_leftall(GtkMenuItem * menuitem,gpointer user_data)1798 static void cursor_findzerocrossing_leftall(GtkMenuItem *menuitem,
1799 gpointer user_data)
1800 {
1801 Mainwindow *w = MAINWINDOW(user_data);
1802 off_t newpos;
1803
1804 newpos = chunk_zero_crossing_all_reverse(
1805 w->doc->chunk,w->statusbar,w->doc->cursorpos);
1806
1807 if(newpos >= 0) {
1808 document_set_cursor(w->doc,newpos);
1809 }
1810 }
1811
cursor_findzerocrossing_rightall(GtkMenuItem * menuitem,gpointer user_data)1812 static void cursor_findzerocrossing_rightall(GtkMenuItem *menuitem,
1813 gpointer user_data)
1814 {
1815 Mainwindow *w = MAINWINDOW(user_data);
1816 off_t newpos;
1817
1818 newpos = chunk_zero_crossing_all_forward(
1819 w->doc->chunk,w->statusbar,w->doc->cursorpos);
1820
1821 if(newpos >= 0) {
1822 document_set_cursor(w->doc,newpos);
1823 }
1824 }
1825
cursor_findzerocrossing_leftany(GtkMenuItem * menuitem,gpointer user_data)1826 static void cursor_findzerocrossing_leftany(GtkMenuItem *menuitem,
1827 gpointer user_data)
1828 {
1829 Mainwindow *w = MAINWINDOW(user_data);
1830 off_t newpos;
1831
1832 newpos = chunk_zero_crossing_any_reverse(
1833 w->doc->chunk,w->statusbar,w->doc->cursorpos);
1834
1835 if(newpos >= 0) {
1836 document_set_cursor(w->doc,newpos);
1837 }
1838 }
1839
cursor_findzerocrossing_rightany(GtkMenuItem * menuitem,gpointer user_data)1840 static void cursor_findzerocrossing_rightany(GtkMenuItem *menuitem,
1841 gpointer user_data)
1842 {
1843 Mainwindow *w = MAINWINDOW(user_data);
1844 off_t newpos;
1845
1846 newpos = chunk_zero_crossing_any_forward(
1847 w->doc->chunk,w->statusbar,w->doc->cursorpos);
1848
1849 if(newpos >= 0) {
1850 document_set_cursor(w->doc,newpos);
1851 }
1852 }
1853
byteswap_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1854 static Chunk *byteswap_proc(Chunk *chunk, StatusBar *bar,
1855 gpointer user_data)
1856 {
1857 return chunk_byteswap(chunk);
1858 }
1859
effects_byteswap(GtkMenuItem * menuitem,gpointer user_data)1860 static void effects_byteswap(GtkMenuItem *menuitem, gpointer user_data)
1861 {
1862 document_apply_cb(MAINWINDOW(user_data)->doc,byteswap_proc,TRUE,NULL);
1863 }
1864
fadein_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1865 static Chunk *fadein_proc(Chunk *chunk, StatusBar *bar, gpointer user_data)
1866 {
1867 return chunk_volume_ramp(chunk,0.0,1.0,dither_editing,bar);
1868 }
1869
fadeout_proc(Chunk * chunk,StatusBar * bar,gpointer user_data)1870 static Chunk *fadeout_proc(Chunk *chunk, StatusBar *bar, gpointer user_data)
1871 {
1872 return chunk_volume_ramp(chunk,1.0,0.0,dither_editing,bar);
1873 }
1874
effects_fadein(GtkMenuItem * menuitem,gpointer user_data)1875 static void effects_fadein(GtkMenuItem *menuitem, gpointer user_data)
1876 {
1877 document_apply_cb(MAINWINDOW(user_data)->doc,fadein_proc,TRUE,NULL);
1878 }
1879
effects_fadeout(GtkMenuItem * menuitem,gpointer user_data)1880 static void effects_fadeout(GtkMenuItem *menuitem, gpointer user_data)
1881 {
1882 document_apply_cb(MAINWINDOW(user_data)->doc,fadeout_proc,TRUE,NULL);
1883 }
1884
effects_dialog(GtkMenuItem * menuitem,gpointer user_data)1885 static void effects_dialog(GtkMenuItem *menuitem, gpointer user_data)
1886 {
1887 mainwindow_show_effect_dialog(MAINWINDOW(user_data),NULL);
1888 }
1889
file_recent(GtkMenuItem * menuitem,gpointer user_data)1890 static void file_recent(GtkMenuItem *menuitem, gpointer user_data)
1891 {
1892 Mainwindow *w = MAINWINDOW(user_data);
1893 Document *doc;
1894 gchar *fn;
1895 GList *l = w->recent;
1896 GList *m = recent_filenames;
1897 while (l->data != menuitem) { l=l->next; m=m->next; }
1898 fn = g_strdup((gchar *)m->data);
1899 doc = document_new_with_file(fn, w->statusbar);
1900 if (doc == NULL) { g_free(fn); return; }
1901 mainwindow_set_document(w, doc, fn);
1902 inifile_set("lastOpenFile",fn);
1903 recent_file(fn);
1904 g_free(fn);
1905 }
1906
translate_menu_path(const gchar * path,gpointer func_data)1907 static gchar *translate_menu_path(const gchar *path, gpointer func_data)
1908 {
1909 return _(path);
1910 }
1911
xgtk_item_factory_get_item(GtkItemFactory * itemf,gchar * caption)1912 static GtkWidget *xgtk_item_factory_get_item(GtkItemFactory *itemf,
1913 gchar *caption)
1914 {
1915 GtkWidget *w;
1916 w = gtk_item_factory_get_item(itemf,caption);
1917 g_assert(w != NULL);
1918 return w;
1919 }
1920
create_menu(Mainwindow * w)1921 static GtkWidget *create_menu(Mainwindow *w)
1922 {
1923 guint i,j;
1924 GtkWidget *item;
1925 GtkItemFactoryEntry entry = {};
1926
1927 GtkItemFactoryEntry menu_items1[] = {
1928 { N_("/_File"), NULL, NULL, 0, "<Branch>" },
1929 { N_("/File/_Open..."), "<control>O", file_open, 0, NULL },
1930 { N_("/File/_Save"), "<control>S", file_save, 0, NULL },
1931 { N_("/File/Save _as..."),NULL, file_saveas, 0, NULL },
1932 {N_("/File/Save selection as..."),"<control>U",file_saveselection,0,NULL},
1933 { N_("/_Edit"), NULL, NULL, 0, "<Branch>" },
1934 { N_("/Edit/_Undo"), "<control>Z", edit_undo, 0, NULL },
1935 { N_("/Edit/_Redo"), "<shift><control>Z", edit_redo, 0, NULL },
1936 { N_("/Edit/sep1"), NULL, NULL, 0, "<Separator>" },
1937 { N_("/Edit/Cu_t"), "<control>X", edit_cut, 0, NULL },
1938 { N_("/Edit/_Copy"), "<control>C", edit_copy, 0, NULL },
1939 { N_("/Edit/_Paste"), "<control>V", edit_paste, 0, NULL },
1940 { N_("/Edit/Paste _over"),NULL, edit_pasteover, 0, NULL },
1941 { N_("/Edit/_Mix paste"),NULL, edit_mixpaste, 0, NULL },
1942 { N_("/Edit/Insert _silence"),NULL, edit_insertsilence,0,NULL },
1943 { N_("/Edit/Paste to _new"),NULL, edit_pastetonew,0, NULL },
1944 { N_("/Edit/Cr_op"), NULL, edit_crop, 0, NULL },
1945 { N_("/Edit/_Delete"), "<control>D", edit_delete, 0, NULL },
1946 { N_("/Edit/Silence selection"),NULL,edit_silence, 0, NULL },
1947 { N_("/Edit/sep2"), NULL, NULL, 0, "<Separator>" },
1948 { N_("/Edit/Select _all"),"<control>A",edit_selectall,0, NULL },
1949 { N_("/Edit/Select none"),NULL,edit_selectnone,0, NULL },
1950 { N_("/Edit/sep3"), NULL, NULL, 0, "<Separator>" },
1951 { N_("/Edit/Clear clipboard"),NULL, edit_clearclipboard,0,NULL },
1952 { N_("/Edit/sep4"), NULL, NULL, 0, "<Separator>" },
1953 { N_("/Edit/Preferences"),"<control>P", edit_preferences,0,NULL },
1954 { N_("/_View"), NULL, NULL, 0, "<Branch>" },
1955 { N_("/View/Zoom _in"), NULL, view_zoomin, 0, NULL },
1956 { N_("/View/Zoom _out"),NULL, view_zoomout, 0, NULL },
1957 { N_("/View/Zoom to _selection"),NULL,view_zoomtoselection,0,NULL },
1958 { N_("/View/sep1"), NULL, NULL, 0, "<Separator>" },
1959 { N_("/View/Zoom _all"),NULL, view_zoomall, 0, NULL },
1960 { N_("/View/sep2"), NULL, NULL, 0, "<Separator>" },
1961 { N_("/View/_Time scale"),NULL, view_timescale, 0, "<CheckItem>" },
1962 { N_("/View/_Horizontal zoom"),NULL, view_horizoom, 0, "<CheckItem>" },
1963 { N_("/View/_Vertical zoom"),NULL, view_vertzoom, 0, "<CheckItem>" },
1964 { N_("/View/Sp_eed slider"),NULL, view_speed, 0, "<CheckItem>" },
1965 { N_("/View/Slider labels"),NULL, view_sliderlabels,0,"<CheckItem>"},
1966 { N_("/View/Buffer position"),NULL, view_bufpos, 0, "<CheckItem>" },
1967 { N_("/_Cursor"), NULL, NULL, 0, "<Branch>" },
1968 {N_("/Cursor/Set selection start"),"<control>Q",edit_selstartcursor,0,
1969 NULL},
1970 { N_("/Cursor/Set selection end"),"<control>W",edit_selendcursor,0,NULL},
1971 { N_("/Cursor/sep1"), NULL, NULL, 0, "<Separator>" },
1972 { N_("/Cursor/Move to"), NULL, NULL, 0, "<Branch>" },
1973 { N_("/Cursor/Move to/Beginning"),"<control>H",cursor_moveto_beginning,0,
1974 NULL},
1975 { N_("/Cursor/Move to/End"),"<control>J",cursor_moveto_end, 0, NULL },
1976 { N_("/Cursor/Move to/Selection start"),"<control>K",
1977 cursor_moveto_selstart,0,NULL},
1978 { N_("/Cursor/Move to/Selection end"),"<control>L",
1979 cursor_moveto_selend,0,NULL},
1980 { N_("/Cursor/Move"), NULL, NULL, 0, "<Branch>" },
1981 { N_("/Cursor/Move/Left"),"H",cursor_move_left,0,NULL},
1982 { N_("/Cursor/Move/Right"),"J",cursor_move_right,0,NULL},
1983 { N_("/Cursor/Move/Left sample"),"K",cursor_move_leftsample,0,NULL},
1984 { N_("/Cursor/Move/Right sample"),"L",cursor_move_rightsample,0,NULL},
1985 { N_("/Cursor/Find zero-crossing"),NULL,NULL,0,"<Branch>"},
1986 { N_("/Cursor/Find zero-crossing/Left (all channels)"),"Y",
1987 cursor_findzerocrossing_leftall,0,NULL},
1988 { N_("/Cursor/Find zero-crossing/Right (all channels)"),"U",
1989 cursor_findzerocrossing_rightall,0,NULL},
1990 { N_("/Cursor/Find zero-crossing/Left (any channel)"),"I",
1991 cursor_findzerocrossing_leftany,0,NULL},
1992 { N_("/Cursor/Find zero-crossing/Right (any channel)"),"O",
1993 cursor_findzerocrossing_rightany,0,NULL},
1994 { N_("/Cursor/sep2"), NULL, NULL, 0, "<Separator>" },
1995 { N_("/Cursor/Position cursor..."),"<control>G",edit_positioncursor,0,
1996 NULL},
1997 { N_("/_Play"), NULL, NULL, 0, "<Branch>" },
1998 { N_("/Play/_Play from cursor"),NULL, edit_play, 0, NULL },
1999 { N_("/Play/Play _all"),NULL, edit_playall, 0, NULL },
2000 { N_("/Play/Play se_lection"),NULL, edit_playselection,0,NULL },
2001 { N_("/Play/_Stop"), NULL, edit_stop, 0, NULL },
2002 { N_("/Play/sep1"), NULL, NULL, 0, "<Separator>" },
2003 { N_("/Play/_Record..."), "F12", edit_record, 0, NULL },
2004 { N_("/Effec_ts"), NULL, NULL, 0, "<Branch>" },
2005 { N_("/Effects/Fade _in"),NULL, effects_fadein, 0, NULL },
2006 { N_("/Effects/Fade o_ut"),NULL, effects_fadeout,0, NULL },
2007 { N_("/Effects/_Normalize"),"<control>N",effects_normalize,0, NULL },
2008 { N_("/Effects/Normali_ze to..."),NULL,effects_normalizeto,0,NULL },
2009 { N_("/Effects/_Volume adjust (fade)..."),NULL,effects_volume,0,NULL },
2010 { N_("/Effects/sep1"), NULL, NULL, 0, "<Separator>" },
2011 { N_("/Effects/Convert sample_rate..."),NULL,effects_samplerate,0,NULL },
2012 { N_("/Effects/Convert sample _format..."),NULL,effects_samplesize,0,
2013 NULL},
2014 { N_("/Effects/B_yte swap"),NULL, effects_byteswap,0,NULL },
2015 { N_("/Effects/sep2"), NULL, NULL, 0, "<Separator>" },
2016 { N_("/Effects/_Mix to mono"),NULL,effects_mixchannels,0,NULL },
2017 { N_("/Effects/Add channe_l"),NULL,effects_splitchannel,0,NULL },
2018 { N_("/Effects/Ma_p channels..."),NULL,effects_mapchannels,0,NULL },
2019 {N_("/Effects/_Combine channels..."),NULL,effects_combinechannels,0,NULL},
2020 { N_("/Effects/Add channels from other file..."),NULL,effects_sandwich,0,NULL},
2021 { N_("/Effects/sep3"), NULL, NULL, 0, "<Separator>" },
2022 { N_("/Effects/_Speed adjustment..."),NULL,effects_speed, 0, NULL },
2023 { N_("/Effects/Pipe through program..."),NULL,effects_pipe,0,NULL },
2024 { N_("/Effects/sep4"), NULL, NULL, 0, "<Separator>" },
2025 { N_("/Effects/Effects dialog..."),"<control>E",effects_dialog,0,NULL },
2026 #ifdef SHOW_DEBUG_MENU
2027 { N_("/Debug"), NULL, NULL, 0, "<Branch>" },
2028 /* { N_("/Debug/Mark as modified"),NULL, debug_mark, 0, NULL }, */
2029 { N_("/Debug/Dummy effect"),NULL, debug_dummy, 0, NULL },
2030 { N_("/Debug/Dummy effect FP"),NULL, debug_dummy2, 0, NULL },
2031 { N_("/Debug/Check opencount"),NULL, debug_checkoc, 0, NULL },
2032 { N_("/Debug/Dump chunk info"),NULL, debug_chunkinfo,0, NULL },
2033 #endif
2034 { N_("/_Help"), NULL, NULL, 0, "<LastBranch>"},
2035 { N_("/Help/_Documentation"),"F1", help_readme, 0, NULL },
2036 { N_("/Help/_About"), NULL, help_about, 0, NULL }
2037 };
2038
2039 GtkItemFactoryEntry menu_items2[] = {
2040 { N_("/File/sep1"), NULL, NULL, 0, "<Separator>" },
2041 { N_("/File/_Close"), NULL, file_close, 0, NULL },
2042 { N_("/File/sep2"), NULL, NULL, 0, "<Separator>" },
2043 { N_("/File/_Exit"), NULL, file_exit, 0, NULL }
2044 };
2045
2046 gchar *need_chunk_names[] = {
2047 "/File/Save", "/File/Save as...",
2048 "/Edit/Insert silence",
2049 "/Edit/Select all", "/Cursor", "/View", "/Play/Play from cursor",
2050 "/Play/Play all", "/Play/Stop", "/Effects",
2051 "/Effects/Normalize",
2052 "/Effects/Effects dialog...",
2053 "/Edit/Select none"
2054 };
2055
2056 gchar *need_selection_names[] = {
2057 "/Edit/Cut", "/Edit/Copy", "/Edit/Delete", "/Edit/Crop",
2058 "/Edit/Silence selection",
2059 "/View/Zoom to selection", "/File/Save selection as...",
2060 "/Play/Play selection"
2061 };
2062
2063 gchar *need_clipboard_names[] = {
2064 "/Edit/Paste", "/Edit/Paste over", "/Edit/Mix paste",
2065 "/Edit/Paste to new", "/Edit/Clear clipboard"
2066 };
2067
2068 GtkAccelGroup *accel_group;
2069 GtkItemFactory *item_factory;
2070
2071 accel_group = gtk_accel_group_new();
2072 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR,"<main>",
2073 accel_group);
2074
2075 #ifdef ENABLE_NLS
2076 gtk_item_factory_set_translate_func(item_factory,
2077 translate_menu_path, NULL, NULL);
2078 #endif
2079
2080 gtk_item_factory_create_items_ac(item_factory,ARRAY_LENGTH(menu_items1),
2081 menu_items1,w,2);
2082 w->recent = NULL;
2083 j = inifile_get_guint32("recentFiles",4);
2084 if (j > MAINWINDOW_RECENT_MAX) j=4;
2085 if (j > 0) {
2086 entry.path = "/File/sep3";
2087 entry.item_type = "<Separator>";
2088 entry.callback = NULL;
2089 gtk_item_factory_create_item(item_factory,&entry,w,2);
2090 item = gtk_item_factory_get_item(item_factory,entry.path);
2091 }
2092 for (i=1; i<=j; i++) {
2093 entry.item_type = NULL;
2094 entry.path = g_strdup_printf("/File/Last%d",i);
2095 entry.callback = (GtkItemFactoryCallback)file_recent;
2096 gtk_item_factory_create_item(item_factory,&entry,w,2);
2097 item = gtk_item_factory_get_item(item_factory,entry.path);
2098 w->recent = g_list_append(w->recent, item);
2099 gtk_widget_set_sensitive(item,FALSE);
2100 g_free(entry.path);
2101 }
2102 gtk_item_factory_create_items_ac(item_factory,ARRAY_LENGTH(menu_items2),
2103 menu_items2,w,2);
2104 gtk_window_add_accel_group(GTK_WINDOW(w),accel_group);
2105
2106 for (i=0; i<ARRAY_LENGTH(need_chunk_names); i++)
2107 w->need_chunk_items =
2108 g_list_append(w->need_chunk_items,xgtk_item_factory_get_item(
2109 item_factory,need_chunk_names[i]));
2110
2111 for (i=0; i<ARRAY_LENGTH(need_selection_names); i++)
2112 w->need_selection_items =
2113 g_list_append(w->need_selection_items,
2114 xgtk_item_factory_get_item(
2115 item_factory,need_selection_names[i]));
2116
2117 for (i=0; i<ARRAY_LENGTH(need_clipboard_names); i++)
2118 w->need_clipboard_items =
2119 g_list_append(w->need_clipboard_items,
2120 xgtk_item_factory_get_item(
2121 item_factory,need_clipboard_names[i]));
2122
2123 w->need_undo_items =
2124 g_list_append(w->need_undo_items,gtk_item_factory_get_item
2125 (item_factory,"/Edit/Undo") );
2126 w->need_redo_items =
2127 g_list_append(w->need_redo_items,
2128 xgtk_item_factory_get_item(item_factory,"/Edit/Redo"));
2129
2130 update_file_recent(w);
2131
2132 item = gtk_item_factory_get_item(item_factory,"/View/Zoom in");
2133 w->zoom_items = g_list_append(w->zoom_items,item);
2134 item = gtk_item_factory_get_item(item_factory,"/View/Zoom out");
2135 w->zoom_items = g_list_append(w->zoom_items,item);
2136
2137 item = gtk_item_factory_get_item(item_factory,"/View/Time scale");
2138 gtk_check_menu_item_set_active(
2139 GTK_CHECK_MENU_ITEM(item),
2140 inifile_get_gboolean(INI_SETTING_TIMESCALE,
2141 INI_SETTING_TIMESCALE_DEFAULT));
2142
2143 item = gtk_item_factory_get_item(item_factory,"/View/Horizontal zoom");
2144 gtk_check_menu_item_set_active
2145 (GTK_CHECK_MENU_ITEM(item),
2146 inifile_get_gboolean(INI_SETTING_HZOOM,INI_SETTING_HZOOM_DEFAULT));
2147
2148 item = gtk_item_factory_get_item(item_factory,"/View/Vertical zoom");
2149 gtk_check_menu_item_set_active
2150 (GTK_CHECK_MENU_ITEM(item),
2151 inifile_get_gboolean(INI_SETTING_VZOOM,INI_SETTING_VZOOM_DEFAULT));
2152
2153 item = gtk_item_factory_get_item(item_factory,"/View/Speed slider");
2154 gtk_check_menu_item_set_active
2155 (GTK_CHECK_MENU_ITEM(item),
2156 inifile_get_gboolean(INI_SETTING_SPEED,INI_SETTING_SPEED_DEFAULT));
2157
2158 item = gtk_item_factory_get_item(item_factory,"/View/Slider labels");
2159 gtk_check_menu_item_set_active
2160 (GTK_CHECK_MENU_ITEM(item),
2161 inifile_get_gboolean(INI_SETTING_SLABELS,INI_SETTING_SLABELS_DEFAULT));
2162
2163 item = gtk_item_factory_get_item(item_factory,"/View/Buffer position");
2164 gtk_check_menu_item_set_active
2165 (GTK_CHECK_MENU_ITEM(item),
2166 inifile_get_gboolean(INI_SETTING_BUFPOS,INI_SETTING_BUFPOS_DEFAULT));
2167
2168 item = gtk_item_factory_get_item(item_factory,"/Play/Record...");
2169 gtk_widget_set_sensitive(item,input_supported());
2170
2171 item = gtk_item_factory_get_item(item_factory,"/Edit/Delete");
2172 gtk_widget_add_accelerator(item, "activate", accel_group, GDK_Delete, 0, 0);
2173
2174 return gtk_item_factory_get_widget(item_factory,"<main>");
2175 }
2176
loopmode_toggle(GtkToggleButton * button,gboolean * user_data)2177 static void loopmode_toggle(GtkToggleButton *button, gboolean *user_data)
2178 {
2179 *user_data = gtk_toggle_button_get_active(button);
2180 inifile_set_gboolean("loopMode", *user_data);
2181 }
2182
followmode_toggle(GtkToggleButton * button,gboolean * user_data)2183 static void followmode_toggle(GtkToggleButton *button, gboolean *user_data)
2184 {
2185 Mainwindow *w = MAINWINDOW(user_data);
2186 w->followmode = gtk_toggle_button_get_active(button);
2187 if (w->doc != NULL)
2188 document_set_followmode(w->doc, w->followmode);
2189 inifile_set_gboolean("followMode", w->followmode);
2190 }
2191
bouncemode_toggle(GtkToggleButton * button,gboolean * user_data)2192 static void bouncemode_toggle(GtkToggleButton *button, gboolean *user_data)
2193 {
2194 Mainwindow *w = MAINWINDOW(user_data);
2195 w->bouncemode = gtk_toggle_button_get_active(button);
2196 inifile_set_gboolean("bounceMode", gtk_toggle_button_get_active(button));
2197 }
2198
create_toolbar(Mainwindow * w)2199 static GtkWidget *create_toolbar(Mainwindow *w)
2200 {
2201 GtkWidget *t,*b,*r;
2202 GdkPixmap *p;
2203 GdkBitmap *bmp;
2204 #if GTK_MAJOR_VERSION == 2
2205 t = gtk_toolbar_new();
2206 #else
2207 t = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS);
2208 #endif
2209 p = gdk_pixmap_colormap_create_from_xpm_d(
2210 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2211 button_open_xpm);
2212 b = gtk_pixmap_new(p, bmp);
2213 r = gtk_toolbar_append_element(
2214 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2215 _("Load a file from disk"),"X",b,GTK_SIGNAL_FUNC(file_open),w);
2216 p = gdk_pixmap_colormap_create_from_xpm_d(
2217 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2218 button_save_xpm);
2219 b = gtk_pixmap_new(p, bmp);
2220 r = gtk_toolbar_append_element(
2221 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2222 _("Save the current file to disk"),"X",b,GTK_SIGNAL_FUNC(file_save),w);
2223 w->need_chunk_items = g_list_append(w->need_chunk_items,r);
2224 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2225 p = gdk_pixmap_colormap_create_from_xpm_d(
2226 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2227 button_undo_xpm);
2228 b = gtk_pixmap_new(p, bmp);
2229 r = gtk_toolbar_append_element(
2230 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2231 _("Undo the last change"),"X",b,GTK_SIGNAL_FUNC(edit_undo),w);
2232 w->need_undo_items = g_list_append(w->need_undo_items, r);
2233 p = gdk_pixmap_colormap_create_from_xpm_d(
2234 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2235 button_redo_xpm);
2236 b = gtk_pixmap_new(p, bmp);
2237 r = gtk_toolbar_append_element(
2238 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2239 _("Redo the last undo operation"),"X",b,GTK_SIGNAL_FUNC(edit_redo),
2240 w);
2241 w->need_redo_items = g_list_append(w->need_redo_items, r);
2242 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2243 p = gdk_pixmap_colormap_create_from_xpm_d(
2244 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2245 button_cut_xpm);
2246 b = gtk_pixmap_new(p, bmp);
2247 r = gtk_toolbar_append_element(
2248 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2249 _("Cut out the current selection"),"X",b,GTK_SIGNAL_FUNC(edit_cut),w);
2250 w->need_selection_items = g_list_append(w->need_selection_items, r);
2251 p = gdk_pixmap_colormap_create_from_xpm_d(
2252 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2253 button_copy_xpm);
2254 b = gtk_pixmap_new(p, bmp);
2255 r = gtk_toolbar_append_element(
2256 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2257 _("Copy the current selection"),"X",b,GTK_SIGNAL_FUNC(edit_copy),w);
2258 w->need_selection_items = g_list_append(w->need_selection_items, r);
2259 p = gdk_pixmap_colormap_create_from_xpm_d(
2260 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2261 button_paste_xpm);
2262 b = gtk_pixmap_new(p, bmp);
2263 r = gtk_toolbar_append_element(
2264 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2265 _("Paste at cursor position"),"X",b,GTK_SIGNAL_FUNC(edit_paste),w);
2266 w->need_clipboard_items = g_list_append(w->need_clipboard_items, r);
2267 p = gdk_pixmap_colormap_create_from_xpm_d(
2268 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2269 button_pasteover_xpm);
2270 b = gtk_pixmap_new(p, bmp);
2271 r = gtk_toolbar_append_element(
2272 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2273 _("Paste, overwriting the data after the cursor position"),"X",b,
2274 GTK_SIGNAL_FUNC(edit_pasteover),w);
2275 w->need_clipboard_items = g_list_append(w->need_clipboard_items, r);
2276 gtk_widget_set_sensitive(r,FALSE);
2277 p = gdk_pixmap_colormap_create_from_xpm_d(
2278 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2279 button_delete_xpm);
2280 b = gtk_pixmap_new(p, bmp);
2281 r = gtk_toolbar_append_element(
2282 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2283 _("Delete the selection"),"X",b,GTK_SIGNAL_FUNC(edit_delete),w);
2284 w->need_selection_items = g_list_append(w->need_selection_items, r);
2285 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2286 p = gdk_pixmap_colormap_create_from_xpm_d(
2287 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2288 button_cursorstart_xpm);
2289 b = gtk_pixmap_new(p, bmp);
2290 r = gtk_toolbar_append_element(
2291 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2292 _("Set selection start to cursor position"),"X",b,
2293 GTK_SIGNAL_FUNC(edit_selstartcursor),w);
2294 w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2295 p = gdk_pixmap_colormap_create_from_xpm_d(
2296 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2297 button_cursorend_xpm);
2298 b = gtk_pixmap_new(p, bmp);
2299 r = gtk_toolbar_append_element(
2300 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2301 _("Set selection end to cursor position"),"X",b,
2302 GTK_SIGNAL_FUNC(edit_selendcursor),w);
2303 w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2304 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2305 p = gdk_pixmap_colormap_create_from_xpm_d(
2306 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2307 button_play_xpm);
2308 b = gtk_pixmap_new(p, bmp);
2309 r = gtk_toolbar_append_element(
2310 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2311 _("Play from cursor position"),"X",b,
2312 GTK_SIGNAL_FUNC(edit_play),w);
2313 w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2314 p = gdk_pixmap_colormap_create_from_xpm_d
2315 (NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2316 button_playselection_xpm);
2317 b = gtk_pixmap_new(p, bmp);
2318 r = gtk_toolbar_append_element(
2319 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2320 _("Play selected area"),"X",b,
2321 GTK_SIGNAL_FUNC(edit_playselection),w);
2322 w->need_chunk_items = g_list_append(w->need_chunk_items,r);
2323 p = gdk_pixmap_colormap_create_from_xpm_d(
2324 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2325 button_stop_xpm);
2326 b = gtk_pixmap_new(p, bmp);
2327 r = gtk_toolbar_append_element(
2328 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2329 _("Stop playing"),"X",b,
2330 GTK_SIGNAL_FUNC(edit_stop),w);
2331 w->need_chunk_items = g_list_append(w->need_chunk_items, r);
2332 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2333 p = gdk_pixmap_colormap_create_from_xpm_d(
2334 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2335 button_loop_xpm);
2336 b = gtk_pixmap_new(p, bmp);
2337 r = gtk_toolbar_append_element(
2338 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_TOGGLEBUTTON,NULL,NULL,
2339 _("Loop mode (play over and over)"),"X",b,
2340 GTK_SIGNAL_FUNC(loopmode_toggle),&(w->loopmode));
2341 if ( inifile_get_gboolean("loopMode",FALSE) )
2342 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(r), TRUE);
2343 p = gdk_pixmap_colormap_create_from_xpm_d(
2344 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2345 button_follow_xpm);
2346 b = gtk_pixmap_new(p, bmp);
2347 r = gtk_toolbar_append_element(
2348 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_TOGGLEBUTTON,NULL,NULL,
2349 _("Keep view and playback together"),"X",b,
2350 GTK_SIGNAL_FUNC(followmode_toggle),w);
2351 if ( inifile_get_gboolean("followMode",FALSE) ) {
2352 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(r), TRUE);
2353 w->followmode = TRUE;
2354 } else
2355 w->followmode = FALSE;
2356 p = gdk_pixmap_colormap_create_from_xpm_d(
2357 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2358 button_bounce_xpm);
2359 b = gtk_pixmap_new(p, bmp);
2360 r = gtk_toolbar_append_element(
2361 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_TOGGLEBUTTON,NULL,NULL,
2362 _("Auto return to playback start"),"X",b,
2363 GTK_SIGNAL_FUNC(bouncemode_toggle),w);
2364 if ( inifile_get_gboolean("bounceMode",FALSE) ) {
2365 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(r), TRUE);
2366 w->bouncemode = TRUE;
2367 }
2368
2369 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2370 p = gdk_pixmap_colormap_create_from_xpm_d(
2371 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2372 button_record_xpm);
2373 b = gtk_pixmap_new(p, bmp);
2374 r = gtk_toolbar_append_element(
2375 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2376 _("Record"),"X",b,GTK_SIGNAL_FUNC(edit_record),w);
2377 gtk_widget_set_sensitive(r,input_supported());
2378 gtk_toolbar_append_space(GTK_TOOLBAR(t));
2379 p = gdk_pixmap_colormap_create_from_xpm_d(
2380 NULL, gtk_widget_get_colormap(GTK_WIDGET(w)), &bmp, NULL,
2381 button_mixer_xpm);
2382 b = gtk_pixmap_new(p, bmp);
2383 r = gtk_toolbar_append_element(
2384 GTK_TOOLBAR(t),GTK_TOOLBAR_CHILD_BUTTON,NULL,NULL,
2385 _("Launch mixer"),"X",b,GTK_SIGNAL_FUNC(launch_mixer),w);
2386 return t;
2387 }
2388
2389 static gboolean setting_zoom_flag = FALSE;
2390
mainwindow_view_changed(Document * d,gpointer user_data)2391 static void mainwindow_view_changed(Document *d, gpointer user_data)
2392 {
2393 float max_samp,min_samp,current_samp;
2394 Mainwindow *w = MAINWINDOW(user_data);
2395 w->view_adj->page_size = (d->viewend - d->viewstart);
2396 w->view_adj->upper = d->chunk->length;
2397 w->view_adj->value = d->viewstart;
2398 w->view_adj->step_increment = 16;
2399 w->view_adj->page_increment = w->view_adj->page_size / 2;
2400 gtk_adjustment_changed ( w->view_adj );
2401 setting_zoom_flag = TRUE;
2402 max_samp = w->doc->chunk->length;
2403 min_samp = GTK_WIDGET(w->view)->allocation.width;
2404 current_samp = w->doc->viewend - w->doc->viewstart;
2405 if (current_samp < min_samp) {
2406 if (current_samp < w->doc->chunk->length) {
2407 /* We are zoomed in longer than the slider allows, so set it
2408 * to max */
2409 w->zoom_adj->value = 1.0;
2410 w->zoom_adj->page_size = 0.2;
2411 set_sensitive(w->zoom_items,TRUE);
2412 } else {
2413 /* We're viewing the whole chunk and can't zoom in or out */
2414 w->zoom_adj->value = 0.0;
2415 w->zoom_adj->page_size = 1.2;
2416 set_sensitive(w->zoom_items,FALSE);
2417 }
2418 } else {
2419 w->zoom_adj->value =
2420 log(current_samp/max_samp)/log(min_samp/max_samp);
2421 w->zoom_adj->page_size = 0.2;
2422 set_sensitive(w->zoom_items,TRUE);
2423 }
2424 gtk_adjustment_changed ( w->zoom_adj );
2425 setting_zoom_flag = FALSE;
2426 update_desc(w);
2427 }
2428
mainwindow_selection_changed(Document * d,gpointer user_data)2429 static void mainwindow_selection_changed(Document *d, gpointer user_data)
2430 {
2431 Mainwindow *w = MAINWINDOW ( user_data );
2432 update_desc ( w );
2433 set_sensitive(w->need_selection_items, (d->selstart != d->selend));
2434 }
2435
mainwindow_cursor_changed(Document * d,gboolean rolling,gpointer user_data)2436 static void mainwindow_cursor_changed(Document *d, gboolean rolling,
2437 gpointer user_data)
2438 {
2439 Mainwindow *w;
2440 w = MAINWINDOW ( user_data );
2441 if (!rolling || status_bar_roll_cursor) update_desc(w);
2442 }
2443
mainwindow_state_changed(Document * d,gpointer user_data)2444 static void mainwindow_state_changed(Document *d, gpointer user_data)
2445 {
2446 Mainwindow *w = MAINWINDOW(user_data);
2447 fix_title(w);
2448 update_desc(w);
2449 set_sensitive(w->need_undo_items,document_can_undo(d));
2450 set_sensitive(w->need_redo_items,document_can_redo(d));
2451 set_sensitive(w->need_selection_items,(d->selstart != d->selend));
2452 mainwindow_view_changed(d,user_data);
2453 }
2454
mainwindow_value_changed(GtkAdjustment * adjustment,gpointer user_data)2455 static void mainwindow_value_changed(GtkAdjustment *adjustment,
2456 gpointer user_data)
2457 {
2458 Document *d = MAINWINDOW(user_data)->doc;
2459 off_t s,e;
2460 s = (off_t)adjustment->value;
2461 e = (off_t)(adjustment->value + adjustment->page_size);
2462 /* Due to rounding, these can become out of range.
2463 * Especially for GTK1 where value and page_size are gfloats */
2464 if (s < 0) s = 0;
2465 if (e <= s) e = s+1; else if (e > d->chunk->length) e = d->chunk->length;
2466 document_set_view(d, s, e);
2467 }
2468
mainwindow_zoom_changed(GtkAdjustment * adjustment,gpointer user_data)2469 static void mainwindow_zoom_changed(GtkAdjustment *adjustment,
2470 gpointer user_data)
2471 {
2472 gboolean follow_cursor;
2473 float max_samp,min_samp,target_samp,current_samp;
2474 Mainwindow *w = MAINWINDOW(user_data);
2475
2476 /* puts("mainwindow_zoom_changed"); */
2477 if (setting_zoom_flag) return;
2478 current_samp = w->doc->viewend - w->doc->viewstart;
2479 min_samp = GTK_WIDGET(w->view)->allocation.width;
2480 max_samp = w->doc->chunk->length;
2481 target_samp = max_samp * pow(min_samp/max_samp,adjustment->value);
2482 follow_cursor = target_samp <= current_samp;
2483 document_zoom(w->doc,current_samp/target_samp,follow_cursor);
2484 }
2485
mainwindow_vertical_zoom_changed(GtkAdjustment * adjustment,gpointer user_data)2486 static void mainwindow_vertical_zoom_changed(GtkAdjustment *adjustment,
2487 gpointer user_data)
2488 {
2489 gfloat s;
2490 Mainwindow *w = MAINWINDOW(user_data);
2491 gchar c[32],d[32];
2492 int ndec;
2493 s = pow(100.0, adjustment->value);
2494 chunk_view_set_scale(w->view, s);
2495 ndec = 3-(int)(adjustment->value*2.0);
2496 if (ndec > 0) {
2497 g_snprintf(d,sizeof(d),"V: %%.0%df",ndec);
2498 g_snprintf(c,sizeof(c),d,(float) s);
2499 } else {
2500 g_snprintf(c,sizeof(c),"V: %d",(int)s);
2501 }
2502 gtk_label_set_text(w->vzoom_label,c);
2503 }
2504
mainwindow_speed_changed(GtkAdjustment * adjustment,gpointer user_data)2505 static void mainwindow_speed_changed(GtkAdjustment *adjustment,
2506 gpointer user_data)
2507 {
2508 Mainwindow *w = MAINWINDOW(user_data);
2509 gchar c[32];
2510 gfloat f;
2511 f = adjustment->value;
2512 #ifdef INV_SPEED
2513 f = -f;
2514 #endif
2515 if (w->doc == playing_document)
2516 player_set_speed(f);
2517 g_snprintf(c,sizeof(c),"S: %d%%",(int)(f*100.0+0.5));
2518 gtk_label_set_text(w->speed_label,c);
2519 }
2520
dc_func(gchar * label,off_t pos,gpointer fud)2521 static void dc_func(gchar *label, off_t pos, gpointer fud)
2522 {
2523 off_t *ud = (off_t *)fud;
2524 if (pos < ud[0] && pos > ud[1]) ud[1] = pos;
2525 else if (pos > ud[0] && pos < ud[2]) ud[2] = pos;
2526 }
2527
mainwindow_view_double_click(ChunkView * view,off_t * sample,Mainwindow * wnd)2528 static void mainwindow_view_double_click(ChunkView *view,
2529 off_t *sample, Mainwindow *wnd)
2530 {
2531 off_t o[3] = { *sample, 0, wnd->doc->chunk->length };
2532 document_foreach_mark(wnd->doc,dc_func,o);
2533 document_set_selection(wnd->doc,o[1],o[2]);
2534 }
2535
hzoom_scale_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2536 static gint hzoom_scale_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2537 {
2538 Mainwindow *mw = MAINWINDOW(user_data);
2539 if (event->button == 3) {
2540 gtk_adjustment_set_value(mw->zoom_adj, 0);
2541 return TRUE;
2542 }
2543 return FALSE;
2544 }
2545
vzoom_scale_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2546 static gint vzoom_scale_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2547 {
2548 Mainwindow *mw = MAINWINDOW(user_data);
2549 if (event->button == 3) {
2550 gtk_adjustment_set_value(mw->vertical_zoom_adj, 0);
2551 return TRUE;
2552 }
2553 return FALSE;
2554 }
2555
speed_scale_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2556 static gint speed_scale_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
2557 {
2558 Mainwindow *mw = MAINWINDOW(user_data);
2559 if (event->button == 3) {
2560 #ifdef INV_SPEED
2561 gtk_adjustment_set_value(mw->speed_adj, -1.0);
2562 #else
2563 gtk_adjustment_set_value(mw->speed_adj, 1.0);
2564 #endif
2565 return TRUE;
2566 }
2567 return FALSE;
2568 }
2569
mainwindow_init(Mainwindow * obj)2570 static void mainwindow_init(Mainwindow *obj)
2571 {
2572 GtkWidget *a,*b,*c;
2573 GtkRequisition req;
2574 GtkTargetEntry gte;
2575
2576 if (!window_geometry_stack_inited) {
2577 if (inifile_get_gboolean("useGeometry",FALSE))
2578 window_geometry_stack =
2579 geometry_stack_from_inifile("windowGeometry");
2580 window_geometry_stack_inited = TRUE;
2581 load_recent();
2582 }
2583
2584 /* St�ll in datastrukturen */
2585 obj->view = CHUNKVIEW(chunk_view_new());
2586
2587 chunk_view_set_timescale(
2588 obj->view, inifile_get_gboolean(INI_SETTING_TIMESCALE,
2589 INI_SETTING_TIMESCALE_DEFAULT));
2590 obj->view->show_bufpos = inifile_get_gboolean
2591 (INI_SETTING_BUFPOS,INI_SETTING_BUFPOS_DEFAULT);
2592 gtk_signal_connect( GTK_OBJECT(obj->view), "double-click",
2593 GTK_SIGNAL_FUNC(mainwindow_view_double_click), obj);
2594 obj->view_adj = GTK_ADJUSTMENT( gtk_adjustment_new ( 0,0,0,0,0,0 ));
2595 gtk_signal_connect( GTK_OBJECT(obj->view_adj), "value-changed",
2596 GTK_SIGNAL_FUNC(mainwindow_value_changed), obj);
2597 obj->zoom_adj = GTK_ADJUSTMENT( gtk_adjustment_new ( 0, 0, 1.2,0.01, 0.1,
2598 0.2 ));
2599 gtk_signal_connect( GTK_OBJECT(obj->zoom_adj), "value-changed",
2600 GTK_SIGNAL_FUNC(mainwindow_zoom_changed), obj);
2601 obj->vertical_zoom_adj =
2602 GTK_ADJUSTMENT(gtk_adjustment_new ( 0, 0, 0.2 + log (inifile_get_guint32 ("vzoomMax", 100)) / log (100.0), 0.01, 0.1, 0.2 ));
2603 gtk_signal_connect( GTK_OBJECT(obj->vertical_zoom_adj), "value-changed",
2604 GTK_SIGNAL_FUNC(mainwindow_vertical_zoom_changed),
2605 obj);
2606 #ifdef INV_SPEED
2607 obj->speed_adj =
2608 GTK_ADJUSTMENT(gtk_adjustment_new(-1.0,-2.0,0.20,0.01,0.1,0.2));
2609 #else
2610 obj->speed_adj =
2611 GTK_ADJUSTMENT(gtk_adjustment_new(1.0,0.0,2.2,0.01,0.1,0.2));
2612 #endif
2613 gtk_signal_connect(GTK_OBJECT(obj->speed_adj),"value-changed",
2614 GTK_SIGNAL_FUNC(mainwindow_speed_changed),
2615 obj);
2616
2617 obj->statusbar = STATUSBAR(status_bar_new());
2618 gtk_signal_connect(GTK_OBJECT(obj->statusbar),"progress_begin",
2619 GTK_SIGNAL_FUNC(procstart),obj);
2620 gtk_signal_connect(GTK_OBJECT(obj->statusbar),"progress_end",
2621 GTK_SIGNAL_FUNC(procend),obj);
2622 obj->loopmode = inifile_get_gboolean("loopMode",FALSE);
2623 obj->bouncemode = FALSE; /* Set to true by create_toolbar */
2624 obj->sensitive = TRUE;
2625 obj->vzoom_icon = obj->vzoom_slider = NULL;
2626 obj->hzoom_icon = obj->hzoom_slider = NULL;
2627 obj->speed_icon = obj->speed_slider = NULL;
2628 obj->speed_label = GTK_LABEL(gtk_label_new("S: 500%"));
2629 gtk_misc_set_alignment(GTK_MISC(obj->speed_label),0.0,0.0);
2630 gtk_widget_size_request(GTK_WIDGET(obj->speed_label),&req);
2631 gtk_widget_set_usize(GTK_WIDGET(obj->speed_label),req.width,req.height);
2632 obj->vzoom_label = GTK_LABEL(gtk_label_new("V: 1.000"));
2633 gtk_misc_set_alignment(GTK_MISC(obj->vzoom_label),0.0,0.0);
2634 gtk_widget_size_request(GTK_WIDGET(obj->vzoom_label),&req);
2635 gtk_widget_set_usize(GTK_WIDGET(obj->vzoom_label),req.width,req.height);
2636
2637 obj->need_chunk_items = NULL;
2638 obj->need_selection_items = NULL;
2639 obj->need_clipboard_items = NULL;
2640 obj->need_undo_items = NULL;
2641 obj->zoom_items = NULL;
2642
2643 fix_title ( obj );
2644
2645 /* Bygg upp komponenterna */
2646 a = gtk_vbox_new( FALSE, 0 );
2647 gtk_container_add(GTK_CONTAINER(obj),a);
2648 b = create_menu( obj );
2649 obj->menubar = b;
2650 gtk_box_pack_start(GTK_BOX(a),b,FALSE,FALSE,0);
2651 b = gtk_table_new(3,4,FALSE);
2652 gtk_box_pack_start(GTK_BOX(a),b,TRUE,TRUE,0);
2653
2654 c = create_toolbar( obj );
2655 obj->toolbar = c;
2656
2657 c = gtk_event_box_new();
2658 gtk_container_add(GTK_CONTAINER(c),GTK_WIDGET(obj->toolbar));
2659 gtk_widget_size_request(c,&req);
2660 gtk_widget_set_usize(c,10,req.height);
2661
2662 gtk_table_attach(GTK_TABLE(b),c,0,1,0,1,GTK_SHRINK|GTK_FILL,GTK_FILL,0,0);
2663
2664 c = bitmap_new_from_data(vzoom_bits, vzoom_width, vzoom_height);
2665 bitmap_set_fg(BITMAP(c),0.8);
2666 gtk_table_attach(GTK_TABLE(b),c,1,2,0,1,GTK_FILL,0,0,0);
2667 obj->vzoom_icon = c;
2668
2669 c = bitmap_new_from_data(hzoom_bits, hzoom_width, hzoom_height);
2670 bitmap_set_fg(BITMAP(c),0.8);
2671 gtk_table_attach(GTK_TABLE(b),c,2,3,0,1,GTK_FILL,0,0,0);
2672 obj->hzoom_icon = c;
2673
2674 c = bitmap_new_from_data(speed_bits, speed_width, speed_height);
2675 bitmap_set_fg(BITMAP(c),0.8);
2676 gtk_table_attach(GTK_TABLE(b),c,3,4,0,1,GTK_FILL,0,0,0);
2677 obj->speed_icon = c;
2678
2679 gtk_table_attach(GTK_TABLE(b),GTK_WIDGET(obj->view),0,1,1,2,
2680 GTK_EXPAND|GTK_FILL|GTK_SHRINK,
2681 GTK_EXPAND|GTK_FILL|GTK_SHRINK,0,0);
2682
2683 c = gtk_vscale_new ( obj->zoom_adj );
2684 /* GTK1 doesn't work well with using the right mouse button press event.
2685 * As a work around, we use the release event instead */
2686 #if GTK_MAJOR_VERSION > 1
2687 gtk_signal_connect(GTK_OBJECT(c),"button_press_event",GTK_SIGNAL_FUNC(hzoom_scale_press),obj);
2688 #else
2689 gtk_signal_connect(GTK_OBJECT(c),"button_release_event",GTK_SIGNAL_FUNC(hzoom_scale_press),obj);
2690 #endif
2691 gtk_scale_set_digits(GTK_SCALE(c),3);
2692 gtk_scale_set_draw_value (GTK_SCALE(c), FALSE);
2693 gtk_table_attach(GTK_TABLE(b),c,2,3,1,2,0,GTK_EXPAND|GTK_FILL,0,0);
2694 obj->need_chunk_items = g_list_append(obj->need_chunk_items,c);
2695 obj->hzoom_slider = c;
2696
2697 c = gtk_vscale_new ( obj->vertical_zoom_adj );
2698 #if GTK_MAJOR_VERSION > 1
2699 gtk_signal_connect(GTK_OBJECT(c),"button_press_event",GTK_SIGNAL_FUNC(vzoom_scale_press),obj);
2700 #else
2701 gtk_signal_connect(GTK_OBJECT(c),"button_release_event",GTK_SIGNAL_FUNC(vzoom_scale_press),obj);
2702 #endif
2703 gtk_scale_set_digits(GTK_SCALE(c),3);
2704 gtk_scale_set_draw_value (GTK_SCALE(c), FALSE);
2705 gtk_table_attach(GTK_TABLE(b),c,1,2,1,2,0,GTK_EXPAND|GTK_FILL,0,0);
2706 obj->need_chunk_items = g_list_append(obj->need_chunk_items,c);
2707 obj->vzoom_slider = c;
2708
2709 c = gtk_vscale_new ( obj->speed_adj );
2710 #if GTK_MAJOR_VERSION > 1
2711 gtk_signal_connect(GTK_OBJECT(c),"button_press_event",GTK_SIGNAL_FUNC(speed_scale_press),obj);
2712 #else
2713 gtk_signal_connect(GTK_OBJECT(c),"button_release_event",GTK_SIGNAL_FUNC(speed_scale_press),obj);
2714 #endif
2715 gtk_scale_set_digits(GTK_SCALE(c),2);
2716 gtk_scale_set_draw_value (GTK_SCALE(c), FALSE);
2717 /* gtk_range_set_update_policy(GTK_RANGE(c),GTK_UPDATE_DELAYED); */
2718 #ifndef INV_SPEED
2719 gtk_range_set_inverted(GTK_RANGE(c),TRUE);
2720 #endif
2721 gtk_table_attach(GTK_TABLE(b),c,3,4,1,2,0,GTK_EXPAND|GTK_FILL,0,0);
2722 obj->need_chunk_items = g_list_append(obj->need_chunk_items,c);
2723 obj->speed_slider = c;
2724
2725 c = gtk_hscrollbar_new ( obj->view_adj );
2726 gtk_table_attach(GTK_TABLE(b),c,0,1,2,3,GTK_FILL,0,0,0);
2727
2728 c = GTK_WIDGET(obj->speed_label);
2729 gtk_table_attach(GTK_TABLE(b),c,1,4,3,4,GTK_FILL,0,2,0);
2730
2731 c = gtk_event_box_new();
2732 gtk_container_add(GTK_CONTAINER(c),GTK_WIDGET (obj->statusbar));
2733 gtk_table_attach(GTK_TABLE(b),c,0,1,3,4,GTK_FILL,0,0,0);
2734
2735 c = GTK_WIDGET(obj->vzoom_label);
2736 gtk_table_attach(GTK_TABLE(b),c,1,4,2,3,GTK_FILL,0,2,0);
2737
2738 gtk_adjustment_value_changed(obj->speed_adj);
2739 gtk_adjustment_value_changed(obj->vertical_zoom_adj);
2740 gtk_widget_show_all(a);
2741
2742 if (!inifile_get_gboolean(INI_SETTING_VZOOM,INI_SETTING_VZOOM_DEFAULT)) {
2743 gtk_widget_hide(obj->vzoom_icon);
2744 gtk_widget_hide(obj->vzoom_slider);
2745 gtk_widget_hide(GTK_WIDGET(obj->vzoom_label));
2746 }
2747
2748 if (!inifile_get_gboolean(INI_SETTING_HZOOM,INI_SETTING_HZOOM_DEFAULT)) {
2749 gtk_widget_hide(obj->hzoom_icon);
2750 gtk_widget_hide(obj->hzoom_slider);
2751 }
2752
2753 if (!inifile_get_gboolean(INI_SETTING_SPEED,INI_SETTING_SPEED_DEFAULT)) {
2754 gtk_widget_hide(obj->speed_icon);
2755 gtk_widget_hide(obj->speed_slider);
2756 gtk_widget_hide(GTK_WIDGET(obj->speed_label));
2757 }
2758
2759 obj->show_labels = inifile_get_gboolean(INI_SETTING_SLABELS,INI_SETTING_SLABELS_DEFAULT);
2760 if (!obj->show_labels) {
2761 gtk_widget_hide(GTK_WIDGET(obj->vzoom_label));
2762 gtk_widget_hide(GTK_WIDGET(obj->speed_label));
2763 }
2764
2765 gtk_window_set_policy(GTK_WINDOW(obj),FALSE,TRUE,FALSE);
2766
2767 set_sensitive(obj->need_chunk_items, FALSE);
2768 set_sensitive(obj->need_selection_items, FALSE);
2769 set_sensitive(obj->need_clipboard_items, clipboard != NULL);
2770 set_sensitive(obj->need_undo_items, FALSE);
2771 set_sensitive(obj->need_redo_items, FALSE);
2772
2773 if (!geometry_stack_pop(&window_geometry_stack,NULL,GTK_WINDOW(obj)))
2774 gtk_window_set_default_size(GTK_WINDOW(obj),540,230);
2775
2776 /* Setup drag'n'drop target */
2777 gte.target = "text/uri-list";
2778 gte.flags = gte.info = 0;
2779 gtk_drag_dest_set(GTK_WIDGET(obj), GTK_DEST_DEFAULT_ALL, >e, 1,
2780 GDK_ACTION_COPY | GDK_ACTION_MOVE);
2781 }
2782
mainwindow_get_type(void)2783 GtkType mainwindow_get_type(void)
2784 {
2785 static GtkType id=0;
2786 if (!id) {
2787 GtkTypeInfo info = {
2788 "Mainwindow",
2789 sizeof(Mainwindow),
2790 sizeof(MainwindowClass),
2791 (GtkClassInitFunc) mainwindow_class_init,
2792 (GtkObjectInitFunc) mainwindow_init
2793 };
2794 id=gtk_type_unique(gtk_window_get_type(),&info);
2795 }
2796 return id;
2797 }
2798
mainwindow_new(void)2799 GtkWidget *mainwindow_new(void)
2800 {
2801 return GTK_WIDGET( gtk_type_new(mainwindow_get_type()) );
2802 }
2803
mainwindow_new_with_file(char * filename,gboolean log)2804 GtkWidget *mainwindow_new_with_file(char *filename, gboolean log)
2805 {
2806 Mainwindow *w;
2807 Document *doc;
2808 gchar *d;
2809 w = MAINWINDOW ( mainwindow_new() );
2810 d = make_filename_rooted(filename);
2811 doc = document_new_with_file(d, w->statusbar);
2812 if (doc != NULL) {
2813 mainwindow_set_document(w, doc, d);
2814 if (log) {
2815 inifile_set("lastOpenFile",d);
2816 recent_file(d);
2817 }
2818 }
2819 g_free(d);
2820 return GTK_WIDGET(w);
2821 }
2822
reset_statusbar(Mainwindow * w)2823 static void reset_statusbar(Mainwindow *w)
2824 {
2825 status_bar_reset(w->statusbar);
2826 }
2827
mainwindow_update_texts(void)2828 void mainwindow_update_texts(void)
2829 {
2830 list_object_foreach(mainwindow_objects,(GFunc)fix_title,NULL);
2831 list_object_foreach(mainwindow_objects,(GFunc)reset_statusbar,NULL);
2832 list_object_foreach(mainwindow_objects,(GFunc)update_desc,NULL);
2833 }
2834
mainwindow_set_sensitive(Mainwindow * mw,gboolean sensitive)2835 void mainwindow_set_sensitive(Mainwindow *mw, gboolean sensitive)
2836 {
2837 gtk_widget_set_sensitive(mw->menubar,sensitive);
2838 gtk_widget_set_sensitive(mw->toolbar,sensitive);
2839 gtk_widget_set_sensitive(GTK_WIDGET(mw->view),sensitive);
2840 mw->sensitive = sensitive;
2841 }
2842
mainwindow_set_all_sensitive(gboolean sensitive)2843 void mainwindow_set_all_sensitive(gboolean sensitive)
2844 {
2845 list_object_foreach(mainwindow_objects,(GFunc)mainwindow_set_sensitive,
2846 GINT_TO_POINTER(sensitive));
2847 }
2848
mainwindow_repaint_views(void)2849 void mainwindow_repaint_views(void)
2850 {
2851 GList *l;
2852 for (l=mainwindow_objects->list; l!=NULL; l=l->next) {
2853 chunk_view_force_repaint(MAINWINDOW(l->data)->view);
2854 }
2855 }
2856