mp3splt-gtk: src/player_window.c Source File

mp3splt-gtk 0.9.3.1519

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