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