mp3splt-gtk

- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

player_window.c
Go to the documentation of this file.
1 /**********************************************************
2 * mp3splt-gtk -- utility based on mp3splt,
3 *
4 * for mp3/ogg splitting without decoding
5 *
6 * Copyright: (C) 2005-2013 Alexandru Munteanu
7 * Contact: m@ioalex.net
8 *
9 * http://mp3splt.sourceforge.net/
10 *
11 *********************************************************/
12
13 /**********************************************************
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
28 * USA.
29 *
30 *********************************************************/
31
32 /*!********************************************************
33 * \file
34 * The player control tab
35 *
36 * this file is used for the player control tab
37 **********************************************************/
38
39 #include "player_window.h"
40
41 #define DRAWING_AREA_WIDTH 400
42 #define DRAWING_AREA_HEIGHT 123
43 #define DRAWING_AREA_HEIGHT_WITH_SILENCE_WAVE 232
44
45 //playlist tree enumeration
46 enum {
47 COL_NAME,
48 COL_FILENAME,
49 PLAYLIST_COLUMNS
50 };
51
52 static void draw_small_rectangle(gint time_left, gint time_right,
53 GdkColor color, cairo_t *cairo_surface, ui_state *ui);
54 static gint mytimer(ui_state *ui);
55
57 static void get_silence_level(long time, float level, void *user_data)
58 {
59 ui_state *ui = (ui_state *)user_data;
60
61 gint converted_level = (gint)floorf(abs(level));
62 if (converted_level < 0)
63 {
64 return;
65 }
66
67 //TODO: using an idle here does not work.
68 // At least on windows idles are not executed in order
69
70 if (!ui->infos->silence_points)
71 {
72 ui->infos->silence_points = g_malloc(sizeof(silence_wave) * 3000);
73 ui->infos->malloced_num_of_silence_points = 3000;
74 }
75 else if (ui->infos->number_of_silence_points >= ui->infos->malloced_num_of_silence_points)
76 {
77 ui->infos->silence_points = g_realloc(ui->infos->silence_points,
78 sizeof(silence_wave) * (ui->infos->number_of_silence_points + 3000));
79 ui->infos->malloced_num_of_silence_points = ui->infos->number_of_silence_points + 3000;
80 }
81
82 ui->infos->silence_points[ui->infos->number_of_silence_points].time = time;
83 ui->infos->silence_points[ui->infos->number_of_silence_points].level = abs(level);
84
85 ui->infos->number_of_silence_points++;
86 }
87
88 static GArray *build_gdk_points_for_douglas_peucker(ui_infos *infos)
89 {
90 GArray *points = g_array_new(TRUE, TRUE, sizeof(GdkPoint));
91
92 gint i = 0;
93 for (i = 0;i < infos->number_of_silence_points;i++)
94 {
95 long time = infos->silence_points[i].time;
96 float level = infos->silence_points[i].level;
97
98 GdkPoint point;
99 point.x = (gint)time;
100 point.y = (gint)floorf(level);
101 g_array_append_val(points, point);
102 }
103
104 return points;
105 }
106
107 static void douglas_peucker_callback(ui_state *ui)
108 {
109 ui->status->douglas_callback_counter++;
110
111 if (ui->status->douglas_callback_counter % 400 != 0)
112 {
113 return;
114 }
115
116 gtk_progress_bar_pulse(ui->gui->percent_progress_bar);
117 gtk_progress_bar_set_text(ui->gui->percent_progress_bar,
118 _("Processing Douglas-Peucker filters ..."));
119 gtk_widget_queue_draw(GTK_WIDGET(ui->gui->percent_progress_bar));
120 while (gtk_events_pending())
121 {
122 gtk_main_iteration();
123 }
124
125 ui->status->douglas_callback_counter = 0;
126 }
127
128 void compute_douglas_peucker_filters(ui_state *ui)
129 {
130 if (!ui->status->show_silence_wave || ui->status->currently_compute_douglas_peucker_filters)
131 {
132 return;
133 }
134
135 ui_infos *infos = ui->infos;
136 gui_status *status = ui->status;
137
138 status->currently_compute_douglas_peucker_filters = TRUE;
139
140 status->douglas_callback_counter = 0;
141
142 GArray *gdk_points_for_douglas_peucker = build_gdk_points_for_douglas_peucker(infos);
143
144 splt_douglas_peucker_free(infos->filtered_points_presence);
145
146 infos->filtered_points_presence =
147 splt_douglas_peucker(gdk_points_for_douglas_peucker, douglas_peucker_callback, ui,
148 infos->douglas_peucker_thresholds[0], infos->douglas_peucker_thresholds[1],
149 infos->douglas_peucker_thresholds[2], infos->douglas_peucker_thresholds[3],
150 infos->douglas_peucker_thresholds[4], infos->douglas_peucker_thresholds[5],
151 -1.0);
152
153 g_array_free(gdk_points_for_douglas_peucker, TRUE);
154
155 clear_previous_distances(ui);
156
157 check_update_down_progress_bar(ui);
158
159 status->currently_compute_douglas_peucker_filters = FALSE;
160 }
161
162 void set_currently_scanning_for_silence_safe(gint value, ui_state *ui)
163 {
164 lock_mutex(&ui->variables_mutex);
165 ui->status->currently_scanning_for_silence = value;
166 unlock_mutex(&ui->variables_mutex);
167 }
168
169 gint get_currently_scanning_for_silence_safe(ui_state *ui)
170 {
171 lock_mutex(&ui->variables_mutex);
172 gint currently_scanning_for_silence = ui->status->currently_scanning_for_silence;
173 unlock_mutex(&ui->variables_mutex);
174
175 return currently_scanning_for_silence;
176 }
177
178 static gboolean detect_silence_end(ui_with_err *ui_err)
179 {
180 ui_state *ui = ui_err->ui;
181
182 mp3splt_set_silence_level_function(ui->mp3splt_state, NULL, NULL);
183
184 set_is_splitting_safe(FALSE, ui);
185 set_currently_scanning_for_silence_safe(FALSE, ui);
186
187 compute_douglas_peucker_filters(ui);
188
189 print_status_bar_confirmation(ui_err->err, ui);
190 gtk_widget_set_sensitive(ui->gui->cancel_button, FALSE);
191
192 refresh_drawing_area(ui->gui);
193 refresh_preview_drawing_areas(ui->gui);
194
195 set_process_in_progress_and_wait_safe(FALSE, ui_err->ui);
196
197 g_free(ui_err);
198
199 return FALSE;
200 }
201
202 static gpointer detect_silence(ui_state *ui)
203 {
204 set_process_in_progress_and_wait_safe(TRUE, ui);
205
206 set_is_splitting_safe(TRUE, ui);
207 set_currently_scanning_for_silence_safe(TRUE, ui);
208
209 if (ui->infos->silence_points)
210 {
211 g_free(ui->infos->silence_points);
212 ui->infos->silence_points = NULL;
213 ui->infos->number_of_silence_points = 0;
214 }
215
216 enter_threads();
217 gtk_widget_set_sensitive(ui->gui->cancel_button, TRUE);
218 exit_threads();
219
220 lock_mutex(&ui->variables_mutex);
221 mp3splt_set_filename_to_split(ui->mp3splt_state, get_input_filename(ui->gui));
222 unlock_mutex(&ui->variables_mutex);
223
224 mp3splt_set_silence_level_function(ui->mp3splt_state, get_silence_level, ui);
225
226 gint err = SPLT_OK;
227 mp3splt_set_silence_points(ui->mp3splt_state, &err);
228
229 ui_with_err *ui_err = g_malloc0(sizeof(ui_with_err));
230 ui_err->err = err;
231 ui_err->ui = ui;
232
233 gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)detect_silence_end, ui_err, NULL);
234
235 return NULL;
236 }
237
238 static void detect_silence_action(ui_state *ui)
239 {
240 create_thread((GThreadFunc)detect_silence, ui);
241 }
242
247 static void scan_for_silence_wave(ui_state *ui)
248 {
249 if (get_currently_scanning_for_silence_safe(ui))
250 {
251 cancel_button_event(ui->gui->cancel_button, ui);
252 }
253
254 if (ui->status->timer_active)
255 {
256 detect_silence_action(ui);
257 }
258 }
259
265 void change_current_filename(const gchar *fname, ui_state *ui)
266 {
267 const gchar *old_fname = get_input_filename(ui->gui);
268 if (!old_fname)
269 {
270 set_input_filename(fname, ui);
271
272 if (ui->status->show_silence_wave)
273 {
274 scan_for_silence_wave(ui);
275 }
276
277 if (gtk_toggle_button_get_active(ui->gui->names_from_filename))
278 {
279 copy_filename_to_current_description(fname, ui);
280 }
281
282 return;
283 }
284
285 if (strcmp(old_fname, fname) == 0)
286 {
287 return;
288 }
289
290 set_input_filename(fname, ui);
291 if (ui->status->show_silence_wave)
292 {
293 scan_for_silence_wave(ui);
294 }
295
296 if (gtk_toggle_button_get_active(ui->gui->names_from_filename))
297 {
298 copy_filename_to_current_description(fname, ui);
299 }
300 }
301
303 static void reset_inactive_progress_bar(gui_state *gui)
304 {
305 gtk_widget_set_sensitive(GTK_WIDGET(gui->progress_bar), FALSE);
306 gtk_adjustment_set_value(gui->progress_adj, 0);
307 }
308
310 static void reset_inactive_volume_button(gui_state *gui)
311 {
312 gtk_widget_set_sensitive(GTK_WIDGET(gui->volume_button), FALSE);
313 gtk_scale_button_set_value(GTK_SCALE_BUTTON(gui->volume_button), 0);
314 }
315
317 static void reset_label_time(gui_state *gui)
318 {
319 gtk_label_set_text(GTK_LABEL(gui->label_time), "");
320 }
321
323 static void reset_song_infos(gui_state *gui)
324 {
325 gtk_label_set_text(GTK_LABEL(gui->song_infos),"");
326 }
327
329 static void reset_song_name_label(gui_state *gui)
330 {
331 gtk_label_set_text(GTK_LABEL(gui->song_name_label), "");
332 }
333
335 static void clear_data_player(gui_state *gui)
336 {
337 reset_song_name_label(gui);
338 reset_song_infos(gui);
339 reset_inactive_volume_button(gui);
340 reset_inactive_progress_bar(gui);
341 reset_label_time(gui);
342 }
343
345 void enable_player_buttons(ui_state *ui)
346 {
347 gui_state *gui = ui->gui;
348
349 gtk_widget_set_sensitive(gui->stop_button, TRUE);
350 wh_set_image_on_button(GTK_BUTTON(gui->stop_button), g_object_ref(gui->StopButton_active));
351
352 gtk_widget_set_sensitive(gui->pause_button, TRUE);
353 wh_set_image_on_button(GTK_BUTTON(gui->pause_button), g_object_ref(gui->PauseButton_active));
354
355 if (ui->infos->selected_player != PLAYER_GSTREAMER)
356 {
357 gtk_widget_set_sensitive(gui->go_beg_button, TRUE);
358 wh_set_image_on_button(GTK_BUTTON(gui->go_beg_button), g_object_ref(gui->Go_BegButton_active));
359
360 gtk_widget_set_sensitive(gui->go_end_button, TRUE);
361 wh_set_image_on_button(GTK_BUTTON(gui->go_end_button), g_object_ref(gui->Go_EndButton_active));
362 }
363
364 gtk_widget_set_sensitive(gui->play_button, TRUE);
365 wh_set_image_on_button(GTK_BUTTON(gui->play_button), g_object_ref(gui->PlayButton_active));
366
367 player_key_actions_set_sensitivity(TRUE, gui);
368 }
369
371 static void disable_player_buttons(gui_state *gui)
372 {
373 gtk_widget_set_sensitive(gui->stop_button, FALSE);
374 wh_set_image_on_button(GTK_BUTTON(gui->stop_button), g_object_ref(gui->StopButton_inactive));
375
376 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gui->pause_button), FALSE);
377 gtk_widget_set_sensitive(gui->pause_button, FALSE);
378 wh_set_image_on_button(GTK_BUTTON(gui->pause_button), g_object_ref(gui->PauseButton_inactive));
379
380 gtk_widget_set_sensitive(gui->go_beg_button, FALSE);
381 wh_set_image_on_button(GTK_BUTTON(gui->go_beg_button), g_object_ref(gui->Go_BegButton_inactive));
382
383 gtk_widget_set_sensitive(gui->go_end_button, FALSE);
384 wh_set_image_on_button(GTK_BUTTON(gui->go_end_button), g_object_ref(gui->Go_EndButton_inactive));
385
386 gtk_widget_set_sensitive(gui->play_button, FALSE);
387 wh_set_image_on_button(GTK_BUTTON(gui->play_button), g_object_ref(gui->PlayButton_inactive));
388
389 gtk_widget_set_sensitive(gui->player_add_button, FALSE);
390 gtk_widget_set_sensitive(gui->silence_wave_check_button, FALSE);
391
392 player_key_actions_set_sensitivity(FALSE, gui);
393 }
394
396 static void show_disconnect_button(gui_state *gui)
397 {
398 if (!wh_container_has_child(GTK_CONTAINER(gui->player_buttons_hbox), gui->disconnect_button))
399 {
400 gtk_box_pack_start(gui->player_buttons_hbox, gui->disconnect_button, FALSE, FALSE, 7);
401 }
402
403 gtk_widget_show_all(gui->disconnect_button);
404 }
405
407 void hide_connect_button(gui_state *gui)
408 {
409 gtk_widget_hide(gui->connect_button);
410 }
411
413 static void connect_change_buttons(ui_state *ui)
414 {
415 if (ui->infos->selected_player == PLAYER_GSTREAMER)
416 {
417 return;
418 }
419
420 show_disconnect_button(ui->gui);
421 hide_connect_button(ui->gui);
422 }
423
425 static void hide_disconnect_button(gui_state *gui)
426 {
427 gtk_widget_hide(gui->disconnect_button);
428 }
429
431 void show_connect_button(gui_state *gui)
432 {
433 if (!wh_container_has_child(GTK_CONTAINER(gui->player_buttons_hbox), gui->connect_button))
434 {
435 gtk_box_pack_start(gui->player_buttons_hbox, gui->connect_button, FALSE, FALSE, 7);
436 }
437
438 gtk_widget_show_all(gui->connect_button);
439 }
440
442 static void disconnect_change_buttons(ui_state *ui)
443 {
444 if (ui->infos->selected_player == PLAYER_GSTREAMER)
445 {
446 return;
447 }
448
449 hide_disconnect_button(ui->gui);
450 show_connect_button(ui->gui);
451 }
452
460 static void connect_with_song(const gchar *fname, gint start_playing, ui_state *ui)
461 {
462 if (fname == NULL)
463 {
464 return;
465 }
466
467 gui_status *status = ui->status;
468
469 GList *song_list = NULL;
470 song_list = g_list_append(song_list, strdup(fname));
471
472 if (start_playing == 0)
473 {
474 if (!player_is_running(ui))
475 {
476 player_start_play_with_songs(song_list, ui);
477 }
478 else
479 {
480 player_add_play_files(song_list, ui);
481 }
482 }
483 else
484 {
485 if (status->file_browsed)
486 {
487 //if the player is not running, start it ,queue to playlist and
488 //play the file
489 if (!player_is_running(ui))
490 {
491 player_start_add_files(song_list, ui);
492 }
493 else
494 {
495 if (!status->playing)
496 {
497 player_add_files_and_select(song_list, ui);
498 }
499 else
500 {
501 player_add_files(song_list, ui);
502 }
503 }
504 }
505 }
506
507 status->playing = player_is_playing(ui);
508
509 if (!status->timer_active)
510 {
511 status->timeout_id = g_timeout_add(ui->infos->timeout_value, (GSourceFunc)mytimer, ui);
512 status->timer_active = TRUE;
513 }
514
515 enable_player_buttons(ui);
516
517 if (player_is_running(ui))
518 {
519 connect_change_buttons(ui);
520 }
521
522 g_list_foreach(song_list, (GFunc)g_free, NULL);
523 g_list_free(song_list);
524 }
525
531 void connect_to_player_with_song(gint i, ui_state *ui)
532 {
533 connect_with_song(get_input_filename(ui->gui), i, ui);
534 }
535
537 void connect_button_event(GtkWidget *widget, ui_state *ui)
538 {
539 gui_status *status = ui->status;
540
541 if (!player_is_running(ui))
542 {
543 player_start(ui);
544 }
545
546 mytimer(ui);
547
548 if (!status->timer_active)
549 {
550 if (ui->infos->selected_player == PLAYER_SNACKAMP)
551 {
552 connect_snackamp(8775, ui);
553 }
554
555 status->timeout_id = g_timeout_add(ui->infos->timeout_value, (GSourceFunc)mytimer, ui);
556 status->timer_active = TRUE;
557 }
558
559 //connect to player with song
560 //1 means dont start playing
561 connect_to_player_with_song(1, ui);
562
563 enable_player_buttons(ui);
564
565 status->file_browsed = FALSE;
566 status->change_volume = TRUE;
567
568 //here we check if we have been connected
569 if (player_is_running(ui))
570 {
571 connect_change_buttons(ui);
572 }
573 else
574 {
575 GtkWidget *label;
576 switch (ui->infos->selected_player)
577 {
578 case PLAYER_SNACKAMP:
579 label = gtk_label_new
580 (_("\n Cannot connect to snackAmp player.\n"
581 " Please download and install snackamp from\n"
582 "\thttp://snackamp.sourceforge.net\n\n"
583 " Verify that snackamp is running.\n"
584 " Verify that your snackamp version is >= 3.1.3\n\n"
585 " Verify that you have enabled socket interface in snackamp:\n"
586 " You have to go to\n"
587 "\tTools->Preferences->Miscellaneous\n"
588 " from the snackamp menu and check\n"
589 "\tEnable Socket Interface\n"
590 " Only default port is supported for now(8775)\n"
591 " After that, restart snackamp and mp3splt-gtk should work.\n"));
592 break;
593 case PLAYER_AUDACIOUS:
594 label = gtk_label_new
595 (_("\n Cannot connect to Audacious player.\n"
596 " Verify that you have installed audacious.\n\n"
597 " Put in your PATH variable the directory where the audacious"
598 " executable is.\n"
599 " If you don't know how to do that, start audacious manually"
600 " and then try to connect.\n"));
601 break;
602 default:
603 label = gtk_label_new(_("Cannot connect to player"));
604 break;
605 }
606
607 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Cannot connect to player"),
608 GTK_WINDOW(ui->gui->window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL);
609 g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
610 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label);
611 gtk_widget_show_all(dialog);
612 }
613
614 ui->infos->current_time = -1;
615 check_update_down_progress_bar(ui);
616
617 if (ui->status->show_silence_wave)
618 {
619 scan_for_silence_wave(ui);
620 }
621
622 mytimer(ui);
623 refresh_drawing_area(ui->gui);
624 }
625
627 static void check_stream(ui_state *ui)
628 {
629 if (((gint)ui->infos->total_time) == -1)
630 {
631 ui->status->stream = TRUE;
632 reset_inactive_progress_bar(ui->gui);
633 }
634 else
635 {
636 ui->status->stream = FALSE;
637 }
638 }
639
641 void disconnect_button_event(GtkWidget *widget, ui_state *ui)
642 {
643 gui_state *gui = ui->gui;
644
645 if (ui->status->timer_active)
646 {
647 if (ui->infos->selected_player == PLAYER_SNACKAMP)
648 {
649 disconnect_snackamp(ui);
650 }
651
652 g_source_remove(ui->status->timeout_id);
653 ui->status->timer_active = FALSE;
654 }
655
656 clear_data_player(gui);
657 disconnect_change_buttons(ui);
658 disable_player_buttons(gui);
659
660 //update bottom progress bar to 0 and ""
661 if (!get_is_splitting_safe(ui))
662 {
663 gtk_progress_bar_set_fraction(gui->percent_progress_bar, 0);
664 gtk_progress_bar_set_text(gui->percent_progress_bar, "");
665 }
666
667 const gchar *fname = get_input_filename(gui);
668 if (file_exists(fname))
669 {
670 gtk_widget_set_sensitive(gui->play_button, TRUE);
671 wh_set_image_on_button(GTK_BUTTON(gui->play_button), g_object_ref(gui->PlayButton_active));
672 }
673
674 player_quit(ui);
675
676 if (get_currently_scanning_for_silence_safe(ui))
677 {
678 cancel_button_event(ui->gui->cancel_button, ui);
679 }
680
681 refresh_drawing_area(ui->gui);
682 }
683
684 void restart_player_timer(ui_state *ui)
685 {
686 if (ui->status->timer_active)
687 {
688 g_source_remove(ui->status->timeout_id);
689 ui->status->timeout_id = g_timeout_add(ui->infos->timeout_value, (GSourceFunc)mytimer, ui);
690 }
691 }
692
694 static void play_event(GtkWidget *widget, ui_state *ui)
695 {
696 gui_state *gui = ui->gui;
697 gui_status *status = ui->status;
698
699 if (status->timer_active)
700 {
701 if (!player_is_running(ui))
702 {
703 player_start(ui);
704 }
705 player_play(ui);
706 status->playing = player_is_playing(ui);
707 }
708 else
709 {
710 //0 = also start playing
711 connect_to_player_with_song(0, ui);
712 if (ui->infos->selected_player == PLAYER_GSTREAMER &&
713 ui->status->show_silence_wave)
714 {
715 scan_for_silence_wave(ui);
716 }
717 }
718
719 gtk_widget_set_sensitive(gui->pause_button, TRUE);
720 wh_set_image_on_button(GTK_BUTTON(gui->pause_button), g_object_ref(gui->PauseButton_active));
721
722 gtk_widget_set_sensitive(gui->stop_button, TRUE);
723 wh_set_image_on_button(GTK_BUTTON(gui->stop_button), g_object_ref(gui->StopButton_active));
724 }
725
727 static void stop_event(GtkWidget *widget, ui_state *ui)
728 {
729 gui_state *gui = ui->gui;
730
731 if (!ui->status->timer_active)
732 {
733 return;
734 }
735
736 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gui->pause_button), FALSE);
737
738 if (player_is_running(ui))
739 {
740 ui->status->playing = FALSE;
741 }
742
743 player_stop(ui);
744
745 gtk_widget_set_sensitive(gui->pause_button, FALSE);
746 wh_set_image_on_button(GTK_BUTTON(gui->pause_button), g_object_ref(gui->PauseButton_inactive));
747
748 gtk_widget_set_sensitive(gui->stop_button, FALSE);
749 wh_set_image_on_button(GTK_BUTTON(gui->stop_button), g_object_ref(gui->StopButton_inactive));
750 }
751
753 void pause_event(GtkWidget *widget, ui_state *ui)
754 {
755 if (!ui->status->timer_active) { return; }
756 if (!player_is_running(ui)) { return; }
757 if (ui->status->only_press_pause) { return; }
758
759 player_pause(ui);
760 }
761
763 static void prev_button_event(GtkWidget *widget, ui_state *ui)
764 {
765 if (!ui->status->timer_active) { return; }
766 if (!player_is_running(ui)) { return; }
767 player_prev(ui);
768 }
769
771 static void next_button_event(GtkWidget *widget, ui_state *ui)
772 {
773 if (!ui->status->timer_active)
774 {
775 return;
776 }
777
778 if (!player_is_running(ui))
779 {
780 return;
781 }
782
783 player_next(ui);
784 }
785
787 static void change_song_position(ui_state *ui)
788 {
789 gint position =
790 ui->infos->player_seconds2 * 1000 +
791 ui->infos->player_minutes2 * 60000 +
792 ui->infos->player_hundr_secs2 * 10;
793
794 player_seek(position, ui);
795 }
796
798 static void toggle_show_silence_wave(GtkToggleButton *show_silence_toggle_button, ui_state *ui)
799 {
800 gui_status *status = ui->status;
801
802 if (gtk_toggle_button_get_active(show_silence_toggle_button))
803 {
804 status->show_silence_wave = TRUE;
805 scan_for_silence_wave(ui);
806 return;
807 }
808
809 status->show_silence_wave = FALSE;
810 if (get_currently_scanning_for_silence_safe(ui))
811 {
812 cancel_button_event(ui->gui->cancel_button, ui);
813 }
814
815 refresh_drawing_area(ui->gui);
816 refresh_preview_drawing_areas(ui->gui);
817
818 ui_save_preferences(NULL, ui);
819 }
820
822 static gboolean volume_button_unclick_event(GtkWidget *widget, GdkEventCrossing *event, ui_state *ui)
823 {
824 ui->status->change_volume = TRUE;
825 return FALSE;
826 }
827
829 static gboolean volume_button_click_event(GtkWidget *widget, GdkEventCrossing *event, ui_state *ui)
830 {
831 ui->status->change_volume = FALSE;
832 return FALSE;
833 }
834
836 static gboolean volume_button_enter_event(GtkWidget *widget, GdkEventCrossing *event, ui_state *ui)
837 {
838 ui->status->on_the_volume_button = TRUE;
839 return FALSE;
840 }
841
843 static gboolean volume_button_leave_event(GtkWidget *widget, GdkEventCrossing *event, ui_state *ui)
844 {
845 ui->status->on_the_volume_button = FALSE;
846 return FALSE;
847 }
848
850 static void change_volume_event(GtkScaleButton *volume_button, gdouble value, ui_state *ui)
851 {
852 if (!gtk_widget_get_sensitive(GTK_WIDGET(volume_button)))
853 {
854 return;
855 }
856
857 player_set_volume((gint)(value * 100), ui);
858 }
859
860 static GtkWidget *create_volume_button(ui_state *ui)
861 {
862 GtkWidget *volume_button = gtk_volume_button_new();
863 ui->gui->volume_button = volume_button;
864
865 g_signal_connect(G_OBJECT(volume_button), "button-press-event",
866 G_CALLBACK(volume_button_click_event), ui);
867 g_signal_connect(G_OBJECT(volume_button), "button-release-event",
868 G_CALLBACK(volume_button_unclick_event), ui);
869 g_signal_connect(G_OBJECT(volume_button), "enter-notify-event",
870 G_CALLBACK(volume_button_enter_event), ui);
871 g_signal_connect(G_OBJECT(volume_button), "leave-notify-event",
872 G_CALLBACK(volume_button_leave_event), ui);
873
874 g_signal_connect(GTK_SCALE_BUTTON(volume_button), "value_changed",
875 G_CALLBACK(change_volume_event), ui);
876
877 gtk_widget_set_sensitive(GTK_WIDGET(volume_button), FALSE);
878
879 return volume_button;
880 }
881
883 static GtkWidget *create_player_buttons_hbox(ui_state *ui)
884 {
885 GtkBox *player_buttons_hbox = GTK_BOX(wh_hbox_new());
886 ui->gui->player_buttons_hbox = player_buttons_hbox;
887
888 GString *imagefile = g_string_new("");
889 build_path(imagefile, IMAGEDIR, "backward"ICON_EXT);
890 GtkWidget *Go_BegButton_active = gtk_image_new_from_file(imagefile->str);
891 ui->gui->Go_BegButton_active = Go_BegButton_active;
892
893 build_path(imagefile, IMAGEDIR, "backward_inactive"ICON_EXT);
894 GtkWidget *Go_BegButton_inactive = gtk_image_new_from_file(imagefile->str);
895 ui->gui->Go_BegButton_inactive = Go_BegButton_inactive;
896 GtkWidget *go_beg_button = gtk_button_new();
897 ui->gui->go_beg_button = go_beg_button;
898 wh_set_image_on_button(GTK_BUTTON(go_beg_button), g_object_ref(Go_BegButton_inactive));
899
900 gtk_box_pack_start(player_buttons_hbox, go_beg_button, FALSE, FALSE, 0);
901 gtk_button_set_relief(GTK_BUTTON(go_beg_button), GTK_RELIEF_NONE);
902 g_signal_connect(G_OBJECT(go_beg_button), "clicked", G_CALLBACK(prev_button_event), ui);
903 gtk_widget_set_sensitive(go_beg_button, FALSE);
904 gtk_widget_set_tooltip_text(go_beg_button, _("Previous track"));
905
906 //play button
907 build_path(imagefile, IMAGEDIR, "play"ICON_EXT);
908 GtkWidget *PlayButton_active = gtk_image_new_from_file(imagefile->str);
909 ui->gui->PlayButton_active = PlayButton_active;
910
911 build_path(imagefile, IMAGEDIR, "play_inactive"ICON_EXT);
912 GtkWidget *PlayButton_inactive = gtk_image_new_from_file(imagefile->str);
913 ui->gui->PlayButton_inactive = PlayButton_inactive;
914 GtkWidget *play_button = gtk_button_new();
915 ui->gui->play_button = play_button;
916 wh_set_image_on_button(GTK_BUTTON(play_button), g_object_ref(PlayButton_inactive));
917
918 gtk_box_pack_start(player_buttons_hbox, play_button, FALSE, FALSE, 0);
919 gtk_button_set_relief(GTK_BUTTON(play_button), GTK_RELIEF_NONE);
920 g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play_event), ui);
921 gtk_widget_set_sensitive(play_button, FALSE);
922 gtk_widget_set_tooltip_text(play_button, _("Play"));
923
924 //pause button
925 build_path(imagefile, IMAGEDIR, "pause"ICON_EXT);
926 GtkWidget *PauseButton_active = gtk_image_new_from_file(imagefile->str);
927 ui->gui->PauseButton_active = PauseButton_active;
928
929 build_path(imagefile, IMAGEDIR, "pause_inactive"ICON_EXT);
930 GtkWidget *PauseButton_inactive = gtk_image_new_from_file(imagefile->str);
931 ui->gui->PauseButton_inactive = PauseButton_inactive;
932 GtkWidget *pause_button = gtk_toggle_button_new();
933 ui->gui->pause_button = pause_button;
934 wh_set_image_on_button(GTK_BUTTON(pause_button), g_object_ref(PauseButton_inactive));
935 gtk_box_pack_start(player_buttons_hbox, pause_button, FALSE, FALSE, 0);
936 gtk_button_set_relief(GTK_BUTTON(pause_button), GTK_RELIEF_NONE);
937 g_signal_connect(G_OBJECT(pause_button), "clicked", G_CALLBACK(pause_event), ui);
938 gtk_widget_set_sensitive(pause_button, FALSE);
939 gtk_widget_set_tooltip_text(pause_button,_("Pause"));
940
941 //stop button
942 build_path(imagefile, IMAGEDIR, "stop"ICON_EXT);
943 GtkWidget *StopButton_active = gtk_image_new_from_file(imagefile->str);
944 ui->gui->StopButton_active = StopButton_active;
945
946 build_path(imagefile, IMAGEDIR, "stop_inactive"ICON_EXT);
947 GtkWidget *StopButton_inactive = gtk_image_new_from_file(imagefile->str);
948 ui->gui->StopButton_inactive = StopButton_inactive;
949 GtkWidget *stop_button = gtk_button_new();
950 ui->gui->stop_button = stop_button;
951 wh_set_image_on_button(GTK_BUTTON(stop_button), g_object_ref(StopButton_inactive));
952 gtk_box_pack_start(player_buttons_hbox, stop_button, FALSE, FALSE, 0);
953 gtk_button_set_relief(GTK_BUTTON(stop_button), GTK_RELIEF_NONE);
954 g_signal_connect(G_OBJECT(stop_button), "clicked", G_CALLBACK(stop_event), ui);
955 gtk_widget_set_sensitive(stop_button, FALSE);
956 gtk_widget_set_tooltip_text(stop_button,_("Stop"));
957
958 //go at the end button
959 build_path(imagefile, IMAGEDIR, "forward"ICON_EXT);
960 GtkWidget *Go_EndButton_active = gtk_image_new_from_file(imagefile->str);
961 ui->gui->Go_EndButton_active = Go_EndButton_active;
962
963 build_path(imagefile, IMAGEDIR, "forward_inactive"ICON_EXT);
964 GtkWidget *Go_EndButton_inactive = gtk_image_new_from_file(imagefile->str);
965 ui->gui->Go_EndButton_inactive = Go_EndButton_inactive;
966 GtkWidget *go_end_button = gtk_button_new();
967 ui->gui->go_end_button = go_end_button;
968 wh_set_image_on_button(GTK_BUTTON(go_end_button), g_object_ref(Go_EndButton_inactive));
969 gtk_box_pack_start(player_buttons_hbox, go_end_button, FALSE, FALSE, 0);
970 gtk_button_set_relief(GTK_BUTTON(go_end_button), GTK_RELIEF_NONE);
971 g_signal_connect(G_OBJECT(go_end_button), "clicked", G_CALLBACK(next_button_event), ui);
972 gtk_widget_set_sensitive(go_end_button, FALSE);
973 gtk_widget_set_tooltip_text(go_end_button,_("Next track"));
974 g_string_free(imagefile,TRUE);
975
976 GtkWidget *vol_button = create_volume_button(ui);
977 gtk_box_pack_start(player_buttons_hbox, vol_button, FALSE, FALSE, 5);
978
979 //add button
980 GtkWidget *player_add_button = wh_create_cool_button(GTK_STOCK_ADD, _("_Add"), FALSE);
981 ui->gui->player_add_button = player_add_button;
982 gtk_box_pack_start(player_buttons_hbox, player_add_button, FALSE, FALSE, 0);
983 gtk_button_set_relief(GTK_BUTTON(player_add_button), GTK_RELIEF_NONE);
984 g_signal_connect(G_OBJECT(player_add_button), "clicked",
985 G_CALLBACK(add_splitpoint_from_player), ui);
986 gtk_widget_set_sensitive(player_add_button, FALSE);
987 gtk_widget_set_tooltip_text(player_add_button,_("Add splitpoint at the current player position"));
988
989 //set splitpoints from trim silence button
990 GtkWidget *scan_trim_silence_button = wh_create_cool_button(GTK_STOCK_CUT, NULL, FALSE);
991 ui->gui->scan_trim_silence_button_player = scan_trim_silence_button;
992 gtk_widget_set_sensitive(scan_trim_silence_button, TRUE);
993 g_signal_connect(G_OBJECT(scan_trim_silence_button), "clicked",
994 G_CALLBACK(create_trim_silence_window), ui);
995 gtk_widget_set_tooltip_text(scan_trim_silence_button,
996 _("Set trim splitpoints using silence detection"));
997 gtk_box_pack_start(player_buttons_hbox, scan_trim_silence_button, FALSE, FALSE, 0);
998 gtk_button_set_relief(GTK_BUTTON(scan_trim_silence_button), GTK_RELIEF_NONE);
999
1000 //set splitpoints from silence button
1001 GtkWidget *scan_silence_button = wh_create_cool_button(GTK_STOCK_FIND_AND_REPLACE, NULL, FALSE);
1002 ui->gui->scan_silence_button_player = scan_silence_button;
1003 gtk_widget_set_sensitive(scan_silence_button, TRUE);
1004 g_signal_connect(G_OBJECT(scan_silence_button), "clicked",
1005 G_CALLBACK(create_detect_silence_and_add_splitpoints_window), ui);
1006 gtk_widget_set_tooltip_text(scan_silence_button,
1007 _("Set splitpoints from silence detection"));
1008 gtk_box_pack_start(player_buttons_hbox, scan_silence_button, FALSE, FALSE, 0);
1009 gtk_button_set_relief(GTK_BUTTON(scan_silence_button), GTK_RELIEF_NONE);
1010
1011 //silence wave check button
1012 GtkWidget *silence_wave_check_button = gtk_check_button_new_with_mnemonic(_("Amplitude _wave"));
1013 ui->gui->silence_wave_check_button = silence_wave_check_button;
1014 gtk_box_pack_end(player_buttons_hbox, silence_wave_check_button, FALSE, FALSE, 5);
1015 g_signal_connect(G_OBJECT(silence_wave_check_button), "toggled",
1016 G_CALLBACK(toggle_show_silence_wave), ui);
1017 gtk_widget_set_sensitive(silence_wave_check_button, FALSE);
1018 gtk_widget_set_tooltip_text(silence_wave_check_button, _("Shows the amplitude level wave"));
1019
1020 /* connect player button */
1021 GtkWidget *connect_button = wh_create_cool_button(GTK_STOCK_CONNECT,_("_Connect"), FALSE);
1022 ui->gui->connect_button = connect_button;
1023 g_signal_connect(G_OBJECT(connect_button), "clicked", G_CALLBACK(connect_button_event), ui);
1024 gtk_widget_set_tooltip_text(connect_button,_("Connect to player"));
1025
1026 /* disconnect player button */
1027 GtkWidget *disconnect_button = wh_create_cool_button(GTK_STOCK_DISCONNECT,_("_Disconnect"), FALSE);
1028 ui->gui->disconnect_button = disconnect_button;
1029 g_signal_connect(G_OBJECT(disconnect_button), "clicked", G_CALLBACK(disconnect_button_event), ui);
1030 gtk_widget_set_tooltip_text(disconnect_button,_("Disconnect from player"));
1031
1032 return GTK_WIDGET(player_buttons_hbox);
1033 }
1034
1036 static GtkWidget *create_song_informations_hbox(gui_state *gui)
1037 {
1038 GtkWidget *song_info_hbox = wh_hbox_new();
1039
1040 GtkWidget *song_infos = gtk_label_new("");
1041 gui->song_infos = song_infos;
1042 gtk_box_pack_start(GTK_BOX(song_info_hbox), song_infos, FALSE, FALSE, 40);
1043
1044 GtkWidget *label_time = gtk_label_new("");
1045 gui->label_time = label_time;
1046 gtk_box_pack_start(GTK_BOX(song_info_hbox), label_time, FALSE, FALSE, 5);
1047
1048 return song_info_hbox;
1049 }
1050
1052 static gboolean progress_bar_unclick_event(GtkWidget *widget, GdkEventCrossing *event, ui_state *ui)
1053 {
1054 change_song_position(ui);
1055
1056 ui_infos *infos = ui->infos;
1057
1058 infos->player_minutes = infos->player_minutes2;
1059 infos->player_seconds = infos->player_seconds2;
1060 infos->player_hundr_secs = infos->player_hundr_secs2;
1061
1062 ui->status->mouse_on_progress_bar = FALSE;
1063
1064 return FALSE;
1065 }
1066
1068 static gboolean progress_bar_click_event(GtkWidget *widget, GdkEventCrossing *event, ui_state *ui)
1069 {
1070 ui->status->mouse_on_progress_bar = TRUE;
1071 return FALSE;
1072 }
1073
1075 static gfloat get_elapsed_time(ui_state *ui)
1076 {
1077 gfloat adj_position = gtk_adjustment_get_value(ui->gui->progress_adj);
1078 return (adj_position * ui->infos->total_time) / 100000;
1079 }
1080
1081 void refresh_drawing_area(gui_state *gui)
1082 {
1083 gtk_widget_queue_draw(gui->drawing_area);
1084 }
1085
1087 void check_update_down_progress_bar(ui_state *ui)
1088 {
1089 if (get_is_splitting_safe(ui) ||
1090 get_currently_scanning_for_silence_safe(ui) ||
1091 ui->status->currently_compute_douglas_peucker_filters)
1092 {
1093 return;
1094 }
1095
1096 gfloat progress_time = 0;
1097 gint splitpoint_time_left = -1;
1098 gint splitpoint_time_right = -1;
1099 gint splitpoint_left_index = -1;
1100 get_current_splitpoints_time_left_right(&splitpoint_time_left, &splitpoint_time_right,
1101 &splitpoint_left_index, ui);
1102
1103 if ((splitpoint_time_left != -1) && (splitpoint_time_right != -1))
1104 {
1105 gfloat total_interval = splitpoint_time_right - splitpoint_time_left;
1106 if (((gint)total_interval) != 0)
1107 {
1108 progress_time = (ui->infos->current_time-splitpoint_time_left) / total_interval;
1109 }
1110 }
1111 else
1112 {
1113 if (splitpoint_time_right == -1)
1114 {
1115 gfloat total_interval = ui->infos->total_time - splitpoint_time_left;
1116 if (((gint)total_interval) != 0)
1117 {
1118 progress_time = (ui->infos->current_time-splitpoint_time_left)/ total_interval;
1119 }
1120 }
1121 else
1122 {
1123 gfloat total_interval = splitpoint_time_right;
1124 if (((gint)total_interval) != 0)
1125 {
1126 progress_time = ui->infos->current_time/total_interval;
1127 }
1128 }
1129 }
1130
1131 if (progress_time < 0)
1132 {
1133 progress_time = 0;
1134 }
1135 if (progress_time > 1)
1136 {
1137 progress_time = 1;
1138 }
1139 if ((progress_time >= 0) && (progress_time <= 1))
1140 {
1141 gtk_progress_bar_set_fraction(ui->gui->percent_progress_bar, progress_time);
1142 }
1143
1144 gchar *progress_description = get_splitpoint_name(splitpoint_left_index-1, ui);
1145 gchar description_shorted[512] = { '\0' };
1146
1147 if (splitpoint_time_right != -1)
1148 {
1149 if (splitpoint_time_left == -1)
1150 {
1151 if (progress_description != NULL)
1152 {
1153 g_snprintf(description_shorted, 60, _("before %s"), progress_description);
1154 }
1155 }
1156 else
1157 {
1158 if (progress_description != NULL)
1159 {
1160 g_snprintf(description_shorted, 60, "%s", progress_description);
1161 }
1162 }
1163 }
1164 else
1165 {
1166 if (splitpoint_time_left != -1)
1167 {
1168 if (progress_description != NULL)
1169 {
1170 g_snprintf(description_shorted, 60, "%s", progress_description);
1171 }
1172 }
1173 else
1174 {
1175 gchar *fname = get_input_filename(ui->gui);
1176 g_snprintf(description_shorted, 60, "%s", get_real_name_from_filename(fname));
1177 }
1178 }
1179
1180 if (strlen(description_shorted) > 55)
1181 {
1182 description_shorted[56] = '.';
1183 description_shorted[57] = '.';
1184 description_shorted[58] = '.';
1185 description_shorted[59] = '\0';
1186 }
1187
1188 gtk_progress_bar_set_text(ui->gui->percent_progress_bar, description_shorted);
1189 g_free(progress_description);
1190 }
1191
1193 static void progress_bar_value_changed_event(GtkRange *range, ui_state *ui)
1194 {
1195 refresh_drawing_area(ui->gui);
1196
1197 ui_infos *infos = ui->infos;
1198
1199 infos->player_hundr_secs2 = (gint)infos->current_time % 100;
1200
1201 gint tt2 = infos->total_time / 100;
1202 gfloat adj_position = (gint)gtk_adjustment_get_value(ui->gui->progress_adj);
1203 infos->current_time = (adj_position * tt2) / 100000;
1204
1205 infos->player_seconds2 = (gint)infos->current_time % 60;
1206 infos->player_minutes2 = (gint)infos->current_time / 60;
1207
1208 infos->current_time = get_elapsed_time(ui);
1209
1210 check_update_down_progress_bar(ui);
1211 }
1212
1214 static gboolean progress_bar_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
1215 {
1216 return FALSE;
1217 }
1218
1220 static gboolean progress_bar_enter_event(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
1221 {
1222 return FALSE;
1223 }
1224
1226 static gboolean progress_bar_leave_event(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
1227 {
1228 return FALSE;
1229 }
1230
1232 static GtkWidget *create_song_bar_hbox(ui_state *ui)
1233 {
1234 GtkAdjustment *progress_adj =
1235 GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 100001.0, 0, 10000, 1));
1236 ui->gui->progress_adj = progress_adj;
1237
1238 GtkWidget *progress_bar = wh_hscale_new(progress_adj);
1239 ui->gui->progress_bar = progress_bar;
1240 g_object_set(progress_bar, "draw-value", FALSE, NULL);
1241
1242 g_signal_connect(G_OBJECT(progress_bar), "button-press-event",
1243 G_CALLBACK(progress_bar_click_event), ui);
1244 g_signal_connect(G_OBJECT(progress_bar), "button-release-event",
1245 G_CALLBACK(progress_bar_unclick_event), ui);
1246 g_signal_connect(G_OBJECT(progress_bar), "value-changed",
1247 G_CALLBACK(progress_bar_value_changed_event), ui);
1248
1249 g_signal_connect(G_OBJECT(progress_bar), "enter-notify-event",
1250 G_CALLBACK(progress_bar_enter_event), NULL);
1251 g_signal_connect(G_OBJECT(progress_bar), "leave-notify-event",
1252 G_CALLBACK(progress_bar_leave_event), NULL);
1253 g_signal_connect(G_OBJECT(progress_bar), "scroll-event",
1254 G_CALLBACK(progress_bar_scroll_event), NULL);
1255
1256 gtk_widget_set_sensitive(GTK_WIDGET(progress_bar), FALSE);
1257
1258 GtkWidget *song_bar_hbox = wh_hbox_new();
1259 gtk_box_pack_start(GTK_BOX(song_bar_hbox), progress_bar, TRUE, TRUE, 5);
1260 return song_bar_hbox;
1261 }
1262
1264 static void print_about_the_song(ui_state *ui)
1265 {
1266 gchar total_infos[512];
1267 player_get_song_infos(total_infos, ui);
1268
1269 gtk_label_set_text(GTK_LABEL(ui->gui->song_infos), total_infos);
1270 }
1271
1273 static void print_player_filename(ui_state *ui)
1274 {
1275 gchar *fname = player_get_filename(ui);
1276 if (fname != NULL)
1277 {
1278 if (strcmp(fname, "disconnect"))
1279 {
1280 change_current_filename(fname, ui);
1281 }
1282 g_free(fname);
1283 }
1284
1285 gchar *title = player_get_title(ui);
1286 if (title != NULL)
1287 {
1288 gtk_label_set_text(GTK_LABEL(ui->gui->song_name_label), title);
1289 if (title != NULL)
1290 {
1291 g_free(title);
1292 }
1293 }
1294 }
1295
1300 static void print_all_song_infos(ui_state *ui)
1301 {
1302 print_about_the_song(ui);
1303 print_player_filename(ui);
1304 }
1305
1312 static void print_song_time_elapsed(ui_state *ui)
1313 {
1314 gchar seconds[16], minutes[16], seconds_minutes[64];
1315
1316 gint time = player_get_elapsed_time(ui);
1317 ui->infos->player_hundr_secs = (time % 1000) / 10;
1318
1319 gint temp = (time/1000)/60;
1320 ui->infos->player_minutes = temp;
1321 ui->infos->player_seconds = (time/1000) - (temp*60);
1322
1323 g_snprintf(minutes, 16, "%d", temp);
1324 g_snprintf(seconds, 16, "%d", (time/1000) - (temp*60));
1325
1326 gchar total_seconds[16], total_minutes[16];
1327
1328 gint tt = ui->infos->total_time * 10;
1329 temp = (tt / 1000) / 60;
1330
1331 g_snprintf(total_minutes, 16, "%d", temp);
1332 g_snprintf(total_seconds, 16, "%d", (tt/1000) - (temp*60));
1333 g_snprintf(seconds_minutes, 64, "%s : %s / %s : %s",
1334 minutes, seconds, total_minutes, total_seconds);
1335
1336 gtk_label_set_text(GTK_LABEL(ui->gui->label_time), seconds_minutes);
1337 }
1338
1340 static void change_volume_button(ui_state *ui)
1341 {
1342 if (!player_is_running(ui))
1343 {
1344 return;
1345 }
1346
1347 gint volume = player_get_volume(ui);
1348 if (volume < 0)
1349 {
1350 return;
1351 }
1352
1353 gtk_scale_button_set_value(GTK_SCALE_BUTTON(ui->gui->volume_button), volume / 100.0);
1354 }
1355
1356 void set_quick_preview_end_splitpoint_safe(gint value, ui_state *ui)
1357 {
1358 lock_mutex(&ui->variables_mutex);
1359 ui->status->quick_preview_end_splitpoint = value;
1360 unlock_mutex(&ui->variables_mutex);
1361 }
1362
1363 gint get_quick_preview_end_splitpoint_safe(ui_state *ui)
1364 {
1365 lock_mutex(&ui->variables_mutex);
1366 gint quick_preview_end_splitpoint = ui->status->quick_preview_end_splitpoint;
1367 unlock_mutex(&ui->variables_mutex);
1368 return quick_preview_end_splitpoint;
1369 }
1370
1372 static void change_progress_bar(ui_state *ui)
1373 {
1374 gui_status *status = ui->status;
1375 ui_infos *infos = ui->infos;
1376
1377 if (!player_is_running(ui) || status->mouse_on_progress_bar)
1378 {
1379 refresh_drawing_area(ui->gui);
1380 return;
1381 }
1382
1383 infos->total_time = player_get_total_time(ui) / 10;
1384
1385 infos->current_time = infos->player_seconds * 100 +
1386 infos->player_minutes * 6000 +
1387 infos->player_hundr_secs;
1388
1389 gdouble adj_position = (infos->current_time * 100000) / infos->total_time;
1390 gtk_adjustment_set_value(ui->gui->progress_adj, adj_position);
1391
1392 infos->current_time = get_elapsed_time(ui);
1393
1394 gint stop_splitpoint = get_splitpoint_time(get_quick_preview_end_splitpoint_safe(ui), ui);
1395 gint start_splitpoint = get_splitpoint_time(status->preview_start_splitpoint, ui);
1396 if ((stop_splitpoint < (gint)(infos->current_time-150)) ||
1397 (start_splitpoint > (gint)(infos->current_time+150)))
1398 {
1399 cancel_quick_preview(status);
1400 }
1401 }
1402
1404 static GtkWidget *create_filename_player_hbox(gui_state *gui)
1405 {
1406 GtkWidget *song_name_label = gtk_label_new("");
1407 gtk_label_set_selectable(GTK_LABEL(song_name_label), TRUE);
1408 gui->song_name_label = song_name_label;
1409
1410 g_object_set(G_OBJECT(song_name_label), "selectable", FALSE, NULL);
1411
1412 gtk_label_set_ellipsize(GTK_LABEL(song_name_label), PANGO_ELLIPSIZE_END);
1413
1414 GtkWidget *filename_player_hbox = wh_hbox_new();
1415
1416 #if GTK_MAJOR_VERSION <= 2
1417 //ellipsize does not work as in gtk+2, so we show the label in the middle
1418 gtk_box_pack_start(GTK_BOX(filename_player_hbox), song_name_label,
1419 TRUE, TRUE, 15);
1420 #else
1421 gtk_box_pack_start(GTK_BOX(filename_player_hbox), song_name_label, FALSE, FALSE, 15);
1422 #endif
1423
1424 return filename_player_hbox;
1425 }
1426
1428 gfloat get_right_drawing_time(gfloat current_time, gfloat total_time, gfloat zoom_coeff)
1429 {
1430 gfloat right = total_time / zoom_coeff;
1431 gfloat center = right/2;
1432 gfloat offset = current_time - center;
1433 return right + offset;
1434 }
1435
1437 gfloat get_left_drawing_time(gfloat current_time, gfloat total_time, gfloat zoom_coeff)
1438 {
1439 gfloat right = total_time / zoom_coeff;
1440 gfloat center = right/2;
1441 return current_time - center;
1442 }
1443
1449 static gchar *get_time_for_drawing(gchar *str, gint time, gboolean hundr_or_not, gint *number_of_chars)
1450 {
1451 gint mins = time / 6000;
1452 gint secs = (time / 100) % 60;
1453
1454 if (hundr_or_not)
1455 {
1456 gint hundr = time % 100;
1457 *number_of_chars = g_snprintf(str, 30, "%d:%02d:%02d", mins, secs, hundr);
1458 }
1459 else
1460 {
1461 *number_of_chars = g_snprintf(str, 30, "%d:%02d", mins, secs);
1462 }
1463
1464 return str;
1465 }
1466
1467 //transform pixels to time
1468 static gfloat pixels_to_time(gfloat width, gint pixels, ui_state *ui)
1469 {
1470 return (ui->infos->total_time * (gfloat)pixels)/(width * ui->infos->zoom_coeff);
1471 }
1472
1473 static gfloat time_to_pixels_float(gint width, gfloat time, gfloat total_time, gfloat zoom_coeff)
1474 {
1475 return width * time * zoom_coeff / total_time;
1476 }
1477
1478 static gint time_to_pixels(gint width, gfloat time, gfloat total_time, gfloat zoom_coeff)
1479 {
1480 return roundf(time_to_pixels_float(width, time, total_time, zoom_coeff));
1481 }
1482
1488 static gint convert_time_to_pixels(gint width, gfloat time,
1489 gfloat current_time, gfloat total_time, gfloat zoom_coeff)
1490 {
1491 return width/2 + time_to_pixels(width, time - current_time, total_time, zoom_coeff);
1492 }
1493
1494 static void draw_motif(GtkWidget *da, cairo_t *gc, gint ylimit, gint x, gint time_interval)
1495 {
1496 GdkColor color;
1497 switch (time_interval)
1498 {
1499 case HUNDR_SECONDS:
1500 color.red = 65000;color.green = 0;color.blue = 0;
1501 break;
1502 case TENS_OF_SECONDS:
1503 color.red = 0;color.green = 0;color.blue = 65000;
1504 break;
1505 case SECONDS:
1506 color.red = 0;color.green = 65000;color.blue = 0;
1507 break;
1508 case TEN_SECONDS:
1509 color.red = 65000;color.green = 0;color.blue = 40000;
1510 break;
1511 case MINUTES:
1512 color.red = 1000;color.green = 10000;color.blue = 65000;
1513 break;
1514 case TEN_MINUTES:
1515 color.red = 65000;color.green = 0;color.blue = 0;
1516 break;
1517 case HOURS:
1518 color.red = 0;color.green = 0;color.blue = 0;
1519 break;
1520 default:
1521 break;
1522 }
1523
1524 dh_set_color(gc, &color);
1525
1526 draw_point(gc, x, ylimit+6);
1527 draw_point(gc, x, ylimit+7);
1528 draw_point(gc, x, ylimit+8);
1529 draw_point(gc, x-1, ylimit+8);
1530 draw_point(gc, x+1, ylimit+8);
1531 draw_point(gc, x, ylimit+9);
1532 draw_point(gc, x-1, ylimit+9);
1533 draw_point(gc, x+1, ylimit+9);
1534 draw_point(gc, x-2, ylimit+9);
1535 draw_point(gc, x+2, ylimit+9);
1536 draw_point(gc, x-3, ylimit+9);
1537 draw_point(gc, x+3, ylimit+9);
1538 draw_point(gc, x, ylimit+10);
1539 draw_point(gc, x-1, ylimit+10);
1540 draw_point(gc, x+1, ylimit+10);
1541 draw_point(gc, x-2, ylimit+10);
1542 draw_point(gc, x+2, ylimit+10);
1543 draw_point(gc, x-3, ylimit+10);
1544 draw_point(gc, x+3, ylimit+10);
1545
1546 cairo_stroke(gc);
1547 }
1548
1550 static void draw_marks(gint time_interval, gint left_mark,
1551 gint right_mark, gint ylimit, GtkWidget *da, cairo_t *gc, ui_state *ui)
1552 {
1553 gint left2 = (left_mark / time_interval) * time_interval;
1554 if (left2 < left_mark)
1555 {
1556 left2 += time_interval;
1557 }
1558
1559 gint i;
1560 gint i_pixel;
1561 for (i = left2; i <= right_mark; i += time_interval)
1562 {
1563 i_pixel = convert_time_to_pixels(ui->infos->width_drawing_area, i,
1564 ui->infos->current_time, ui->infos->total_time, ui->infos->zoom_coeff);
1565
1566 draw_motif(da, gc, ylimit, i_pixel, time_interval);
1567 }
1568 }
1569
1571 void cancel_quick_preview_all(ui_state *ui)
1572 {
1573 cancel_quick_preview(ui->status);
1574 set_quick_preview_end_splitpoint_safe(-1, ui);
1575 ui->status->preview_start_splitpoint = -1;
1576 }
1577
1579 void cancel_quick_preview(gui_status *status)
1580 {
1581 status->quick_preview = FALSE;
1582 }
1583
1592 static void draw_motif_splitpoints(GtkWidget *da, cairo_t *gc,
1593 gint x, gint draw, gint current_point_hundr_secs,
1594 gboolean move, gint number_splitpoint, ui_state *ui)
1595 {
1596 int m = ui->gui->margin - 1;
1597
1598 Split_point point = g_array_index(ui->splitpoints, Split_point, number_splitpoint);
1599 gboolean splitpoint_checked = point.checked;
1600
1601 GdkColor color;
1602 color.red = 255 * 212; color.green = 255 * 100; color.blue = 255 * 200;
1603 dh_set_color(gc, &color);
1604
1605 //if it' the splitpoint we move, don't fill in the circle and the square
1606 if (!draw)
1607 {
1608 dh_draw_rectangle(gc, FALSE, x-6,4, 11,11);
1609 }
1610 else
1611 {
1612 dh_draw_rectangle(gc, TRUE, x-6,4, 12,12);
1613
1614 if (number_splitpoint == get_first_splitpoint_selected(ui->gui))
1615 {
1616 color.red = 255 * 220; color.green = 255 * 220; color.blue = 255 * 255;
1617 dh_set_color(gc, &color);
1618
1619 dh_draw_rectangle(gc, TRUE, x-4,6, 8,8);
1620 }
1621 }
1622
1623 color.red = 255 * 212; color.green = 255 * 196; color.blue = 255 * 221;
1624 dh_set_color(gc, &color);
1625
1626 gint i = 0;
1627 for(i = 0;i < 5;i++)
1628 {
1629 draw_point(gc, x+i, ui->gui->erase_split_ylimit + m + 3);
1630 draw_point(gc, x-i, ui->gui->erase_split_ylimit + m + 3);
1631 draw_point(gc, x+i, ui->gui->erase_split_ylimit + m + 4);
1632 draw_point(gc, x-i, ui->gui->erase_split_ylimit + m + 4);
1633 }
1634 cairo_stroke(gc);
1635
1636 if (move)
1637 {
1638 if (splitpoint_checked)
1639 {
1640 color.red = 15000;color.green = 40000;color.blue = 25000;
1641 }
1642 else
1643 {
1644 color.red = 25000;color.green = 25000;color.blue = 40000;
1645 }
1646 dh_set_color(gc, &color);
1647
1648 dh_draw_line(gc, x, ui->gui->erase_split_ylimit + m -8, x, ui->gui->progress_ylimit + m, TRUE, TRUE);
1649 }
1650
1651 color.red = 255 * 22; color.green = 255 * 35; color.blue = 255 * 91;
1652 dh_set_color(gc, &color);
1653
1654 //draw the splitpoint motif
1655 for (i = -3;i <= 1;i++)
1656 {
1657 draw_point(gc, x, ui->gui->erase_split_ylimit + m +i);
1658 }
1659 for (i = 2;i <= 5;i++)
1660 {
1661 draw_point(gc, x, ui->gui->erase_split_ylimit + m + i);
1662 }
1663 for (i = 3;i <= 4;i++)
1664 {
1665 draw_point(gc, x-1, ui->gui->erase_split_ylimit + m + i);
1666 draw_point(gc, x+1, ui->gui->erase_split_ylimit + m + i);
1667 }
1668 for (i = 6;i <= 11;i++)
1669 {
1670 draw_point(gc, x, ui->gui->erase_split_ylimit + m + i);
1671 }
1672
1673 //bottom splitpoint vertical bar
1674 for (i = 0;i < ui->gui->margin;i++)
1675 {
1676 draw_point(gc, x, ui->gui->progress_ylimit + m - i);
1677 }
1678
1679 //bottom checkbox vertical bar
1680 for (i = 0;i < ui->gui->margin;i++)
1681 {
1682 draw_point(gc, x, ui->gui->splitpoint_ypos + m - i - 1);
1683 }
1684 cairo_stroke(gc);
1685
1686 //bottom rectangle
1687 dh_set_color(gc, &color);
1688 color.red = 25000;color.green = 25000;color.blue = 25000;
1689 dh_draw_rectangle(gc, FALSE, x-6, ui->gui->splitpoint_ypos + m, 12,12);
1690
1691 //draw a cross with 2 lines if the splitpoint is checked
1692 if (splitpoint_checked)
1693 {
1694 gint left = x - 6;
1695 gint right = x + 6;
1696 gint top = ui->gui->splitpoint_ypos + m;
1697 gint bottom = ui->gui->splitpoint_ypos + m + 12;
1698 dh_draw_line(gc, left, top, right, bottom, FALSE, TRUE);
1699 dh_draw_line(gc, left, bottom, right, top, FALSE, TRUE);
1700 }
1701
1702 //-if the splitpoint is checked, set green color
1703 if (splitpoint_checked)
1704 {
1705 color.red = 15000;color.green = 40000;color.blue = 25000;
1706 }
1707 else
1708 {
1709 color.red = 25000;color.green = 25000;color.blue = 40000;
1710 }
1711 dh_set_color(gc, &color);
1712
1713 dh_draw_arc(gc, FALSE, x, ui->gui->progress_ylimit + m+ 1 + 7, 14 / 2, 0, 2 * G_PI);
1714
1715 //only fill the circle if we don't move that splitpoint
1716 if (draw)
1717 {
1718 dh_draw_arc(gc, TRUE, x, ui->gui->progress_ylimit + m + 1 + 8, 16 / 2, 0, 2 * G_PI);
1719 }
1720
1721 if (draw)
1722 {
1723 gint number_of_chars = 0;
1724 gchar str[30] = { '\0' };
1725 get_time_for_drawing(str, current_point_hundr_secs, TRUE, &number_of_chars);
1726 dh_draw_text(gc, str, x - (number_of_chars * 3), ui->gui->checkbox_ypos + ui->gui->margin - 1);
1727 }
1728
1729 if (ui->status->show_silence_wave)
1730 {
1731 color.red = 0;color.green = 0;color.blue = 0;
1732 dh_set_color(gc, &color);
1733 dh_draw_line(gc, x,ui->gui->text_ypos + ui->gui->margin, x,ui->gui->wave_ypos, move, TRUE);
1734 }
1735 }
1736
1738 static void draw_splitpoints(gint left_mark, gint right_mark, GtkWidget *da, cairo_t *gc,
1739 ui_state *ui)
1740 {
1741 gint i = 0;
1742 for(i = 0; i < ui->infos->splitnumber; i++ )
1743 {
1744 gint current_point_hundr_secs = get_splitpoint_time(i, ui);
1745 if ((current_point_hundr_secs <= right_mark) &&
1746 (current_point_hundr_secs >= left_mark))
1747 {
1748 gint split_pixel =
1749 convert_time_to_pixels(ui->infos->width_drawing_area, current_point_hundr_secs,
1750 ui->infos->current_time, ui->infos->total_time, ui->infos->zoom_coeff);
1751
1752 //the splitpoint that we move, draw it differently
1753 gboolean draw = TRUE;
1754 if (ui->status->splitpoint_to_move == i)
1755 {
1756 draw = FALSE;
1757 }
1758
1759 draw_motif_splitpoints(da, gc, split_pixel, draw, current_point_hundr_secs, FALSE, i, ui);
1760 }
1761 }
1762 }
1763
1764 static gint get_silence_filtered_presence_index(gfloat draw_time, ui_infos *infos)
1765 {
1766 //num_of_points_coeff_f : ogg ~= 1, mp3 ~= 4
1767 gfloat num_of_points_coeff_f =
1768 ceil((infos->number_of_silence_points / infos->total_time) * 10);
1769 gint num_of_points_coeff = (gint)num_of_points_coeff_f;
1770
1771 if (draw_time > infos->fourty_minutes_time)
1772 {
1773 if (num_of_points_coeff < 3)
1774 {
1775 return 2;
1776 }
1777 return 4;
1778 }
1779
1780 if (draw_time > infos->twenty_minutes_time)
1781 {
1782 if (num_of_points_coeff < 3)
1783 {
1784 return 1;
1785 }
1786 return 3;
1787 }
1788
1789 if (draw_time > infos->ten_minutes_time)
1790 {
1791 if (num_of_points_coeff < 3)
1792 {
1793 return 0;
1794 }
1795 return 2;
1796 }
1797
1798 if (draw_time > infos->six_minutes_time)
1799 {
1800 if (num_of_points_coeff < 3)
1801 {
1802 return -1;
1803 }
1804 return 1;
1805 }
1806
1807 if (draw_time > infos->three_minutes_time)
1808 {
1809 if (num_of_points_coeff < 3)
1810 {
1811 return -1;
1812 }
1813 return 0;
1814 }
1815
1816 return -1;
1817 }
1818
1819 static gint point_is_filtered(gint index, gint filtered_index, ui_infos *infos)
1820 {
1821 if (!infos->filtered_points_presence)
1822 {
1823 return TRUE;
1824 }
1825
1826 GArray *points_presence = g_ptr_array_index(infos->filtered_points_presence, filtered_index);
1827 return !g_array_index(points_presence, gint, index);
1828 }
1829
1830 static gint adjust_filtered_index_according_to_number_of_points(gint filtered_index,
1831 gint left_mark, gint right_mark, ui_state *ui)
1832 {
1833 ui_infos *infos = ui->infos;
1834
1835 if (filtered_index == 5)
1836 {
1837 return filtered_index;
1838 }
1839
1840 gint number_of_points = 0;
1841 gint number_of_filtered_points = 0;
1842
1843 gint i = 0;
1844 for (i = 0;i < infos->number_of_silence_points;i++)
1845 {
1846 long time = infos->silence_points[i].time;
1847 if ((time > right_mark) || (time < left_mark))
1848 {
1849 continue;
1850 }
1851
1852 if (filtered_index >= 0 && point_is_filtered(i, filtered_index, infos))
1853 {
1854 number_of_filtered_points++;
1855 }
1856
1857 number_of_points++;
1858 }
1859
1860 if (number_of_points <= ui->infos->silence_wave_number_of_points_threshold)
1861 {
1862 return -1;
1863 }
1864
1865 if (number_of_points - number_of_filtered_points > ui->infos->silence_wave_number_of_points_threshold)
1866 {
1867 return filtered_index + 1;
1868 }
1869
1870 return filtered_index;
1871 }
1872
1874 gint draw_silence_wave(gint left_mark, gint right_mark,
1875 gint interpolation_text_x, gint interpolation_text_y,
1876 gfloat draw_time, gint width_drawing_area, gint y_margin,
1877 gfloat current_time, gfloat total_time, gfloat zoom_coeff,
1878 GtkWidget *da, cairo_t *gc, ui_state *ui)
1879 {
1880 if (ui->status->currently_compute_douglas_peucker_filters ||
1881 get_currently_scanning_for_silence_safe(ui))
1882 {
1883 return -1;
1884 }
1885
1886 GdkColor color;
1887
1888 if (!ui->infos->silence_points)
1889 {
1890 color.red = 0;color.green = 0;color.blue = 0;
1891 dh_set_color(gc, &color);
1892 dh_draw_text_with_size(gc,_("No available wave"),
1893 interpolation_text_x, interpolation_text_y, 13);
1894 return -1;
1895 }
1896
1897 double dashes[] = { 1.0, 3.0 };
1898 cairo_set_dash(gc, dashes, 0, 0.0);
1899 cairo_set_line_width(gc, 1.0);
1900 cairo_set_line_cap(gc, CAIRO_LINE_CAP_ROUND);
1901
1902 color.red = 0;color.green = 0;color.blue = 0;
1903 dh_set_color(gc, &color);
1904
1905 gint filtered_index = get_silence_filtered_presence_index(draw_time, ui->infos);
1906 gint interpolation_level =
1907 adjust_filtered_index_according_to_number_of_points(filtered_index, left_mark, right_mark, ui);
1908
1909 gint stroke_counter = 0;
1910
1911 if (!double_equals(zoom_coeff, ui->status->previous_zoom_coeff) ||
1912 interpolation_level != ui->status->previous_interpolation_level)
1913 {
1914 clear_previous_distances(ui);
1915 }
1916 ui->status->previous_zoom_coeff = zoom_coeff;
1917 ui->status->previous_interpolation_level = interpolation_level;
1918
1919 GHashTable* distance_by_time = g_hash_table_new_full(g_int64_hash, g_int64_equal, g_free, g_free);
1920
1921 gint i = 0;
1922 gint previous_x = 0;
1923 long second_splitpoint_time = -2;
1924 gint second_splitpoint_time_displayed = 0;
1925 gint missed_lookups = 0;
1926 gint time_counter = 0;
1927 for (i = 0;i < ui->infos->number_of_silence_points;i++)
1928 {
1929 if (interpolation_level >= 0 && point_is_filtered(i, interpolation_level, ui->infos))
1930 {
1931 continue;
1932 }
1933
1934 long time = ui->infos->silence_points[i].time;
1935 if (time_counter == 1)
1936 {
1937 second_splitpoint_time = time;
1938 }
1939 time_counter++;
1940
1941 if ((time > right_mark) || (time < left_mark))
1942 {
1943 continue;
1944 }
1945
1946 float level = ui->infos->silence_points[i].level;
1947
1948 gint x =
1949 convert_time_to_pixels(width_drawing_area, (gfloat)time, current_time, total_time, zoom_coeff);
1950 gint y = y_margin + (gint)floorf(level);
1951
1952 if (time > second_splitpoint_time && second_splitpoint_time > -2)
1953 {
1954 gint64 *time_key = g_new(gint64, 1);
1955 *time_key = (gint64)time;
1956
1957 gint *has_distance = g_hash_table_lookup(distance_by_time, time_key);
1958 if (has_distance != NULL) { continue; }
1959
1960 if (ui->status->previous_distance_by_time != NULL)
1961 {
1962 gint *previous_diff =
1963 g_hash_table_lookup(ui->status->previous_distance_by_time, time_key);
1964
1965 //if we miss some lookups at the start, invalid distances
1966 if (previous_diff == NULL && stroke_counter < 20)
1967 {
1968 missed_lookups++;
1969 if (missed_lookups > 3)
1970 {
1971 clear_previous_distances(ui);
1972 }
1973 }
1974
1975 if (previous_diff != NULL && stroke_counter > 0)
1976 {
1977 x = previous_x + *previous_diff;
1978 if (stroke_counter == 1)
1979 {
1980 ui->status->previous_second_x_drawed = x;
1981 ui->status->previous_second_time_drawed = time;
1982 }
1983 }
1984 else if (stroke_counter == 0 && !second_splitpoint_time_displayed)
1985 {
1986 if (x < 0) { x = 0; }
1987
1988 //the first point always needs to grow up
1989 if (time == ui->status->previous_first_time_drawed &&
1990 x > ui->status->previous_first_x_drawed)
1991 {
1992 x = ui->status->previous_first_x_drawed;
1993 }
1994 else
1995 {
1996 //when the second point becomes the first point, dont make it grow
1997 if (time == ui->status->previous_second_time_drawed &&
1998 x > ui->status->previous_second_x_drawed)
1999 {
2000 x = ui->status->previous_second_x_drawed;
2001 }
2002
2003 ui->status->previous_first_time_drawed = time;
2004 ui->status->previous_first_x_drawed = x;
2005 }
2006 }
2007 }
2008
2009 gint *diff = g_new(gint, 1);
2010 *diff = x - previous_x;
2011 if (*diff < 0) { *diff = 0; }
2012
2013 g_hash_table_insert(distance_by_time, time_key, diff);
2014 }
2015 else if (time == second_splitpoint_time)
2016 {
2017 second_splitpoint_time_displayed = 1;
2018 }
2019
2020 previous_x = x;
2021
2022 cairo_line_to(gc, x, y);
2023
2024 stroke_counter++;
2025 if (stroke_counter % 4 == 0)
2026 {
2027 cairo_stroke(gc);
2028 }
2029 cairo_move_to(gc, x, y);
2030 }
2031
2032 if (ui->status->previous_distance_by_time != NULL)
2033 {
2034 g_hash_table_destroy(ui->status->previous_distance_by_time);
2035 }
2036 ui->status->previous_distance_by_time = distance_by_time;
2037
2038 cairo_stroke(gc);
2039
2040 color.red = 0;color.green = 0;color.blue = 0;
2041 dh_set_color(gc, &color);
2042
2043 if (interpolation_level < 0)
2044 {
2045 dh_draw_text_with_size(gc,_("No wave interpolation"),
2046 interpolation_text_x, interpolation_text_y, 13);
2047 }
2048 else
2049 {
2050 gchar interpolation_text[128] = { '\0' };
2051 g_snprintf(interpolation_text, 128, _("Wave interpolation level %d"), interpolation_level + 1);
2052 dh_draw_text_with_size(gc, interpolation_text, interpolation_text_x, interpolation_text_y, 13);
2053 }
2054
2055 return interpolation_level;
2056 }
2057
2058 void clear_previous_distances(ui_state *ui)
2059 {
2060 gui_status *status = ui->status;
2061
2062 if (status->previous_distance_by_time != NULL)
2063 {
2064 g_hash_table_destroy(status->previous_distance_by_time);
2065 status->previous_distance_by_time = NULL;
2066 }
2067
2068 status->previous_first_time_drawed = -2;
2069 status->previous_first_x_drawed = -2;
2070 status->previous_second_x_drawed = -2;
2071 status->previous_second_time_drawed = -2;
2072 }
2073
2074 static void draw_rectangles_between_splitpoints(cairo_t *cairo_surface, ui_state *ui)
2075 {
2076 GdkColor color;
2077
2078 //yellow small rectangle
2079 gint point_time_left = -1;
2080 gint point_time_right = -1;
2081 get_current_splitpoints_time_left_right(&point_time_left, &point_time_right, NULL, ui);
2082 color.red = 255 * 255;color.green = 255 * 255;color.blue = 255 * 210;
2083 draw_small_rectangle(point_time_left, point_time_right, color, cairo_surface, ui);
2084
2085 gint gray_factor = 210;
2086 color.red = 255 * gray_factor;color.green = 255 * gray_factor;color.blue = 255 * gray_factor;
2087
2088 //gray areas
2089 if (ui->infos->splitnumber == 0)
2090 {
2091 draw_small_rectangle(0, ui->infos->total_time, color, cairo_surface, ui);
2092 return;
2093 }
2094
2095 draw_small_rectangle(0, get_splitpoint_time(0, ui), color, cairo_surface, ui);
2096 draw_small_rectangle(get_splitpoint_time(ui->infos->splitnumber-1, ui), ui->infos->total_time,
2097 color, cairo_surface, ui);
2098 gint i = 0;
2099 for (i = 0; i < ui->infos->splitnumber - 1; i++ )
2100 {
2101 Split_point point = g_array_index(ui->splitpoints, Split_point, i);
2102 if (!point.checked)
2103 {
2104 gint left_time = get_splitpoint_time(i, ui);
2105 gint right_time = get_splitpoint_time(i+1, ui);
2106 draw_small_rectangle(left_time, right_time, color, cairo_surface, ui);
2107 }
2108 }
2109 }
2110
2111 #if GTK_MAJOR_VERSION <= 2
2112 static gboolean da_draw_event(GtkWidget *da, GdkEventExpose *event, ui_state *ui)
2113 {
2114 cairo_t *gc = gdk_cairo_create(da->window);
2115 #else
2116 static gboolean da_draw_event(GtkWidget *da, cairo_t *gc, ui_state *ui)
2117 {
2118 #endif
2119
2120 ui_infos *infos = ui->infos;
2121 gui_state *gui = ui->gui;
2122 gui_status *status = ui->status;
2123
2124 #ifdef __WIN32__
2125 if ((status->playing || status->timer_active) &&
2126 get_process_in_progress_safe(ui))
2127 {
2128 GdkColor mycolor;
2129 mycolor.red = 255 * 0; mycolor.green = 255 * 0; mycolor.blue = 255 * 255;
2130 dh_set_color(gc, &mycolor);
2131 dh_draw_text_with_size(gc, _(" Please wait for the process to finish ..."),
2132 30, gui->margin - 3, 13);
2133
2134 return TRUE;
2135 }
2136 #endif
2137
2138 set_process_in_progress_safe(TRUE, ui);
2139
2140 if (gui->drawing_area_expander != NULL &&
2141 !gtk_expander_get_expanded(GTK_EXPANDER(gui->drawing_area_expander)))
2142 {
2143 set_process_in_progress_safe(FALSE, ui);
2144 return TRUE;
2145 }
2146
2147 //on a slow hardware, this improves a lot the computing performance
2148 if (status->currently_compute_douglas_peucker_filters)
2149 {
2150 GdkColor mycolor;
2151 mycolor.red = 255 * 0; mycolor.green = 255 * 0; mycolor.blue = 255 * 255;
2152 dh_set_color(gc, &mycolor);
2153 dh_draw_text_with_size(gc, _(" Please wait ... currently computing Douglas Peucker filters."),
2154 30, gui->margin - 3, 13);
2155
2156 set_process_in_progress_safe(FALSE, ui);
2157 return TRUE;
2158 }
2159
2160 gint old_width_drawing_area = infos->width_drawing_area;
2161
2162 int width = 0, height = 0;
2163 wh_get_widget_size(da, &width, &height);
2164 if (status->show_silence_wave)
2165 {
2166 if (height != DRAWING_AREA_HEIGHT_WITH_SILENCE_WAVE)
2167 {
2168 gtk_widget_set_size_request(da, DRAWING_AREA_WIDTH, DRAWING_AREA_HEIGHT_WITH_SILENCE_WAVE);
2169 }
2170 }
2171 else
2172 {
2173 if (height != DRAWING_AREA_HEIGHT)
2174 {
2175 gtk_widget_set_size_request(da, DRAWING_AREA_WIDTH, DRAWING_AREA_HEIGHT);
2176 }
2177 }
2178
2179 gint real_progress_length = 26;
2180 gint real_text_length = 12;
2181
2182 gint erase_splitpoint_length = gui->real_erase_split_length + (gui->margin * 2);
2183 gint progress_length = real_progress_length + gui->margin;
2184 gint move_split_length = gui->real_move_split_length + gui->margin;
2185 gint text_length = real_text_length + gui->margin;
2186 gint checkbox_length = gui->real_checkbox_length + gui->margin;
2187 gint wave_length = gui->real_wave_length + gui->margin;
2188
2189 //
2190 gui->erase_split_ylimit = erase_splitpoint_length;
2191 gui->progress_ylimit = gui->erase_split_ylimit + progress_length;
2192 gui->splitpoint_ypos = gui->progress_ylimit + move_split_length;
2193 gui->checkbox_ypos = gui->splitpoint_ypos + checkbox_length;
2194 gui->text_ypos = gui->checkbox_ypos + text_length + gui->margin;
2195 gui->wave_ypos = gui->text_ypos + wave_length + gui->margin;
2196
2197 gint bottom_left_middle_right_text_ypos = gui->text_ypos;
2198 if (status->show_silence_wave)
2199 {
2200 bottom_left_middle_right_text_ypos = gui->wave_ypos;
2201 }
2202
2203 gint nbr_chars = 0;
2204
2205 wh_get_widget_size(da, &infos->width_drawing_area, NULL);
2206
2207 if (infos->width_drawing_area != old_width_drawing_area)
2208 {
2209 refresh_preview_drawing_areas(gui);
2210 }
2211
2212 GdkColor color;
2213 color.red = 255 * 235;color.green = 255 * 235; color.blue = 255 * 235;
2214 dh_set_color(gc, &color);
2215
2216 //background rectangle
2217 dh_draw_rectangle(gc, TRUE, 0,0, infos->width_drawing_area, gui->wave_ypos + text_length + 2);
2218
2219 color.red = 255 * 255;color.green = 255 * 255;color.blue = 255 * 255;
2220 dh_set_color(gc, &color);
2221
2222 //background white rectangles
2223 dh_draw_rectangle(gc, TRUE, 0, gui->margin, infos->width_drawing_area, gui->real_erase_split_length);
2224 dh_draw_rectangle(gc, TRUE, 0, gui->erase_split_ylimit, infos->width_drawing_area, progress_length);
2225 dh_draw_rectangle(gc, TRUE, 0, gui->progress_ylimit+gui->margin, infos->width_drawing_area, gui->real_move_split_length);
2226 dh_draw_rectangle(gc, TRUE, 0, gui->splitpoint_ypos+gui->margin, infos->width_drawing_area, gui->real_checkbox_length);
2227 dh_draw_rectangle(gc, TRUE, 0, gui->checkbox_ypos+gui->margin, infos->width_drawing_area, text_length);
2228 if (status->show_silence_wave)
2229 {
2230 dh_draw_rectangle(gc, TRUE, 0, gui->text_ypos + gui->margin, infos->width_drawing_area, wave_length);
2231 }
2232
2233 if (!status->playing || !status->timer_active)
2234 {
2235 color.red = 255 * 212; color.green = 255 * 100; color.blue = 255 * 200;
2236 dh_set_color(gc, &color);
2237 dh_draw_text(gc, _(" left click on splitpoint selects it, right click erases it"),
2238 0, gui->margin - 3);
2239
2240 color.red = 0;color.green = 0;color.blue = 0;
2241 dh_set_color(gc, &color);
2242 dh_draw_text(gc, _(" left click + move changes song position, right click + move changes zoom"),
2243 0, gui->erase_split_ylimit + gui->margin);
2244
2245 color.red = 15000;color.green = 40000;color.blue = 25000;
2246 dh_set_color(gc, &color);
2247 dh_draw_text(gc,
2248 _(" left click on point + move changes point position, right click play preview"),
2249 0, gui->progress_ylimit + gui->margin);
2250
2251 color.red = 0; color.green = 0; color.blue = 0;
2252 dh_set_color(gc, &color);
2253 dh_draw_text(gc, _(" left click on rectangle checks/unchecks 'keep splitpoint'"),
2254 0, gui->splitpoint_ypos + 1);
2255
2256 set_process_in_progress_safe(FALSE, ui);
2257 return TRUE;
2258 }
2259
2260 gfloat left_time = get_left_drawing_time(infos->current_time, infos->total_time, infos->zoom_coeff);
2261 gfloat right_time = get_right_drawing_time(infos->current_time, infos->total_time, infos->zoom_coeff);
2262
2263 //marks to draw seconds, minutes...
2264 gint left_mark = (gint)left_time;
2265 gint right_mark = (gint)right_time;
2266 if (left_mark < 0)
2267 {
2268 left_mark = 0;
2269 }
2270 if (right_mark > infos->total_time)
2271 {
2272 right_mark = (gint)infos->total_time;
2273 }
2274
2275 gfloat total_draw_time = right_time - left_time;
2276
2277 gchar str[30] = { '\0' };
2278 gint beg_pixel = convert_time_to_pixels(infos->width_drawing_area, 0,
2279 infos->current_time, infos->total_time, infos->zoom_coeff);
2280
2281 draw_rectangles_between_splitpoints(gc, ui);
2282
2283 //blue color
2284 color.red = 255 * 150; color.green = 255 * 150; color.blue = 255 * 255;
2285 dh_set_color(gc, &color);
2286
2287 //if it's the first splitpoint from play preview
2288 if (get_quick_preview_end_splitpoint_safe(ui) != -1)
2289 {
2290 gint right_pixel =
2291 convert_time_to_pixels(infos->width_drawing_area,
2292 get_splitpoint_time(get_quick_preview_end_splitpoint_safe(ui), ui),
2293 infos->current_time, infos->total_time, infos->zoom_coeff);
2294 gint left_pixel =
2295 convert_time_to_pixels(infos->width_drawing_area,
2296 get_splitpoint_time(status->preview_start_splitpoint, ui),
2297 infos->current_time, infos->total_time, infos->zoom_coeff);
2298
2299 gint preview_splitpoint_length = right_pixel - left_pixel + 1;
2300
2301 //top buttons
2302 dh_draw_rectangle(gc, TRUE, left_pixel, gui->progress_ylimit-2, preview_splitpoint_length, 3);
2303
2304 //for quick preview, put red bar
2305 if (status->quick_preview)
2306 {
2307 color.red = 255 * 255;color.green = 255 * 160;color.blue = 255 * 160;
2308 dh_set_color(gc, &color);
2309 dh_draw_rectangle(gc, TRUE, left_pixel, gui->erase_split_ylimit, preview_splitpoint_length, 3);
2310 }
2311 }
2312 else
2313 {
2314 //if we draw until the end
2315 if ((status->preview_start_splitpoint != -1) &&
2316 (status->preview_start_splitpoint != (infos->splitnumber-1)))
2317 {
2318 gint left_pixel =
2319 convert_time_to_pixels(infos->width_drawing_area,
2320 get_splitpoint_time(status->preview_start_splitpoint, ui),
2321 infos->current_time, infos->total_time, infos->zoom_coeff);
2322 dh_draw_rectangle(gc, TRUE, left_pixel, gui->progress_ylimit-2, infos->width_drawing_area-left_pixel, 3);
2323
2324 //red bar quick preview
2325 if (status->quick_preview)
2326 {
2327 color.red = 255 * 255;color.green = 255 * 160;color.blue = 255 * 160;
2328 dh_set_color(gc, &color);
2329 dh_draw_rectangle(gc, TRUE, left_pixel, gui->erase_split_ylimit, infos->width_drawing_area-left_pixel, 3);
2330 }
2331 }
2332 }
2333
2334 //song start
2335 if (left_time <= 0)
2336 {
2337 color.red = 255 * 235;color.green = 255 * 235; color.blue = 255 * 235;
2338 dh_set_color(gc, &color);
2339 dh_draw_rectangle(gc, TRUE, 0,0, beg_pixel, gui->wave_ypos);
2340 }
2341 else
2342 {
2343 color.red = 30000;color.green = 0;color.blue = 30000;
2344 dh_set_color(gc, &color);
2345
2346 get_time_for_drawing(str, left_time, FALSE, &nbr_chars);
2347 dh_draw_text(gc, str, 15, bottom_left_middle_right_text_ypos);
2348 }
2349
2350 gint end_pixel =
2351 convert_time_to_pixels(infos->width_drawing_area, infos->total_time,
2352 infos->current_time, infos->total_time, infos->zoom_coeff);
2353 //song end
2354 if (right_time >= infos->total_time)
2355 {
2356 color.red = 255 * 235;color.green = 255 * 235;color.blue = 255 * 235;
2357 dh_set_color(gc, &color);
2358 dh_draw_rectangle(gc, TRUE, end_pixel,0, infos->width_drawing_area, bottom_left_middle_right_text_ypos);
2359 }
2360 else
2361 {
2362 color.red = 30000;color.green = 0;color.blue = 30000;
2363 dh_set_color(gc, &color);
2364
2365 get_time_for_drawing(str, right_time, FALSE, &nbr_chars);
2366 dh_draw_text(gc, str, infos->width_drawing_area - 52, bottom_left_middle_right_text_ypos);
2367 }
2368
2369 if (total_draw_time < infos->hundr_secs_th)
2370 {
2371 draw_marks(HUNDR_SECONDS, left_mark, right_mark,
2372 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2373 }
2374 if (total_draw_time < infos->tens_of_secs_th)
2375 {
2376 draw_marks(TENS_OF_SECONDS, left_mark, right_mark,
2377 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2378 }
2379 if (total_draw_time < infos->secs_th)
2380 {
2381 draw_marks(SECONDS, left_mark, right_mark,
2382 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2383 }
2384 if (total_draw_time < infos->ten_secs_th)
2385 {
2386 draw_marks(TEN_SECONDS, left_mark, right_mark,
2387 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2388 }
2389 if (total_draw_time < infos->minutes_th)
2390 {
2391 draw_marks(MINUTES, left_mark, right_mark,
2392 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2393 }
2394 if (total_draw_time < infos->ten_minutes_th)
2395 {
2396 draw_marks(TEN_MINUTES, left_mark, right_mark,
2397 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2398 }
2399 draw_marks(HOURS, left_mark, right_mark,
2400 gui->erase_split_ylimit + progress_length/4, da, gc, ui);
2401
2402 //draw mobile button1 position line
2403 if (status->button1_pressed)
2404 {
2405 gint move_pixel = convert_time_to_pixels(infos->width_drawing_area,
2406 status->move_time, infos->current_time,
2407 infos->total_time, infos->zoom_coeff);
2408
2409 if (status->move_splitpoints)
2410 {
2411 draw_motif_splitpoints(da, gc, move_pixel,TRUE, status->move_time,
2412 TRUE, status->splitpoint_to_move, ui);
2413
2414 color.red = 0;color.green = 0;color.blue = 0;
2415 dh_set_color(gc, &color);
2416
2417 get_time_for_drawing(str, infos->current_time, FALSE, &nbr_chars);
2418 dh_draw_text(gc, str, infos->width_drawing_area/2-11, bottom_left_middle_right_text_ypos);
2419 }
2420 else
2421 {
2422 color.red = 255 * 255;color.green = 0;color.blue = 0;
2423 dh_set_color(gc, &color);
2424 dh_draw_line(gc, move_pixel, gui->erase_split_ylimit, move_pixel, gui->progress_ylimit, TRUE, TRUE);
2425
2426 if (status->show_silence_wave)
2427 {
2428 dh_draw_line(gc, move_pixel, gui->text_ypos + gui->margin, move_pixel, gui->wave_ypos, TRUE, TRUE);
2429 }
2430
2431 color.red = 0;color.green = 0;color.blue = 0;
2432 dh_set_color(gc, &color);
2433
2434 get_time_for_drawing(str, status->move_time, FALSE, &nbr_chars);
2435 dh_draw_text(gc, str, infos->width_drawing_area/2-11, bottom_left_middle_right_text_ypos);
2436 }
2437 }
2438 else
2439 {
2440 color.red = 0;color.green = 0;color.blue = 0;
2441 dh_set_color(gc, &color);
2442
2443 get_time_for_drawing(str, infos->current_time, FALSE, &nbr_chars);
2444 dh_draw_text(gc, str, infos->width_drawing_area/2-11, bottom_left_middle_right_text_ypos);
2445 }
2446
2447 color.red = 255 * 255;color.green = 0;color.blue = 0;
2448 dh_set_color(gc, &color);
2449
2450 //top middle line, current position
2451 dh_draw_line(gc, infos->width_drawing_area/2, gui->erase_split_ylimit,
2452 infos->width_drawing_area/2, gui->progress_ylimit, FALSE, TRUE);
2453
2454 //silence wave
2455 if (status->show_silence_wave)
2456 {
2457 draw_silence_wave(left_mark, right_mark,
2458 infos->width_drawing_area/2 + 3, gui->wave_ypos - gui->margin * 4,
2459 total_draw_time,
2460 infos->width_drawing_area, gui->text_ypos + gui->margin,
2461 infos->current_time, infos->total_time, infos->zoom_coeff,
2462 da, gc, ui);
2463
2464 //silence wave middle line
2465 color.red = 255 * 255;color.green = 0;color.blue = 0;
2466 dh_set_color(gc, &color);
2467 dh_draw_line(gc, infos->width_drawing_area/2, gui->text_ypos + gui->margin,
2468 infos->width_drawing_area/2, gui->wave_ypos, FALSE, TRUE);
2469 }
2470
2471 draw_splitpoints(left_mark, right_mark, da, gc, ui);
2472
2473 #if GTK_MAJOR_VERSION <= 2
2474 cairo_destroy(gc);
2475 #endif
2476
2477 set_process_in_progress_safe(FALSE, ui);
2478
2479 return TRUE;
2480 }
2481
2482 static void draw_small_rectangle(gint time_left, gint time_right,
2483 GdkColor color, cairo_t *cairo_surface, ui_state *ui)
2484 {
2485 if (time_left == -1 || time_right == -1)
2486 {
2487 return;
2488 }
2489
2490 gint pixels_left = convert_time_to_pixels(ui->infos->width_drawing_area, time_left,
2491 ui->infos->current_time, ui->infos->total_time, ui->infos->zoom_coeff);
2492 gint pixels_right = convert_time_to_pixels(ui->infos->width_drawing_area, time_right,
2493 ui->infos->current_time, ui->infos->total_time, ui->infos->zoom_coeff);
2494 gint pixels_length = pixels_right - pixels_left;
2495
2496 dh_set_color(cairo_surface, &color);
2497 dh_draw_rectangle(cairo_surface, TRUE, pixels_left, ui->gui->erase_split_ylimit,
2498 pixels_length, ui->gui->progress_ylimit - ui->gui->erase_split_ylimit+1);
2499
2500 if (ui->status->show_silence_wave)
2501 {
2502 dh_draw_rectangle(cairo_surface, TRUE, pixels_left, ui->gui->text_ypos + ui->gui->margin,
2503 pixels_length, ui->gui->real_wave_length + ui->gui->margin);
2504 }
2505 }
2506
2507 void get_current_splitpoints_time_left_right(gint *time_left, gint *time_right,
2508 gint *splitpoint_left, ui_state *ui)
2509 {
2510 ui_infos *infos = ui->infos;
2511
2512 gint i = 0;
2513 for (i = 0; i < infos->splitnumber; i++ )
2514 {
2515 gint current_point_hundr_secs = get_splitpoint_time(i, ui);
2516 if (current_point_hundr_secs < infos->current_time - (DELTA * 2))
2517 {
2518 *time_left = current_point_hundr_secs;
2519 continue;
2520 }
2521
2522 if (current_point_hundr_secs > infos->current_time + (DELTA * 2))
2523 {
2524 *time_right = current_point_hundr_secs;
2525 if (splitpoint_left != NULL) { *splitpoint_left = i; }
2526 break;
2527 }
2528 }
2529
2530 if (splitpoint_left != NULL && *splitpoint_left == -1)
2531 {
2532 *splitpoint_left = infos->splitnumber;
2533 }
2534 }
2535
2546 static gint get_splitpoint_clicked(gint button_y, gint type_clicked, gint type, ui_state *ui)
2547 {
2548 gint time_pos, time_right_pos;
2549 gint left_time = get_left_drawing_time(ui->infos->current_time, ui->infos->total_time, ui->infos->zoom_coeff);
2550
2551 gint but_y;
2552 //click on a right button
2553 if (type_clicked != 3)
2554 {
2555 but_y = button_y;
2556 time_pos = left_time + pixels_to_time(ui->infos->width_drawing_area, ui->status->button_x, ui);
2557 }
2558 else
2559 {
2560 but_y = ui->status->button_y2;
2561 time_pos = left_time + pixels_to_time(ui->infos->width_drawing_area, ui->status->button_x2, ui);
2562 }
2563
2564 //we get this to find time_right_pos - time_right
2565 //to see what time we have for X pixels
2566 gint pixels_to_look_for = ui->gui->real_erase_split_length / 2;
2567 if (type == 2)
2568 {
2569 pixels_to_look_for = ui->gui->real_move_split_length / 2;
2570 }
2571
2572 if (type_clicked != 3)
2573 {
2574 time_right_pos = left_time +
2575 pixels_to_time(ui->infos->width_drawing_area, ui->status->button_x + pixels_to_look_for, ui);
2576 }
2577 else
2578 {
2579 time_right_pos = left_time +
2580 pixels_to_time(ui->infos->width_drawing_area, ui->status->button_x2 + pixels_to_look_for, ui);
2581 }
2582
2583 //the time margin is the margin for the splitpoint,
2584 //where we can click at his left or right
2585 gint time_margin = time_right_pos - time_pos;
2586
2587 gint margin1, margin2;
2588
2589 if (type == 2)
2590 {
2591 margin1 = ui->gui->progress_ylimit + ui->gui->margin;
2592 margin2 = ui->gui->progress_ylimit + ui->gui->margin + ui->gui->real_move_split_length;
2593 }
2594 else if (type == 1)
2595 {
2596 margin1 = ui->gui->margin;
2597 margin2 = ui->gui->margin + ui->gui->real_erase_split_length;
2598 }
2599 else
2600 {
2601 margin1 = ui->gui->splitpoint_ypos + ui->gui->margin;
2602 margin2 = ui->gui->splitpoint_ypos + ui->gui->margin + ui->gui->real_checkbox_length;
2603 }
2604
2605 //area outside the split move
2606 if ((but_y < margin1) || (but_y > margin2))
2607 {
2608 return -1;
2609 }
2610
2611 gint i = 0;
2612 for(i = 0; i < ui->infos->splitnumber; i++ )
2613 {
2614 gint current_point_hundr_secs = get_splitpoint_time(i, ui);
2615 gint current_point_left = current_point_hundr_secs - time_margin;
2616 gint current_point_right = current_point_hundr_secs + time_margin;
2617
2618 if ((time_pos >= current_point_left) && (time_pos <= current_point_right))
2619 {
2620 return i;
2621 }
2622 }
2623
2624 return -1;
2625 }
2626
2627 void set_preview_start_position_safe(gint value, ui_state *ui)
2628 {
2629 lock_mutex(&ui->variables_mutex);
2630 ui->status->preview_start_position = value;
2631 unlock_mutex(&ui->variables_mutex);
2632 }
2633
2634 gint get_preview_start_position_safe(ui_state *ui)
2635 {
2636 lock_mutex(&ui->variables_mutex);
2637 gint preview_start_position = ui->status->preview_start_position;
2638 unlock_mutex(&ui->variables_mutex);
2639
2640 return preview_start_position;
2641 }
2642
2644 void player_quick_preview(gint splitpoint_to_preview, ui_state *ui)
2645 {
2646 if (splitpoint_to_preview == -1)
2647 {
2648 return;
2649 }
2650
2651 gui_status *status = ui->status;
2652
2653 set_preview_start_position_safe(get_splitpoint_time(splitpoint_to_preview, ui), ui);
2654 status->preview_start_splitpoint = splitpoint_to_preview;
2655
2656 if (!player_is_playing(ui))
2657 {
2658 player_play(ui);
2659 usleep(50000);
2660 }
2661
2662 if (player_is_paused(ui))
2663 {
2664 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui->gui->pause_button), FALSE);
2665 }
2666
2667 if (splitpoint_to_preview < ui->infos->splitnumber-1)
2668 {
2669 set_quick_preview_end_splitpoint_safe(splitpoint_to_preview + 1, ui);
2670 }
2671 else
2672 {
2673 set_quick_preview_end_splitpoint_safe(-1, ui);
2674 }
2675
2676 player_seek(get_preview_start_position_safe(ui) * 10, ui);
2677 change_progress_bar(ui);
2678 put_status_message(_(" quick preview..."), ui);
2679
2680 status->quick_preview = FALSE;
2681 if (get_quick_preview_end_splitpoint_safe(ui) != -1)
2682 {
2683 status->quick_preview = TRUE;
2684 }
2685
2686 if (status->preview_start_splitpoint == (ui->infos->splitnumber-1))
2687 {
2688 cancel_quick_preview_all(ui);
2689 }
2690 }
2691
2693 static gboolean da_press_event(GtkWidget *da, GdkEventButton *event, ui_state *ui)
2694 {
2695 if (!ui->status->playing || !ui->status->timer_active)
2696 {
2697 return TRUE;
2698 }
2699
2700 gui_status *status = ui->status;
2701 gui_state *gui = ui->gui;
2702 ui_infos *infos = ui->infos;
2703
2704 //left click
2705 if (event->button == 1)
2706 {
2707 status->button_x = event->x;
2708 status->button_y = event->y;
2709 status->button1_pressed = TRUE;
2710
2711 if ((status->button_y > gui->progress_ylimit + gui->margin) &&
2712 (status->button_y < gui->progress_ylimit + gui->margin + gui->real_move_split_length))
2713 {
2714 status->splitpoint_to_move = get_splitpoint_clicked(status->button_y, 1, 2, ui);
2715 if (status->splitpoint_to_move != -1)
2716 {
2717 status->move_splitpoints = TRUE;
2718 }
2719 }
2720 else
2721 {
2722 //area to remove a splitpoint
2723 if ((status->button_y > gui->margin) &&
2724 (status->button_y < gui->margin + gui->real_erase_split_length))
2725 {
2726 gint splitpoint_selected = get_splitpoint_clicked(status->button_y, 1, 1, ui);
2727 if (splitpoint_selected != -1)
2728 {
2729 status->select_splitpoints = TRUE;
2730 select_splitpoint(splitpoint_selected, gui);
2731 }
2732 refresh_drawing_area(gui);
2733 }
2734 else
2735 {
2736 //area to check a splitpoint
2737 if ((status->button_y > gui->splitpoint_ypos + gui->margin) &&
2738 (status->button_y < gui->splitpoint_ypos + gui->margin + gui->real_checkbox_length))
2739 {
2740 gint splitpoint_selected = get_splitpoint_clicked(status->button_y, 1, 3, ui);
2741 if (splitpoint_selected != -1)
2742 {
2743 status->check_splitpoint = TRUE;
2744 update_splitpoint_check(splitpoint_selected, ui);
2745 }
2746 refresh_drawing_area(gui);
2747 }
2748 }
2749 }
2750
2751 if (!status->move_splitpoints)
2752 {
2753 status->move_time = infos->current_time;
2754 }
2755 else
2756 {
2757 status->move_time = get_splitpoint_time(status->splitpoint_to_move, ui);
2758 }
2759
2760 return TRUE;
2761 }
2762
2763 //right click
2764 if (event->button == 3)
2765 {
2766 status->button_x2 = event->x;
2767 status->button_y2 = event->y;
2768 status->button2_pressed = TRUE;
2769
2770 infos->zoom_coeff_old = infos->zoom_coeff;
2771
2772 if ((status->button_y2 > gui->progress_ylimit + gui->margin) &&
2773 (status->button_y2 < gui->progress_ylimit + gui->margin + gui->real_move_split_length))
2774 {
2775 player_quick_preview(get_splitpoint_clicked(status->button_y2, 3, 2, ui), ui);
2776 }
2777 else
2778 {
2779 //to remove a splitpoint
2780 if ((status->button_y2 > gui->margin) &&
2781 (status->button_y2 < gui->margin + gui->real_erase_split_length))
2782 {
2783 gint splitpoint_to_erase = get_splitpoint_clicked(status->button_y2, 3, 1, ui);
2784 if (splitpoint_to_erase != -1)
2785 {
2786 status->remove_splitpoints = TRUE;
2787 remove_splitpoint(splitpoint_to_erase, TRUE, ui);
2788 }
2789
2790 refresh_drawing_area(gui);
2791 }
2792 }
2793 }
2794
2795 return TRUE;
2796 }
2797
2799 static gboolean da_unpress_event(GtkWidget *da, GdkEventButton *event, ui_state *ui)
2800 {
2801 gui_status *status = ui->status;
2802
2803 if (!status->playing || !status->timer_active)
2804 {
2805 goto end;
2806 }
2807
2808 if (event->button == 1)
2809 {
2810 status->button1_pressed = FALSE;
2811
2812 //if moving the current _position_
2813 if (!status->move_splitpoints && !status->remove_splitpoints &&
2814 !status->select_splitpoints && !status->check_splitpoint)
2815 {
2816 remove_status_message(ui->gui);
2817 player_seek((gint)(status->move_time * 10), ui);
2818 change_progress_bar(ui);
2819
2820 //if more than 2 splitpoints & outside the split preview, cancel split preview
2821 if (get_quick_preview_end_splitpoint_safe(ui) == -1)
2822 {
2823 if (status->move_time < get_splitpoint_time(status->preview_start_splitpoint, ui))
2824 {
2825 cancel_quick_preview_all(ui);
2826 }
2827 }
2828 else
2829 {
2830 if ((status->move_time < get_splitpoint_time(status->preview_start_splitpoint, ui)) ||
2831 (status->move_time > get_splitpoint_time(get_quick_preview_end_splitpoint_safe(ui),ui)))
2832 {
2833 cancel_quick_preview_all(ui);
2834 }
2835 else
2836 {
2837 //if don't have a preview with the last splitpoint
2838 if (get_quick_preview_end_splitpoint_safe(ui) != -1)
2839 {
2840 if (player_is_paused(ui))
2841 {
2842 player_pause(ui);
2843 }
2844 status->quick_preview = TRUE;
2845 }
2846 }
2847 }
2848 }
2849 else if (status->move_splitpoints)
2850 {
2851 update_splitpoint_from_time(status->splitpoint_to_move, status->move_time, ui);
2852 status->splitpoint_to_move = -1;
2853 }
2854
2855 status->move_splitpoints = FALSE;
2856 status->select_splitpoints = FALSE;
2857 status->check_splitpoint = FALSE;
2858 }
2859 else if (event->button == 3)
2860 {
2861 status->button2_pressed = FALSE;
2862 status->remove_splitpoints = FALSE;
2863 }
2864
2865 end:
2866 refresh_drawing_area(ui->gui);
2867 return TRUE;
2868 }
2869
2871 static gboolean da_notify_event(GtkWidget *da, GdkEventMotion *event, ui_state *ui)
2872 {
2873 gui_status *status = ui->status;
2874 ui_infos *infos = ui->infos;
2875
2876 if ((status->playing && status->timer_active) &&
2877 (status->button1_pressed || status->button2_pressed))
2878 {
2879 gint x, y;
2880 GdkModifierType state;
2881 wh_get_pointer(event, &x, &y, &state);
2882
2883 gint width = 0;
2884 wh_get_widget_size(ui->gui->drawing_area, &width, NULL);
2885 gfloat width_drawing_area = (gfloat) width;
2886
2887 if (!state)
2888 {
2889 return TRUE;
2890 }
2891
2892 if (status->button1_pressed)
2893 {
2894 if (status->move_splitpoints)
2895 {
2896 gdouble splitpoint_time = get_splitpoint_time(status->splitpoint_to_move, ui);
2897 status->move_time = splitpoint_time +
2898 pixels_to_time(width_drawing_area, (x - status->button_x), ui);
2899 }
2900 else
2901 {
2902 if (status->remove_splitpoints || status->select_splitpoints || status->check_splitpoint)
2903 {
2904 status->move_time = infos->current_time;
2905 }
2906 else
2907 {
2908 status->move_time =
2909 infos->current_time + pixels_to_time(width_drawing_area, (x - status->button_x), ui);
2910 }
2911 }
2912
2913 if (status->move_time < 0)
2914 {
2915 status->move_time = 0;
2916 }
2917 if (status->move_time > infos->total_time)
2918 {
2919 status->move_time = infos->total_time;
2920 }
2921
2922 refresh_drawing_area(ui->gui);
2923 }
2924 else
2925 {
2926 if (status->button2_pressed)
2927 {
2928 gint diff = -((event->x - status->button_x2) * 1);
2929 if (diff < (-width_drawing_area + 1))
2930 {
2931 diff = -width_drawing_area + 1;
2932 }
2933 if (diff > (width_drawing_area - 1))
2934 {
2935 diff = width_drawing_area - 1;
2936 }
2937
2938 infos->zoom_coeff = diff / (width_drawing_area);
2939
2940 if (infos->zoom_coeff < 0)
2941 {
2942 infos->zoom_coeff = 1 / (infos->zoom_coeff + 1);
2943 }
2944 else
2945 {
2946 infos->zoom_coeff = 1 - infos->zoom_coeff;
2947 }
2948
2949 infos->zoom_coeff = infos->zoom_coeff_old * infos->zoom_coeff;
2950
2951 adjust_zoom_coeff(infos);
2952
2953 refresh_drawing_area(ui->gui);
2954 }
2955 }
2956 }
2957
2958 return TRUE;
2959 }
2960
2961 void adjust_zoom_coeff(ui_infos *infos)
2962 {
2963 if (infos->zoom_coeff < 0.2)
2964 {
2965 infos->zoom_coeff = 0.2;
2966 }
2967 if (infos->zoom_coeff > 10 * infos->total_time / 6000)
2968 {
2969 infos->zoom_coeff = 10 * infos->total_time / 6000;
2970 }
2971 }
2972
2973 static void drawing_area_expander_event(GObject *object, GParamSpec *param_spec, ui_state *ui)
2974 {
2975 if (object == NULL)
2976 {
2977 return;
2978 }
2979
2980 GtkExpander *expander = GTK_EXPANDER(object);
2981 if (gtk_expander_get_expanded(expander))
2982 {
2983 gtk_widget_show(ui->gui->silence_wave_check_button);
2984 return;
2985 }
2986
2987 gtk_widget_hide(ui->gui->silence_wave_check_button);
2988 }
2989
2991 static GtkWidget *create_drawing_area(ui_state *ui)
2992 {
2993 GtkWidget *frame = gtk_frame_new(NULL);
2994
2995 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
2996
2997 GtkWidget *drawing_area = gtk_drawing_area_new();
2998 dnd_add_drag_data_received_to_widget(drawing_area, DND_SINGLE_MODE_AUDIO_FILE_AND_DATA_FILES, ui);
2999
3000 ui->gui->drawing_area = drawing_area;
3001
3002 gtk_widget_set_size_request(drawing_area, DRAWING_AREA_WIDTH, DRAWING_AREA_HEIGHT);
3003
3004 #if GTK_MAJOR_VERSION <= 2
3005 g_signal_connect(drawing_area, "expose_event", G_CALLBACK(da_draw_event), ui);
3006 #else
3007 g_signal_connect(drawing_area, "draw", G_CALLBACK(da_draw_event), ui);
3008 #endif
3009
3010 g_signal_connect(drawing_area, "button_press_event", G_CALLBACK(da_press_event), ui);
3011 g_signal_connect(drawing_area, "button_release_event", G_CALLBACK(da_unpress_event), ui);
3012 g_signal_connect(drawing_area, "motion_notify_event", G_CALLBACK(da_notify_event), ui);
3013
3014 gtk_widget_set_events(drawing_area, gtk_widget_get_events(drawing_area)
3015 | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK
3016 | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK
3017 | GDK_POINTER_MOTION_HINT_MASK);
3018
3019 gtk_container_add(GTK_CONTAINER(frame), drawing_area);
3020
3021 GtkWidget *drawing_area_expander =
3022 gtk_expander_new_with_mnemonic(_("Splitpoints and amplitude wave v_iew"));
3023 ui->gui->drawing_area_expander = drawing_area_expander;
3024 gtk_expander_set_expanded(GTK_EXPANDER(drawing_area_expander), TRUE);
3025 g_signal_connect(drawing_area_expander, "notify::expanded",
3026 G_CALLBACK(drawing_area_expander_event), ui);
3027 gtk_container_add(GTK_CONTAINER(drawing_area_expander), frame);
3028
3029 return drawing_area_expander;
3030 }
3031
3033 GtkWidget *create_player_control_frame(ui_state *ui)
3034 {
3035 GtkWidget *main_hbox = wh_hbox_new();
3036
3037 GtkWidget *vbox = wh_vbox_new();
3038 gtk_box_pack_start(GTK_BOX(main_hbox), vbox, TRUE, TRUE, 0);
3039
3040 //filename player hbox
3041 GtkWidget *hbox = create_filename_player_hbox(ui->gui);
3042 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
3043
3044 //the song informations
3045 hbox = create_song_informations_hbox(ui->gui);
3046 gtk_container_set_border_width(GTK_CONTAINER (hbox), 0);
3047 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
3048
3049 //audio progress bar
3050 hbox = create_song_bar_hbox(ui);
3051 gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
3052 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
3053
3054 //drawing area
3055 GtkWidget *drawing_area = create_drawing_area(ui);
3056 gtk_container_set_border_width(GTK_CONTAINER(drawing_area), 0);
3057 gtk_box_pack_start(GTK_BOX(vbox), drawing_area, FALSE, FALSE, 0);
3058
3059 //player buttons
3060 hbox = create_player_buttons_hbox(ui);
3061 gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
3062 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
3063
3064 return main_hbox;
3065 }
3066
3068 void add_playlist_file(const gchar *name, ui_state *ui)
3069 {
3070 if (!file_exists(name))
3071 {
3072 return;
3073 }
3074
3075 gboolean name_already_exists_in_playlist = FALSE;
3076
3077 GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->playlist_tree);
3078
3079 gchar *filename = NULL;
3080
3081 GtkTreeIter iter;
3082
3083 gint i = 0;
3084 while (i < ui->infos->playlist_tree_number)
3085 {
3086 GtkTreePath *path = gtk_tree_path_new_from_indices(i ,-1);
3087 gtk_tree_model_get_iter(model, &iter, path);
3088 gtk_tree_model_get(model, &iter, COL_FILENAME, &filename, -1);
3089
3090 if (strcmp(filename, name) == 0)
3091 {
3092 name_already_exists_in_playlist = TRUE;
3093 break;
3094 }
3095
3096 g_free(filename);
3097 i++;
3098 }
3099
3100 if (! name_already_exists_in_playlist)
3101 {
3102 gtk_widget_set_sensitive(ui->gui->playlist_remove_all_files_button,TRUE);
3103 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
3104
3105 //sets text in the minute, second and milisecond column
3106 gtk_list_store_set(GTK_LIST_STORE(model),
3107 &iter,
3108 COL_NAME, get_real_name_from_filename(name),
3109 COL_FILENAME, name,
3110 -1);
3111 ui->infos->playlist_tree_number++;
3112 }
3113 }
3114
3116 static GtkTreeModel *create_playlist_model()
3117 {
3118 GtkListStore * model = gtk_list_store_new(PLAYLIST_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
3119 return GTK_TREE_MODEL(model);
3120 }
3121
3123 static GtkTreeView *create_playlist_tree()
3124 {
3125 GtkTreeModel *model = create_playlist_model();
3126 GtkTreeView *playlist_tree = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
3127 gtk_tree_view_set_headers_visible(playlist_tree, FALSE);
3128 return playlist_tree;
3129 }
3130
3132 void create_playlist_columns(GtkTreeView *playlist_tree)
3133 {
3134 GtkCellRendererText *renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new());
3135 g_object_set_data(G_OBJECT(renderer), "col", GINT_TO_POINTER(COL_NAME));
3136
3137 GtkTreeViewColumn *name_column = gtk_tree_view_column_new_with_attributes
3138 (_("History"), GTK_CELL_RENDERER(renderer), "text", COL_NAME, NULL);
3139 gtk_tree_view_insert_column(playlist_tree, GTK_TREE_VIEW_COLUMN(name_column), COL_NAME);
3140
3141 gtk_tree_view_column_set_alignment(GTK_TREE_VIEW_COLUMN(name_column), 0.5);
3142 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(name_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE);
3143 }
3144
3146 static void playlist_selection_changed(GtkTreeSelection *selec, ui_state *ui)
3147 {
3148 GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->playlist_tree);
3149 GtkTreeSelection *selection = gtk_tree_view_get_selection(ui->gui->playlist_tree);
3150 GList *selected_list = gtk_tree_selection_get_selected_rows(selection, &model);
3151 if (g_list_length(selected_list) > 0)
3152 {
3153 gtk_widget_set_sensitive(ui->gui->playlist_remove_file_button, TRUE);
3154 }
3155 else
3156 {
3157 gtk_widget_set_sensitive(ui->gui->playlist_remove_file_button, FALSE);
3158 }
3159 }
3160
3162 static void playlist_remove_file_button_event(GtkWidget *widget, ui_state *ui)
3163 {
3164 GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->playlist_tree);
3165 GtkTreeSelection *selection = gtk_tree_view_get_selection(ui->gui->playlist_tree);
3166 GList *selected_list = gtk_tree_selection_get_selected_rows(selection, &model);
3167
3168 gchar *filename = NULL;
3169
3170 while (g_list_length(selected_list) > 0)
3171 {
3172 GList *current_element = g_list_last(selected_list);
3173 GtkTreePath *path = current_element->data;
3174
3175 GtkTreeIter iter;
3176 gtk_tree_model_get_iter(model, &iter, path);
3177 gtk_tree_model_get(model, &iter,
3178 COL_FILENAME, &filename, -1);
3179
3180 //remove the path from the selected list
3181 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
3182 selected_list = g_list_remove(selected_list, path);
3183 //remove 1 to the row number of the table
3184 ui->infos->playlist_tree_number--;
3185
3186 gtk_tree_path_free(path);
3187 g_free(filename);
3188 }
3189
3190 if (ui->infos->playlist_tree_number == 0)
3191 {
3192 gtk_widget_set_sensitive(ui->gui->playlist_remove_all_files_button, FALSE);
3193 }
3194
3195 gtk_widget_set_sensitive(ui->gui->playlist_remove_file_button,FALSE);
3196
3197 g_list_foreach(selected_list, (GFunc)gtk_tree_path_free, NULL);
3198 g_list_free(selected_list);
3199 }
3200
3202 static void playlist_remove_all_files_button_event(GtkWidget *widget, ui_state *ui)
3203 {
3204 GtkTreeModel *model = gtk_tree_view_get_model(ui->gui->playlist_tree);
3205
3206 gchar *filename = NULL;
3207 while (ui->infos->playlist_tree_number > 0)
3208 {
3209 GtkTreeIter iter;
3210 gtk_tree_model_get_iter_first(model, &iter);
3211 gtk_tree_model_get(model, &iter,
3212 COL_FILENAME, &filename, -1);
3213 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
3214 ui->infos->playlist_tree_number--;
3215 g_free(filename);
3216 }
3217
3218 gtk_widget_set_sensitive(ui->gui->playlist_remove_all_files_button, FALSE);
3219 gtk_widget_set_sensitive(ui->gui->playlist_remove_file_button, FALSE);
3220 }
3221
3223 static GtkWidget *create_delete_buttons_hbox(ui_state *ui)
3224 {
3225 GtkWidget *hbox = wh_hbox_new();
3226
3227 GtkWidget *playlist_remove_file_button =
3228 wh_create_cool_button(GTK_STOCK_REMOVE, _("_Erase selected entries"), FALSE);
3229 ui->gui->playlist_remove_file_button = playlist_remove_file_button;
3230 gtk_box_pack_start(GTK_BOX(hbox), playlist_remove_file_button, FALSE, FALSE, 5);
3231 gtk_widget_set_sensitive(playlist_remove_file_button,FALSE);
3232 g_signal_connect(G_OBJECT(playlist_remove_file_button), "clicked",
3233 G_CALLBACK(playlist_remove_file_button_event), ui);
3234
3235 GtkWidget *playlist_remove_all_files_button =
3236 wh_create_cool_button(GTK_STOCK_CLEAR, _("E_rase all history"),FALSE);
3237 ui->gui->playlist_remove_all_files_button = playlist_remove_all_files_button;
3238 gtk_box_pack_start(GTK_BOX(hbox), playlist_remove_all_files_button, FALSE, FALSE, 5);
3239 gtk_widget_set_sensitive(playlist_remove_all_files_button,FALSE);
3240 g_signal_connect(G_OBJECT(playlist_remove_all_files_button), "clicked",
3241 G_CALLBACK(playlist_remove_all_files_button_event), ui);
3242
3243 return hbox;
3244 }
3245
3247 GtkWidget *create_player_playlist_frame(ui_state *ui)
3248 {
3249 GtkWidget *vbox = wh_vbox_new();
3250
3251 //scrolled window and the tree
3252 //create the tree and add it to the scrolled window
3253 GtkTreeView *playlist_tree = create_playlist_tree();
3254 dnd_add_drag_data_received_to_widget(GTK_WIDGET(playlist_tree), DND_SINGLE_MODE_AUDIO_FILE, ui);
3255
3256 ui->gui->playlist_tree = playlist_tree;
3257 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
3258 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_NONE);
3259 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
3260 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3261 gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
3262
3263 create_playlist_columns(playlist_tree);
3264 gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(playlist_tree));
3265 g_signal_connect(G_OBJECT(playlist_tree), "row-activated",
3266 G_CALLBACK(split_tree_row_activated), ui);
3267
3268 //selection for the tree
3269 GtkTreeSelection *playlist_tree_selection = gtk_tree_view_get_selection(playlist_tree);
3270 g_signal_connect(G_OBJECT(playlist_tree_selection), "changed",
3271 G_CALLBACK(playlist_selection_changed), ui);
3272 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(playlist_tree_selection), GTK_SELECTION_MULTIPLE);
3273
3274 //horizontal box with delete buttons
3275 GtkWidget *delete_buttons_hbox = create_delete_buttons_hbox(ui);
3276 gtk_box_pack_start(GTK_BOX(vbox), delete_buttons_hbox, FALSE, FALSE, 2);
3277
3278 GtkWidget *history_expander = gtk_expander_new_with_mnemonic(_("Files h_istory"));
3279 gtk_expander_set_expanded(GTK_EXPANDER(history_expander), FALSE);
3280 gtk_container_add(GTK_CONTAINER(history_expander), vbox);
3281
3282 GtkWidget *main_hbox = wh_hbox_new();
3283 gtk_box_pack_start(GTK_BOX(main_hbox), history_expander, TRUE, TRUE, 4);
3284
3285 return main_hbox;
3286 }
3287
3288 static void action_set_sensitivity(gchar *name, gboolean sensitivity, gui_state *gui)
3289 {
3290 GtkAction *action = gtk_action_group_get_action(gui->action_group, name);
3291 gtk_action_set_sensitive(action, sensitivity);
3292 }
3293
3294 void player_key_actions_set_sensitivity(gboolean sensitivity, gui_state *gui)
3295 {
3296 action_set_sensitivity("Player_pause", sensitivity, gui);
3297 action_set_sensitivity("Player_forward", sensitivity, gui);
3298 action_set_sensitivity("Player_backward", sensitivity, gui);
3299 action_set_sensitivity("Player_small_forward", sensitivity, gui);
3300 action_set_sensitivity("Player_small_backward", sensitivity, gui);
3301 action_set_sensitivity("Player_big_forward", sensitivity, gui);
3302 action_set_sensitivity("Player_big_backward", sensitivity, gui);
3303 action_set_sensitivity("Player_next_splitpoint", sensitivity, gui);
3304 action_set_sensitivity("Player_previous_splitpoint", sensitivity, gui);
3305 action_set_sensitivity("Player_before_closest_splitpoint", sensitivity, gui);
3306 action_set_sensitivity("Add_splitpoint", sensitivity, gui);
3307 action_set_sensitivity("Delete_closest_splitpoint", sensitivity, gui);
3308 action_set_sensitivity("Zoom_in", sensitivity, gui);
3309 action_set_sensitivity("Zoom_out", sensitivity, gui);
3310 }
3311
3316 static gint mytimer(ui_state *ui)
3317 {
3318 #ifdef __WIN32__
3319 if (get_process_in_progress_safe(ui))
3320 {
3321 return TRUE;
3322 }
3323 #endif
3324
3325 set_process_in_progress_safe(TRUE, ui);
3326
3327 ui_infos *infos = ui->infos;
3328 gui_state *gui = ui->gui;
3329 gui_status *status = ui->status;
3330
3331 //TODO: file from file chooser can be NULL and != from the real filename of mp3splt-gtk.
3332 //but this does not work: the user can no longer select a folder if we do this
3333 /*if (gui->open_file_chooser_button != NULL)
3334 {
3335 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(gui->open_file_chooser_button));
3336 if (filename == NULL)
3337 {
3338 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gui->open_file_chooser_button),
3339 get_input_filename(ui->gui));
3340 }
3341 }*/
3342
3343 if (!player_is_running(ui))
3344 {
3345 gtk_widget_set_sensitive(gui->silence_wave_check_button, FALSE);
3346
3347 clear_data_player(gui);
3348 status->playing = FALSE;
3349 disconnect_button_event(gui->disconnect_button, ui);
3350
3351 set_process_in_progress_safe(FALSE, ui);
3352 return FALSE;
3353 }
3354
3355 gtk_widget_set_sensitive(gui->silence_wave_check_button, TRUE);
3356
3357 if (status->playing)
3358 {
3359 if (player_get_playlist_number(ui) > -1)
3360 {
3361 if (player_is_playing(ui))
3362 {
3363 print_all_song_infos(ui);
3364 print_song_time_elapsed(ui);
3365 gtk_widget_set_sensitive(GTK_WIDGET(gui->progress_bar), TRUE);
3366 }
3367
3368 check_stream(ui);
3369
3370 //if we have a stream, we must not change the progress bar
3371 if (!status->stream)
3372 {
3373 change_progress_bar(ui);
3374 }
3375
3376 //part of quick preview
3377 if (status->preview_start_splitpoint != -1)
3378 {
3379 //if we have a splitpoint after the current
3380 //previewed one, update quick_preview_end
3381 if (status->preview_start_splitpoint + 1 < infos->splitnumber)
3382 {
3383 set_quick_preview_end_splitpoint_safe(status->preview_start_splitpoint + 1, ui);
3384 }
3385 else
3386 {
3387 if (status->preview_start_splitpoint + 1 == infos->splitnumber)
3388 {
3389 set_quick_preview_end_splitpoint_safe(-1, ui);
3390 }
3391 }
3392 }
3393
3394 //if we have a preview, stop if needed
3395 if (status->quick_preview)
3396 {
3397 gint stop_splitpoint = get_splitpoint_time(get_quick_preview_end_splitpoint_safe(ui), ui);
3398
3399 if ((stop_splitpoint < (gint)infos->current_time)
3400 && (get_quick_preview_end_splitpoint_safe(ui) != -1))
3401 {
3402 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gui->pause_button), TRUE);
3403 cancel_quick_preview(status);
3404 put_status_message(_(" quick preview finished, song paused"), ui);
3405 }
3406 }
3407
3408 gtk_widget_set_sensitive(GTK_WIDGET(gui->volume_button), TRUE);
3409 }
3410 else
3411 {
3412 status->playing = FALSE;
3413 reset_label_time(gui);
3414 }
3415
3416 if (player_is_paused(ui))
3417 {
3418 status->only_press_pause = TRUE;
3419 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gui->pause_button), TRUE);
3420 status->only_press_pause = FALSE;
3421 }
3422 else
3423 {
3424 status->only_press_pause = TRUE;
3425 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gui->pause_button), FALSE);
3426 status->only_press_pause = FALSE;
3427 }
3428 }
3429 else
3430 {
3431 if ((infos->player_minutes != 0) || (infos->player_seconds != 0))
3432 {
3433 infos->player_minutes = 0;
3434 infos->player_seconds = 0;
3435 }
3436
3437 print_player_filename(ui);
3438 reset_song_infos(gui);
3439 reset_label_time(gui);
3440 reset_inactive_progress_bar(gui);
3441 gtk_widget_set_sensitive(gui->player_add_button, FALSE);
3442 }
3443
3444 //if connected, almost always change volume bar
3445 if ((ui->status->change_volume)&& (!ui->status->on_the_volume_button))
3446 {
3447 change_volume_button(ui);
3448 }
3449
3450 status->playing = player_is_playing(ui);
3451 if (status->playing)
3452 {
3453 gtk_widget_set_sensitive(gui->player_add_button, TRUE);
3454 gtk_widget_set_sensitive(gui->stop_button, TRUE);
3455 wh_set_image_on_button(GTK_BUTTON(gui->stop_button), g_object_ref(gui->StopButton_active));
3456
3457 gtk_widget_set_sensitive(gui->pause_button, TRUE);
3458 wh_set_image_on_button(GTK_BUTTON(gui->pause_button), g_object_ref(gui->PauseButton_active));
3459
3460 player_key_actions_set_sensitivity(TRUE, gui);
3461 }
3462 else
3463 {
3464 gtk_widget_set_sensitive(gui->stop_button, FALSE);
3465 wh_set_image_on_button(GTK_BUTTON(gui->stop_button), g_object_ref(gui->StopButton_inactive));
3466
3467 gtk_widget_set_sensitive(gui->pause_button, FALSE);
3468 wh_set_image_on_button(GTK_BUTTON(gui->pause_button), g_object_ref(gui->PauseButton_inactive));
3469
3470 player_key_actions_set_sensitivity(FALSE, gui);
3471 }
3472
3473 set_process_in_progress_safe(FALSE, ui);
3474
3475 return TRUE;
3476 }
3477
3478 //event for the file chooser ok button
3479 void file_chooser_ok_event(const gchar *fname, ui_state *ui)
3480 {
3481 change_current_filename(fname, ui);
3482 gtk_widget_set_sensitive(ui->gui->play_button, TRUE);
3483 wh_set_image_on_button(GTK_BUTTON(ui->gui->play_button), g_object_ref(ui->gui->PlayButton_active));
3484
3485 ui->status->file_browsed = TRUE;
3486
3487 if (ui->status->timer_active)
3488 {
3489 GList *song_list = NULL;
3490 song_list = g_list_append(song_list, g_strdup(fname));
3491
3492 if (!player_is_running(ui))
3493 {
3494 player_start(ui);
3495 }
3496 else if (ui->status->playing)
3497 {
3498 player_stop(ui);
3499 }
3500
3501 player_add_files_and_select(song_list, ui);
3502
3503 if (ui->status->playing && !player_is_paused(ui))
3504 {
3505 player_play(ui);
3506 }
3507
3508 g_list_foreach(song_list, (GFunc)g_free, NULL);
3509 g_list_free(song_list);
3510 }
3511 }
3512
get_left_drawing_time
gfloat get_left_drawing_time(gfloat current_time, gfloat total_time, gfloat zoom_coeff)
returns the value of the left drawing area
Definition: player_window.c:1437
create_player_control_frame
GtkWidget * create_player_control_frame(ui_state *ui)
creates the control player frame, stop button, play button, etc.
Definition: player_window.c:3033
get_right_drawing_time
gfloat get_right_drawing_time(gfloat current_time, gfloat total_time, gfloat zoom_coeff)
returns the value of the right drawing area
Definition: player_window.c:1428
player_is_paused
gint player_is_paused(ui_state *ui)
Check if the player is paused.
Definition: player_control.c:457
get_input_filename
gchar * get_input_filename(gui_state *gui)
Get the name of the input file.
Definition: main_window.c:76
change_current_filename
void change_current_filename(const gchar *fname, ui_state *ui)
Change the name of the song that is to be cut and played.
Definition: player_window.c:265
create_player_playlist_frame
GtkWidget * create_player_playlist_frame(ui_state *ui)
creates the playlist of the player
Definition: player_window.c:3247
gui_status
Definition: ui_types.h:409
player_quit
gint player_quit(ui_state *ui)
quits the player
Definition: player_control.c:611
player_is_running
gint player_is_running(ui_state *ui)
returns FALSE if the player is not running, else TRUE
Definition: player_control.c:95
Split_point
Definition: ui_types.h:74
print_status_bar_confirmation
void print_status_bar_confirmation(gint error, ui_state *ui)
Output an error message from libmp3splt to the status bar.
Definition: main_window.c:1115
cancel_quick_preview
void cancel_quick_preview(gui_status *status)
cancels quick preview
Definition: player_window.c:1579
add_playlist_file
void add_playlist_file(const gchar *name, ui_state *ui)
add a row to the table
Definition: player_window.c:3068
cancel_quick_preview_all
void cancel_quick_preview_all(ui_state *ui)
full cancel of the quick preview
Definition: player_window.c:1571
player_set_volume
void player_set_volume(gint volume, ui_state *ui)
sets the volume of the player
Definition: player_control.c:563
enable_player_buttons
void enable_player_buttons(ui_state *ui)
enables the buttons of the player
Definition: player_window.c:345
player_get_filename
gchar * player_get_filename(ui_state *ui)
gets the filename of the current song
Definition: player_control.c:485
file_exists
gint file_exists(const gchar *fname)
check if specified file exists
Definition: utilities.c:62
disconnect_button_event
void disconnect_button_event(GtkWidget *widget, ui_state *ui)
disconnect button event
Definition: player_window.c:641
cancel_button_event
void cancel_button_event(GtkWidget *widget, ui_state *ui)
event for the cancel button
Definition: main_window.c:300
connect_to_player_with_song
void connect_to_player_with_song(gint i, ui_state *ui)
connects to player with the song from the filename entry
Definition: player_window.c:531
ui_infos
Definition: ui_types.h:99
player_seek
void player_seek(gint position, ui_state *ui)
jumps to a position in the song
Definition: player_control.c:381
player_get_playlist_number
gint player_get_playlist_number(ui_state *ui)
returns the number of songs in the playlist
Definition: player_control.c:586
split_tree_row_activated
void split_tree_row_activated(GtkTreeView *split_tree, GtkTreePath *arg1, GtkTreeViewColumn *arg2, ui_state *ui)
Issued when a row is clicked on.
Definition: split_files_window.c:254
player_get_total_time
gint player_get_total_time(ui_state *ui)
returns total time of the song
Definition: player_control.c:70
player_get_title
gchar * player_get_title(ui_state *ui)
Get the title of the song.
Definition: player_control.c:513
player_start_play_with_songs
void player_start_play_with_songs(GList *list, ui_state *ui)
starts the player
Definition: player_control.c:240
ui_state
Definition: ui_types.h:485
player_prev
void player_prev(ui_state *ui)
pass to the previous song
Definition: player_control.c:358
set_input_filename
void set_input_filename(const gchar *filename, ui_state *ui)
Set the name of the input file.
Definition: main_window.c:44
connect_button_event
void connect_button_event(GtkWidget *widget, ui_state *ui)
play button event
Definition: player_window.c:537
player_start
void player_start(ui_state *ui)
starts the player
Definition: player_control.c:120
player_is_playing
gint player_is_playing(ui_state *ui)
returns TRUE if the player is playing, else FALSE
Definition: player_control.c:432
connect_snackamp
gint connect_snackamp(gint port, ui_state *ui)
connecting to the player to the port port
Definition: snackamp_control.c:48
update_splitpoint_check
void update_splitpoint_check(gint index, ui_state *ui)
Toggles a splitpoint&#39;s &quot;Keep&quot; flag.
Definition: splitpoints_window.c:783
put_status_message
void put_status_message(const gchar *text, ui_state *ui)
Output a info message to the status message bar.
Definition: main_window.c:264
disconnect_snackamp
gint disconnect_snackamp(ui_state *ui)
disconnecting with the player possibly returns an error
Definition: snackamp_control.c:200
get_splitpoint_name
gchar * get_splitpoint_name(gint index, ui_state *ui)
returns the name of the splitpoint
Definition: splitpoints_window.c:1496
create_detect_silence_and_add_splitpoints_window
void create_detect_silence_and_add_splitpoints_window(GtkWidget *button, ui_state *ui)
event for clicking the &#39;detect silence and add splitpoints&#39; button
Definition: splitpoints_window.c:1187
silence_wave
Definition: ui_types.h:89
player_get_elapsed_time
gint player_get_elapsed_time(ui_state *ui)
returns the elapsed time of the player
Definition: player_control.c:45
ui_with_err
Definition: ui_types.h:504
pause_event
void pause_event(GtkWidget *widget, ui_state *ui)
pause button event
Definition: player_window.c:753
draw_silence_wave
gint draw_silence_wave(gint left_mark, gint right_mark, gint interpolation_text_x, gint interpolation_text_y, gfloat draw_time, gint width_drawing_area, gint y_margin, gfloat current_time, gfloat total_time, gfloat zoom_coeff, GtkWidget *da, cairo_t *gc, ui_state *ui)
Draws the silence wave.
Definition: player_window.c:1874
player_add_files_and_select
void player_add_files_and_select(GList *list, ui_state *ui)
add files to playlist
Definition: player_control.c:189
gui_state
Definition: ui_types.h:202
player_quick_preview
void player_quick_preview(gint splitpoint_to_preview, ui_state *ui)
makes a quick preview of the song
Definition: player_window.c:2644
player_add_files
void player_add_files(GList *list, ui_state *ui)
add files to playlist
Definition: player_control.c:166
get_splitpoint_time
gint get_splitpoint_time(gint splitpoint_index, ui_state *ui)
returns a splitpoint from the table
Definition: splitpoints_window.c:1527
wh_container_has_child
gboolean wh_container_has_child(GtkContainer *container, GtkWidget *my_child)
Does this GtkContainer contain that object?
Definition: widgets_helper.c:302
update_splitpoint_from_time
void update_splitpoint_from_time(gint index, gdouble time, ui_state *ui)
Set a splitpoint&#39;s time value.
Definition: splitpoints_window.c:768
player_add_play_files
void player_add_play_files(GList *list, ui_state *ui)
add files to playlist
Definition: player_control.c:215
player_start_add_files
void player_start_add_files(GList *list, ui_state *ui)
start player and add files to playlist
Definition: player_control.c:143
player_get_volume
gint player_get_volume(ui_state *ui)
gets the volume of the player
Definition: player_control.c:538
select_splitpoint
void select_splitpoint(gint index, gui_state *gui)
selects a splitpoint
Definition: splitpoints_window.c:354
create_playlist_columns
void create_playlist_columns(GtkTreeView *playlist_tree)
creates playlist columns
Definition: player_window.c:3132
player_pause
void player_pause(ui_state *ui)
pause the song
Definition: player_control.c:312
get_first_splitpoint_selected
gint get_first_splitpoint_selected(gui_state *gui)
Gets the number of the first splitpoint with selected &quot;Keep&quot; checkbox.
Definition: splitpoints_window.c:263
player_stop
void player_stop(ui_state *ui)
stops the song
Definition: player_control.c:289
wh_create_cool_button
GtkWidget * wh_create_cool_button(gchar *stock_id, gchar *label_text, gint toggle_or_not)
creates a cool button with image from stock
Definition: widgets_helper.c:348
player_play
void player_play(ui_state *ui)
plays the song
Definition: player_control.c:266
show_connect_button
void show_connect_button(gui_state *gui)
Show the connect button.
Definition: player_window.c:431
player_next
void player_next(ui_state *ui)
pass to the next song
Definition: player_control.c:335
hide_connect_button
void hide_connect_button(gui_state *gui)
Hide the connect button.
Definition: player_window.c:407
get_real_name_from_filename
const gchar * get_real_name_from_filename(const gchar *filename)
finding the real name of the file, without the path
Definition: split_files_window.c:92
player_get_song_infos
void player_get_song_infos(gchar *total_infos, ui_state *ui)
get infos about the song
Definition: player_control.c:409
remove_status_message
void remove_status_message(gui_state *gui)
Removes status bar message.
Definition: main_window.c:252
check_update_down_progress_bar
void check_update_down_progress_bar(ui_state *ui)
updates bottom progress bar
Definition: player_window.c:1087
remove_splitpoint
void remove_splitpoint(gint index, gint stop_preview, ui_state *ui)
removes a splitpoint
Definition: splitpoints_window.c:421