2 * playlist.c -- GTK+ 2 omnplay
3 * Copyright (C) 2011 Maksym Veremeyenko <verem@m1stereo.tv>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <gdk/gdkkeysyms.h>
36 extern GtkTargetEntry drag_targets
[];
38 static void playlist_get_selected_items_idx_iter
47 int **plist
= (int**)data
;
50 gtk_tree_model_get(model
, iter
, 7, &idx
, -1);
54 list
= (int*)malloc(sizeof(int));
58 /* find numbers of items in list */
59 for(l
= 0; -1 != list
[l
]; l
++);
60 g_warning("playlist_get_selected_items_idx_iter: l=%d", l
);
63 list
= (int*)realloc(list
, (l
+ 2) * sizeof(int));
74 int* playlist_get_selected_items_idx(instance_t
* app
, int *count
)
76 int* list
= NULL
, l
= 0;
77 GtkTreeSelection
*selection
;
79 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
));
82 gtk_tree_selection_selected_foreach(
84 playlist_get_selected_items_idx_iter
,
88 for(l
= 0; -1 != list
[l
]; l
++);
96 static void playlist_drag_data_get_cb(GtkWidget
*widget
, GdkDragContext
*context
,
97 GtkSelectionData
*selection_data
, guint info
, guint time
, gpointer userdata
)
100 playlist_item_t
* items
;
101 instance_t
* app
= (instance_t
*)userdata
;
103 g_warning("playlist_drag_data_get_cb");
105 list
= playlist_get_selected_items_idx(app
, &c
);
108 /* clear delete flag */
109 for(i
= 0; i
< app
->playlist
.count
; i
++)
110 app
->playlist
.item
[i
].del
= 0;
112 items
= (playlist_item_t
*)malloc(sizeof(playlist_item_t
) * c
);
113 for(i
= 0; i
< c
; i
++)
115 items
[i
] = app
->playlist
.item
[list
[i
]];
116 if(context
->action
== GDK_ACTION_MOVE
)
117 app
->playlist
.item
[list
[i
]].del
= 1;
119 gtk_selection_data_set(selection_data
, selection_data
->target
, 8,
120 (const guchar
*)items
, sizeof(playlist_item_t
) * c
);
126 static void playlist_drag_begin_cb(GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
128 g_warning("playlist_drag_begin_cb");
129 gtk_drag_source_set_icon_stock(widget
, GTK_STOCK_DND
);
132 static void playlist_drag_data_received(GtkWidget
*widget
, GdkDragContext
*context
,
133 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
, gpointer userdata
)
136 playlist_item_type_t t
;
137 playlist_item_t
* items
;
138 GtkTreePath
*path
= NULL
;
139 instance_t
* app
= (instance_t
*)userdata
;
141 g_warning("playlist_drag_data_received: context->action=%d", context
->action
);
143 items
= (playlist_item_t
*)gtk_selection_data_get_data(selection_data
);
144 c
= gtk_selection_data_get_length(selection_data
);
146 if(c
% sizeof(playlist_item_t
))
148 g_warning("playlist_drag_data_received: ODD ITEMS");
152 c
/= sizeof(playlist_item_t
);
154 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget
), x
, y
, &path
, NULL
, NULL
, NULL
))
156 idx
= gtk_tree_path_get_indices(path
)[0];
157 gtk_tree_path_free(path
);
159 g_warning("playlist_drag_data_received: gtk_tree_path_get_indice[0]=%d", idx
);
161 /* normalize, FIX ME */
162 idx
--; if(idx
< 0) idx
= 0;
165 idx
= app
->playlist
.count
;
167 g_warning("playlist_drag_data_received: idx=%d", idx
);
169 if(playlist_insert_check(app
, idx
, &t
))
171 for(i
= 0; i
< c
; i
++)
176 playlist_insert_items(app
, idx
, items
, c
);
180 /* Finish the drag */
181 gtk_drag_finish(context
, TRUE
, FALSE
, time
);
184 static void playlist_drag_data_delete(GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
187 instance_t
* app
= (instance_t
*)userdata
;
189 g_warning("playlist_drag_data_delete");
191 list
= (int*)malloc(sizeof(int) * MAX_PLAYLIST_ITEMS
);
193 for(i
= 0, c
= 0; i
< app
->playlist
.count
; i
++)
194 if(app
->playlist
.item
[i
].del
)
195 if(!playlist_idx_cued(app
, i
, NULL
))
199 g_warning("playlist_drag_data_delete: i=%d, c=%d", i
, c
);
203 playlist_delete_items(app
, list
, c
, 0);
209 * http://www.mail-archive.com/mahogany-users@lists.sourceforge.net/msg00286.html
211 static gboolean
playlist_drag_motion(GtkWidget
*widget
, GdkDragContext
*context
,
212 gint x
, gint y
, guint time
, gpointer data
)
215 GtkWidget
*source_widget
;
217 g_warning("playlist_grid_drag_motion");
219 /* Get source widget and check if it is the same as the
220 * destination widget.
222 source_widget
= gtk_drag_get_source_widget(context
);
223 same
= ((source_widget
== widget
) ? TRUE
: FALSE
);
225 /* Put additional checks here, perhaps if same is FALSE then
226 * set the default drag to GDK_ACTION_COPY.
229 /* Say we just want to allow GDK_ACTION_MOVE, first we check
230 * if that is in the list of allowed actions on the dc. If
231 * so then we set it to that. Note if the user holds down the
232 * ctrl key then the only flag in dc->actions will be
233 * GDK_ACTION_COPY. The constraint for dc->actions is that
234 * specified from the given actions in gtk_drag_dest_set() and
235 * gtk_drag_source_set().
239 if(context
->actions
== GDK_ACTION_MOVE
)
240 gdk_drag_status(context
, GDK_ACTION_COPY
, time
);
242 gdk_drag_status(context
, GDK_ACTION_MOVE
, time
);
245 gdk_drag_status(context
, context
->actions
, time
);
251 int playlist_item_index(instance_t
* app
, int start
, int int_idx
)
253 if(start
< 0 || start
>= app
->playlist
.count
)
258 if(app
->playlist
.item
[start
].int_idx
== int_idx
)
261 if(app
->playlist
.item
[start
].type
& PLAYLIST_BLOCK_END
)
271 void playlist_init(instance_t
* app
)
273 gtk_drag_source_set(app
->playlist_grid
, GDK_BUTTON1_MASK
,
274 drag_targets
, 1, (GdkDragAction
)(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
276 gtk_drag_dest_set(app
->playlist_grid
, (GtkDestDefaults
)(GTK_DEST_DEFAULT_HIGHLIGHT
| GTK_DEST_DEFAULT_DROP
),
277 drag_targets
, 1, (GdkDragAction
)(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
279 g_signal_connect (app
->playlist_grid
, "drag_data_get", G_CALLBACK(playlist_drag_data_get_cb
), app
);
280 g_signal_connect (app
->playlist_grid
, "drag_begin", G_CALLBACK(playlist_drag_begin_cb
), app
);
281 g_signal_connect (app
->playlist_grid
, "drag_data_received", G_CALLBACK (playlist_drag_data_received
), app
);
282 g_signal_connect (app
->playlist_grid
, "drag_data_delete", G_CALLBACK (playlist_drag_data_delete
), app
);
283 g_signal_connect (app
->playlist_grid
, "drag_motion", G_CALLBACK (playlist_drag_motion
), app
);
286 void playlist_release(instance_t
* app
)
290 int playlist_idx_cued(instance_t
* app
, int idx
, int* player_idx
)
294 for(i
= 0; i
< app
->players
.count
; i
++)
298 a
= app
->players
.item
[i
].playlist_start
;
299 b
= app
->players
.item
[i
].playlist_length
;
306 if(idx
>= a
&& idx
<= b
)
317 int playlist_range_cued(instance_t
* app
, int start
, int stop
)
321 for(i
= start
; i
<= stop
; i
++)
322 if(playlist_idx_cued(app
, i
, NULL
))
328 void playlist_block(instance_t
* app
, int loop
)
330 int start
, stop
, i
, c
;
331 int* list
= playlist_get_selected_items_idx(app
, &c
);
336 pthread_mutex_lock(&app
->playlist
.lock
);
337 pthread_mutex_lock(&app
->players
.lock
);
343 loop
= PLAYLIST_BLOCK_LOOP
;
345 if(!playlist_range_cued(app
, start
, stop
))
347 /* update selected item */
348 for(i
= start
; i
<= stop
; i
++)
350 int t
= PLAYLIST_BLOCK_BODY
| loop
;
352 if(i
== start
) t
|= PLAYLIST_BLOCK_BEGIN
;
353 if(i
== stop
) t
|= PLAYLIST_BLOCK_END
;
355 app
->playlist
.item
[i
].type
= (playlist_item_type_t
)t
;
357 ui_playlist_draw_item(app
, i
);
360 /* update border items */
361 if(start
&& !(app
->playlist
.item
[start
- 1].type
& PLAYLIST_BLOCK_END
))
363 app
->playlist
.item
[start
- 1].type
= (playlist_item_type_t
)(PLAYLIST_BLOCK_END
364 | app
->playlist
.item
[start
- 1].type
);
365 ui_playlist_draw_item(app
, start
- 1);
367 if((stop
+ 1) < app
->playlist
.count
&& !(app
->playlist
.item
[stop
+ 1].type
& PLAYLIST_BLOCK_BEGIN
))
369 app
->playlist
.item
[stop
+ 1].type
= (playlist_item_type_t
)(PLAYLIST_BLOCK_BEGIN
370 | app
->playlist
.item
[stop
+ 1].type
);
371 ui_playlist_draw_item(app
, stop
+ 1);
375 g_warning("omnplay_playlist_block: range [%d %d] do OVERLAP player\n",
378 pthread_mutex_unlock(&app
->players
.lock
);
379 pthread_mutex_unlock(&app
->playlist
.lock
);
384 int playlist_get_first_selected_item_idx(instance_t
* app
)
387 int* list
= playlist_get_selected_items_idx(app
, &c
);
395 int playlist_get_block(instance_t
* app
, int idx
, int* pstart
, int* pstop
)
399 for(start
= idx
; start
>= 0; start
--)
400 if(app
->playlist
.item
[start
].type
& PLAYLIST_BLOCK_BEGIN
)
403 for(stop
= idx
; stop
< app
->playlist
.count
; stop
++)
404 if(app
->playlist
.item
[stop
].type
& PLAYLIST_BLOCK_END
)
407 g_warning("playlist_get_block: range %d -> %d\n", start
, stop
);
409 /* check block range */
410 if(start
>= 0 && stop
< app
->playlist
.count
)
414 return (stop
- start
+ 1);
420 player_t
*playlist_get_player_at_pos(instance_t
* app
, int pos
)
422 /* check player range */
423 if(app
->playlist
.item
[pos
].player
> -1 && app
->playlist
.item
[pos
].player
< app
->players
.count
)
424 return &app
->players
.item
[app
->playlist
.item
[pos
].player
];
429 void playlist_delete_items(instance_t
* app
, int* idxs
, int count
, int sel
)
433 pthread_mutex_lock(&app
->playlist
.lock
);
434 pthread_mutex_lock(&app
->players
.lock
);
436 for(j
= 0; j
< count
; j
++)
440 /* fix block types */
441 if( app
->playlist
.item
[idx
].type
!= PLAYLIST_ITEM_BLOCK_BODY
&&
442 app
->playlist
.item
[idx
].type
!= PLAYLIST_ITEM_LOOP_BODY
)
445 app
->playlist
.item
[idx
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
- 1].type
|
447 if(idx
+ 1 < app
->playlist
.count
)
448 app
->playlist
.item
[idx
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
+ 1].type
|
449 PLAYLIST_BLOCK_BEGIN
);
452 /* shift playlist items */
455 &app
->playlist
.item
[idx
],
456 &app
->playlist
.item
[idx
+ 1],
457 (app
->playlist
.count
- idx
- 1) * sizeof(playlist_item_t
)
460 /* decrement items count */
461 app
->playlist
.count
--;
463 /* increment servers indexes */
464 for(i
= 0; i
< app
->players
.count
; i
++)
465 if(app
->players
.item
[i
].playlist_start
>= idx
)
466 app
->players
.item
[i
].playlist_start
--;
469 /* redraw playlist */
470 ui_playlist_draw(app
);
474 ui_playlist_select_item(app
, idxs
[0]);
476 pthread_mutex_unlock(&app
->players
.lock
);
477 pthread_mutex_unlock(&app
->playlist
.lock
);
480 void playlist_delete_selected_items(instance_t
* app
)
485 list1
= playlist_get_selected_items_idx(app
, &cnt1
);
488 list2
= (int*)malloc(sizeof(int) * cnt1
);
490 for(i
= 0, cnt2
= 0; i
< cnt1
; i
++)
492 /* check for playing block */
493 if(playlist_idx_cued(app
, list1
[i
], NULL
))
497 list2
[cnt2
++] = list1
[i
];
501 playlist_delete_items(app
, list2
, cnt2
, 1);
507 int playlist_insert_check(instance_t
* app
, int idx
, playlist_item_type_t
* t
)
509 *t
= PLAYLIST_ITEM_BLOCK_SINGLE
;
511 /* before or after playlist */
512 if(!idx
|| idx
== app
->playlist
.count
)
515 /* check for block borders */
516 if( app
->playlist
.item
[idx
- 1].type
& PLAYLIST_BLOCK_END
&&
517 app
->playlist
.item
[idx
+ 0].type
& PLAYLIST_BLOCK_BEGIN
)
520 /* check for playing block */
521 if(playlist_idx_cued(app
, idx
, NULL
))
524 if(app
->playlist
.item
[idx
].type
& PLAYLIST_BLOCK_LOOP
)
525 *t
= PLAYLIST_ITEM_LOOP_BODY
;
527 *t
= PLAYLIST_ITEM_BLOCK_BODY
;
532 void playlist_insert_items(instance_t
* app
, int idx
, playlist_item_t
* items
, int count
)
536 pthread_mutex_lock(&app
->playlist
.lock
);
537 pthread_mutex_lock(&app
->players
.lock
);
539 /* shift playlist items */
542 &app
->playlist
.item
[idx
+ count
],
543 &app
->playlist
.item
[idx
],
544 (app
->playlist
.count
- idx
) * sizeof(playlist_item_t
)
550 &app
->playlist
.item
[idx
],
552 count
* sizeof(playlist_item_t
)
555 /* increment servers indexes */
556 for(i
= 0; i
< app
->players
.count
; i
++)
557 if(app
->players
.item
[i
].playlist_start
>= idx
)
558 app
->players
.item
[i
].playlist_start
+= idx
;
560 /* increment items count */
561 app
->playlist
.count
+= count
;
563 /* redraw playlist */
564 ui_playlist_draw(app
);
567 ui_playlist_select_item(app
, idx
);
569 pthread_mutex_unlock(&app
->players
.lock
);
570 pthread_mutex_unlock(&app
->playlist
.lock
);
573 void playlist_item_copy(instance_t
* app
)
577 list
= playlist_get_selected_items_idx(app
, &c
);
580 for(i
= 0; i
< c
; i
++)
581 app
->clipboard
.item
[i
] = app
->playlist
.item
[list
[i
]];
582 app
->clipboard
.count
= c
;
587 void playlist_item_paste(instance_t
* app
, int after
)
590 playlist_item_type_t t
;
592 /* find insert position */
593 idx
= playlist_get_first_selected_item_idx(app
);
599 if(!playlist_insert_check(app
, idx
, &t
))
603 if(app
->clipboard
.count
)
605 for(i
= 0; i
< app
->clipboard
.count
; i
++)
607 app
->clipboard
.item
[i
].type
= t
;
608 app
->clipboard
.item
[i
].error
= 0;
610 playlist_insert_items(app
, idx
, app
->clipboard
.item
, app
->clipboard
.count
);
614 void playlist_item_swap(instance_t
* app
, int dir
)
616 int sel
, a
, b
, e
= 1;
617 playlist_item_t item
;
619 /* find insert position */
620 sel
= playlist_get_first_selected_item_idx(app
);
637 /* check for playing block */
638 if(playlist_idx_cued(app
, a
, NULL
) || playlist_idx_cued(app
, b
, NULL
))
641 pthread_mutex_lock(&app
->playlist
.lock
);
642 pthread_mutex_lock(&app
->players
.lock
);
645 item
= app
->playlist
.item
[a
];
646 app
->playlist
.item
[a
] = app
->playlist
.item
[b
];
647 app
->playlist
.item
[b
] = item
;
650 if(app
->playlist
.item
[a
].type
!= app
->playlist
.item
[b
].type
)
653 app
->playlist
.item
[a
].type
= PLAYLIST_ITEM_BLOCK_SINGLE
;
654 app
->playlist
.item
[b
].type
= PLAYLIST_ITEM_BLOCK_SINGLE
;
657 /* redraw main items */
658 ui_playlist_draw_item(app
, a
);
659 ui_playlist_draw_item(app
, b
);
661 /* fix block types */
664 app
->playlist
.item
[a
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[a
- 1].type
|
666 ui_playlist_draw_item(app
, a
- 1);
668 if(b
+ 1 < app
->playlist
.count
&& !e
)
670 app
->playlist
.item
[b
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[b
+ 1].type
|
671 PLAYLIST_BLOCK_BEGIN
);
672 ui_playlist_draw_item(app
, b
+ 1);
676 ui_playlist_select_item(app
, sel
);
678 pthread_mutex_unlock(&app
->players
.lock
);
679 pthread_mutex_unlock(&app
->playlist
.lock
);
683 static int playlist_load_file_ply(instance_t
* app
, char* filename
)
686 char *ID
, *CH
, *B
, *IN
, *OUT
, *DUR
, *REST
, *l
;
688 playlist_item_t
* items
;
690 /* allocate space for strings and items */
691 items
= malloc(sizeof(playlist_item_t
) * MAX_PLAYLIST_ITEMS
);
692 memset(items
, 0, sizeof(playlist_item_t
) * MAX_PLAYLIST_ITEMS
);
693 ID
= malloc(PATH_MAX
);
694 CH
= malloc(PATH_MAX
);
695 B
= malloc(PATH_MAX
);
696 IN
= malloc(PATH_MAX
);
697 OUT
= malloc(PATH_MAX
);
698 DUR
= malloc(PATH_MAX
);
699 REST
= malloc(PATH_MAX
);
700 l
= malloc(PATH_MAX
);
702 /* open and process file */
703 f
= fopen(filename
, "rt");
711 memset(l
, 0, PATH_MAX
);
712 fgets(l
, PATH_MAX
, f
);
714 /* remove newlines */
715 if( (s
= strchr(l
, '\n')) ) *s
= 0;
716 if( (s
= strchr(l
, '\r')) ) *s
= 0;
717 if( (s
= strchr(l
, '\t')) ) *s
= 0;
719 /* check for empty line */
720 if(l
[0] && l
[0] != '#')
722 if (6 != sscanf(l
, "%128[^,],%128[^,],%128[^,],%128[^,],%128[^,],%128[^,],%s",
723 ID
, CH
, B
, IN
, OUT
, DUR
, REST
))
727 tc2frames(IN
, 25.0, &items
[count
].in
);
728 tc2frames(DUR
, 25.0, &items
[count
].dur
);
729 strncpy(items
[count
].id
, ID
, PATH_MAX
);
730 items
[count
].player
= atol(CH
) - 1;
733 case 1: items
[count
].type
= PLAYLIST_ITEM_BLOCK_SINGLE
; break;
734 case 2: items
[count
].type
= PLAYLIST_ITEM_LOOP_BEGIN
; break;
735 case 3: items
[count
].type
= PLAYLIST_ITEM_LOOP_BODY
; break;
736 case 4: items
[count
].type
= PLAYLIST_ITEM_LOOP_END
; break;
737 case 6: items
[count
].type
= PLAYLIST_ITEM_BLOCK_END
; break;
740 items
[count
].type
= PLAYLIST_ITEM_BLOCK_BEGIN
;
741 else if(items
[count
- 1].type
== PLAYLIST_ITEM_BLOCK_BEGIN
||
742 items
[count
- 1].type
== PLAYLIST_ITEM_BLOCK_BODY
)
743 items
[count
].type
= PLAYLIST_ITEM_BLOCK_BODY
;
745 items
[count
].type
= PLAYLIST_ITEM_BLOCK_BEGIN
;
749 items
[count
].type
= b
- 1024;
754 switch(items
[count
].type
)
756 case PLAYLIST_ITEM_BLOCK_BEGIN
: n
= "BLOCK_BEGIN"; break;
757 case PLAYLIST_ITEM_BLOCK_BODY
: n
= "BLOCK_BODY"; break;
758 case PLAYLIST_ITEM_BLOCK_END
: n
= "BLOCK_END"; break;
759 case PLAYLIST_ITEM_BLOCK_SINGLE
: n
= "BLOCK_SINGLE"; break;
760 case PLAYLIST_ITEM_LOOP_BEGIN
: n
= "LOOP_BEGIN"; break;
761 case PLAYLIST_ITEM_LOOP_BODY
: n
= "LOOP_BODY"; break;
762 case PLAYLIST_ITEM_LOOP_END
: n
= "LOOP_END"; break;
763 case PLAYLIST_ITEM_LOOP_SINGLE
: n
= "LOOP_SINGLE"; break;
765 fprintf(stderr
, "src=[%s]\ndst=[idx=%d,block=%s,block_id=%d,in=%d,out=%d]\n",
766 l
, count
, n
, items
[count
].type
, items
[count
].in
, items
[count
].dur
);
778 /* add loaded items to playlist */
781 pthread_mutex_lock(&app
->playlist
.lock
);
782 for(i
= 0; i
< count
&& app
->playlist
.count
+ 1 < MAX_PLAYLIST_ITEMS
; i
++)
784 // omnplay_library_normalize_item(app, &items[i]);
785 app
->playlist
.item
[app
->playlist
.count
++] = items
[i
];
787 app
->playlist
.ver_curr
++;
788 pthread_mutex_unlock(&app
->playlist
.lock
);
804 void playlist_load(instance_t
* app
)
808 GtkFileFilter
*filter
;
810 dialog
= gtk_file_chooser_dialog_new("Open File",
811 GTK_WINDOW (app
->window
),
812 GTK_FILE_CHOOSER_ACTION_OPEN
,
813 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
814 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
817 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog
),
818 (app
->playlist
.path
)?app
->playlist
.path
:getenv("HOME"));
820 filter
= gtk_file_filter_new();
821 gtk_file_filter_set_name(filter
, "Playlist formatted (*.ply)");
822 gtk_file_filter_add_pattern(filter
, "*.ply");
823 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
824 filter
= gtk_file_filter_new();
825 gtk_file_filter_set_name(filter
, "All types (*.*)");
826 gtk_file_filter_add_pattern(filter
, "*.*");
827 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
829 r
= gtk_dialog_run(GTK_DIALOG(dialog
));
831 if(r
== GTK_RESPONSE_ACCEPT
)
835 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog
));
837 r
= playlist_load_file_ply(app
, filename
);
840 ui_playlist_draw(app
);
842 if(app
->playlist
.path
)
843 g_free(app
->playlist
.path
);
844 if((app
->playlist
.path
= filename
))
846 char* e
= strrchr(app
->playlist
.path
, '/');
851 gtk_widget_destroy (dialog
);
854 static int playlist_save_file_ply(instance_t
* app
, char* filename
)
858 char tc1
[12], tc2
[12], tc3
[12];
859 char* fname
= filename
;
861 filename
= (char*)malloc(PATH_MAX
);
862 strncpy(filename
, fname
, PATH_MAX
);
863 i
= strlen(filename
);
864 if(i
< 4 || strcasecmp(filename
+ i
- 4, ".ply"))
865 strcat(filename
, ".ply");
867 if((f
= fopen(filename
, "wt")))
869 for(i
= 0; i
< app
->playlist
.count
; i
++)
870 fprintf(f
, "%s,%d,%d,%s,%s,%s,,,,,,,,\n",
871 app
->playlist
.item
[i
].id
,
872 app
->playlist
.item
[i
].player
+ 1,
873 app
->playlist
.item
[i
].type
+ 1024,
874 frames2tc(app
->playlist
.item
[i
].in
, 25.0, tc1
),
875 frames2tc(app
->playlist
.item
[i
].in
+ app
->playlist
.item
[i
].dur
, 25.0, tc2
),
876 frames2tc(app
->playlist
.item
[i
].dur
, 25.0, tc3
));
886 void playlist_save(instance_t
* app
)
890 GtkFileFilter
*filter
;
892 dialog
= gtk_file_chooser_dialog_new("Save File",
893 GTK_WINDOW (app
->window
),
894 GTK_FILE_CHOOSER_ACTION_SAVE
,
895 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
896 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
899 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog
), TRUE
);
901 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog
),
902 (app
->playlist
.path
)?app
->playlist
.path
:getenv("HOME"));
904 filter
= gtk_file_filter_new();
905 gtk_file_filter_set_name(filter
, "Playlist formatted (*.ply)");
906 gtk_file_filter_add_pattern(filter
, "*.ply");
907 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
908 g_object_set_data(G_OBJECT(filter
), "id", GINT_TO_POINTER(0));
909 filter
= gtk_file_filter_new();
910 gtk_file_filter_set_name(filter
, "Text (*.txt)");
911 gtk_file_filter_add_pattern(filter
, "*.*");
912 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
913 g_object_set_data(G_OBJECT(filter
), "id", GINT_TO_POINTER(1));
915 r
= gtk_dialog_run(GTK_DIALOG(dialog
));
917 if(r
== GTK_RESPONSE_ACCEPT
)
921 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog
));
923 r
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog
))), "id"));
925 r
= playlist_save_file_ply(app
, filename
);
927 if(app
->playlist
.path
)
928 g_free(app
->playlist
.path
);
929 if((app
->playlist
.path
= filename
))
931 char* e
= strrchr(app
->playlist
.path
, '/');
936 gtk_widget_destroy (dialog
);
940 void playlist_relink(instance_t
* app
)
945 pthread_mutex_lock(&app
->playlist
.lock
);
946 list
= playlist_get_selected_items_idx(app
, &cnt
);
949 for(i
= 0; i
< cnt
; i
++)
951 /* check for playing block */
952 if(playlist_idx_cued(app
, list
[i
], NULL
))
956 library_relink_item(app
, &app
->playlist
.item
[list
[i
]]);
961 pthread_mutex_unlock(&app
->playlist
.lock
);
963 /* redraw playlist */
964 ui_playlist_draw(app
);
967 void playlist_item_add(instance_t
* app
, int after
)
970 playlist_item_t item
;
971 playlist_item_type_t t
;
973 /* find insert position */
974 idx
= playlist_get_first_selected_item_idx(app
);
980 if(!playlist_insert_check(app
, idx
, &t
))
983 g_warning("allowed insert into idx=%d\n", idx
);
986 memset(&item
, 0, sizeof(playlist_item_t
));
987 if(ui_playlist_item_dialog(app
, &item
))
989 library_normalize_item(app
, &item
);
991 playlist_insert_items(app
, idx
, &item
, 1);
995 void playlist_item_edit(instance_t
* app
)
998 playlist_item_t item
;
1000 /* find insert position */
1001 idx
= playlist_get_first_selected_item_idx(app
);
1006 /* check for playing block */
1007 if(playlist_idx_cued(app
, idx
, NULL
))
1010 item
= app
->playlist
.item
[idx
];
1012 if(ui_playlist_item_dialog(app
, &item
))
1014 library_normalize_item(app
, &item
);
1015 app
->playlist
.item
[idx
] = item
;
1016 ui_playlist_draw_item(app
, idx
);
1020 void playlist_item_add_from_library(instance_t
* app
, int after
)
1024 void playlist_normalize(instance_t
* app
)
1028 /* normalize playlist */
1029 for(i
= 0; i
< app
->playlist
.count
; i
++)
1030 if(library_normalize_item(app
, &app
->playlist
.item
[i
]))
1031 ui_playlist_draw_item(app
, i
);