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>
35 extern GtkTargetEntry drag_targets
[];
37 static void playlist_get_selected_items_idx_iter
46 int **plist
= (int**)data
;
49 gtk_tree_model_get(model
, iter
, 7, &idx
, -1);
53 list
= (int*)malloc(sizeof(int));
57 /* find numbers of items in list */
58 for(l
= 0; -1 != list
[l
]; l
++);
59 g_warning("playlist_get_selected_items_idx_iter: l=%d", l
);
62 list
= (int*)realloc(list
, (l
+ 2) * sizeof(int));
73 int* playlist_get_selected_items_idx(instance_t
* app
, int *count
)
75 int* list
= NULL
, l
= 0;
76 GtkTreeSelection
*selection
;
78 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
));
81 gtk_tree_selection_selected_foreach(
83 playlist_get_selected_items_idx_iter
,
87 for(l
= 0; -1 != list
[l
]; l
++);
95 static void playlist_drag_data_get_cb(GtkWidget
*widget
, GdkDragContext
*context
,
96 GtkSelectionData
*selection_data
, guint info
, guint time
, gpointer userdata
)
99 playlist_item_t
* items
;
100 instance_t
* app
= (instance_t
*)userdata
;
102 g_warning("playlist_drag_data_get_cb");
104 list
= playlist_get_selected_items_idx(app
, &c
);
107 /* clear delete flag */
108 for(i
= 0; i
< app
->playlist
.count
; i
++)
109 app
->playlist
.item
[i
].del
= 0;
111 items
= (playlist_item_t
*)malloc(sizeof(playlist_item_t
) * c
);
112 for(i
= 0; i
< c
; i
++)
114 items
[i
] = app
->playlist
.item
[list
[i
]];
115 if(context
->action
== GDK_ACTION_MOVE
)
116 app
->playlist
.item
[list
[i
]].del
= 1;
118 gtk_selection_data_set(selection_data
, selection_data
->target
, 8,
119 (const guchar
*)items
, sizeof(playlist_item_t
) * c
);
125 static void playlist_drag_begin_cb(GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
127 g_warning("playlist_drag_begin_cb");
128 gtk_drag_source_set_icon_stock(widget
, GTK_STOCK_DND
);
131 static void playlist_drag_data_received(GtkWidget
*widget
, GdkDragContext
*context
,
132 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
, gpointer userdata
)
135 playlist_item_type_t t
;
136 playlist_item_t
* items
;
137 GtkTreePath
*path
= NULL
;
138 instance_t
* app
= (instance_t
*)userdata
;
140 g_warning("playlist_drag_data_received: context->action=%d", context
->action
);
142 items
= (playlist_item_t
*)gtk_selection_data_get_data(selection_data
);
143 c
= gtk_selection_data_get_length(selection_data
);
145 if(c
% sizeof(playlist_item_t
))
147 g_warning("playlist_drag_data_received: ODD ITEMS");
151 c
/= sizeof(playlist_item_t
);
153 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget
), x
, y
, &path
, NULL
, NULL
, NULL
))
155 idx
= gtk_tree_path_get_indices(path
)[0];
156 gtk_tree_path_free(path
);
158 g_warning("playlist_drag_data_received: gtk_tree_path_get_indice[0]=%d", idx
);
160 /* normalize, FIX ME */
161 idx
--; if(idx
< 0) idx
= 0;
164 idx
= app
->playlist
.count
;
166 g_warning("playlist_drag_data_received: idx=%d", idx
);
168 if(playlist_insert_check(app
, idx
, &t
))
170 for(i
= 0; i
< c
; i
++)
175 playlist_insert_items(app
, idx
, items
, c
);
179 /* Finish the drag */
180 gtk_drag_finish(context
, TRUE
, FALSE
, time
);
183 static void playlist_drag_data_delete(GtkWidget
*widget
, GdkDragContext
*context
, gpointer userdata
)
186 instance_t
* app
= (instance_t
*)userdata
;
188 g_warning("playlist_drag_data_delete");
190 list
= (int*)malloc(sizeof(int) * MAX_PLAYLIST_ITEMS
);
192 for(i
= 0, c
= 0; i
< app
->playlist
.count
; i
++)
193 if(app
->playlist
.item
[i
].del
)
194 if(!playlist_idx_cued(app
, i
, NULL
))
198 g_warning("playlist_drag_data_delete: i=%d, c=%d", i
, c
);
202 playlist_delete_items(app
, list
, c
, 0);
208 * http://www.mail-archive.com/mahogany-users@lists.sourceforge.net/msg00286.html
210 static gboolean
playlist_drag_motion(GtkWidget
*widget
, GdkDragContext
*context
,
211 gint x
, gint y
, guint time
, gpointer data
)
214 GtkWidget
*source_widget
;
216 g_warning("playlist_grid_drag_motion");
218 /* Get source widget and check if it is the same as the
219 * destination widget.
221 source_widget
= gtk_drag_get_source_widget(context
);
222 same
= ((source_widget
== widget
) ? TRUE
: FALSE
);
224 /* Put additional checks here, perhaps if same is FALSE then
225 * set the default drag to GDK_ACTION_COPY.
228 /* Say we just want to allow GDK_ACTION_MOVE, first we check
229 * if that is in the list of allowed actions on the dc. If
230 * so then we set it to that. Note if the user holds down the
231 * ctrl key then the only flag in dc->actions will be
232 * GDK_ACTION_COPY. The constraint for dc->actions is that
233 * specified from the given actions in gtk_drag_dest_set() and
234 * gtk_drag_source_set().
238 if(context
->actions
== GDK_ACTION_MOVE
)
239 gdk_drag_status(context
, GDK_ACTION_COPY
, time
);
241 gdk_drag_status(context
, GDK_ACTION_MOVE
, time
);
244 gdk_drag_status(context
, context
->actions
, time
);
250 int playlist_item_index(instance_t
* app
, int start
, int int_idx
)
252 if(start
< 0 || start
>= app
->playlist
.count
)
257 if(app
->playlist
.item
[start
].int_idx
== int_idx
)
260 if(app
->playlist
.item
[start
].type
& PLAYLIST_BLOCK_END
)
270 void playlist_init(instance_t
* app
)
272 gtk_drag_source_set(app
->playlist_grid
, GDK_BUTTON1_MASK
,
273 drag_targets
, 1, (GdkDragAction
)(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
275 gtk_drag_dest_set(app
->playlist_grid
, (GtkDestDefaults
)(GTK_DEST_DEFAULT_HIGHLIGHT
| GTK_DEST_DEFAULT_DROP
),
276 drag_targets
, 1, (GdkDragAction
)(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
278 g_signal_connect (app
->playlist_grid
, "drag_data_get", G_CALLBACK(playlist_drag_data_get_cb
), app
);
279 g_signal_connect (app
->playlist_grid
, "drag_begin", G_CALLBACK(playlist_drag_begin_cb
), app
);
280 g_signal_connect (app
->playlist_grid
, "drag_data_received", G_CALLBACK (playlist_drag_data_received
), app
);
281 g_signal_connect (app
->playlist_grid
, "drag_data_delete", G_CALLBACK (playlist_drag_data_delete
), app
);
282 g_signal_connect (app
->playlist_grid
, "drag_motion", G_CALLBACK (playlist_drag_motion
), app
);
285 void playlist_release(instance_t
* app
)
289 int playlist_idx_cued(instance_t
* app
, int idx
, int* player_idx
)
293 for(i
= 0; i
< app
->players
.count
; i
++)
297 a
= app
->players
.item
[i
].playlist_start
;
298 b
= app
->players
.item
[i
].playlist_length
;
305 if(idx
>= a
&& idx
<= b
)
316 int playlist_range_cued(instance_t
* app
, int start
, int stop
)
320 for(i
= start
; i
<= stop
; i
++)
321 if(playlist_idx_cued(app
, i
, NULL
))
327 void playlist_block(instance_t
* app
, int loop
)
329 int start
, stop
, i
, c
;
330 int* list
= playlist_get_selected_items_idx(app
, &c
);
335 pthread_mutex_lock(&app
->playlist
.lock
);
336 pthread_mutex_lock(&app
->players
.lock
);
341 if(!playlist_range_cued(app
, start
, stop
))
343 /* update selected item */
344 for(i
= start
; i
<= stop
; i
++)
346 int t
= PLAYLIST_BLOCK_BODY
| loop
;
348 if(i
== start
) t
|= PLAYLIST_BLOCK_BEGIN
;
349 if(i
== stop
) t
|= PLAYLIST_BLOCK_END
;
351 app
->playlist
.item
[i
].type
= (playlist_item_type_t
)t
;
353 ui_playlist_draw_item(app
, i
);
356 /* update border items */
357 if(start
&& !(app
->playlist
.item
[start
- 1].type
& PLAYLIST_BLOCK_END
))
359 app
->playlist
.item
[start
- 1].type
= (playlist_item_type_t
)(PLAYLIST_BLOCK_END
360 | app
->playlist
.item
[start
- 1].type
);
361 ui_playlist_draw_item(app
, start
- 1);
363 if((stop
+ 1) < app
->playlist
.count
&& !(app
->playlist
.item
[stop
+ 1].type
& PLAYLIST_BLOCK_BEGIN
))
365 app
->playlist
.item
[stop
+ 1].type
= (playlist_item_type_t
)(PLAYLIST_BLOCK_BEGIN
366 | app
->playlist
.item
[stop
+ 1].type
);
367 ui_playlist_draw_item(app
, stop
+ 1);
371 g_warning("omnplay_playlist_block: range [%d %d] do OVERLAP player\n",
374 pthread_mutex_unlock(&app
->players
.lock
);
375 pthread_mutex_unlock(&app
->playlist
.lock
);
380 int playlist_get_first_selected_item_idx(instance_t
* app
)
383 int* list
= playlist_get_selected_items_idx(app
, &c
);
391 int playlist_get_block(instance_t
* app
, int idx
, int* pstart
, int* pstop
)
395 for(start
= idx
; start
>= 0; start
--)
396 if(app
->playlist
.item
[start
].type
& PLAYLIST_BLOCK_BEGIN
)
399 for(stop
= idx
; stop
< app
->playlist
.count
; stop
++)
400 if(app
->playlist
.item
[stop
].type
& PLAYLIST_BLOCK_END
)
403 g_warning("playlist_get_block: range %d -> %d\n", start
, stop
);
405 /* check block range */
406 if(start
>= 0 && stop
< app
->playlist
.count
)
410 return (stop
- start
+ 1);
416 player_t
*playlist_get_player_at_pos(instance_t
* app
, int pos
)
418 /* check player range */
419 if(app
->playlist
.item
[pos
].player
> -1 && app
->playlist
.item
[pos
].player
< app
->players
.count
)
420 return &app
->players
.item
[app
->playlist
.item
[pos
].player
];
425 void playlist_delete_items(instance_t
* app
, int* idxs
, int count
, int sel
)
429 pthread_mutex_lock(&app
->playlist
.lock
);
430 pthread_mutex_lock(&app
->players
.lock
);
432 for(j
= 0; j
< count
; j
++)
436 /* fix block types */
437 if( app
->playlist
.item
[idx
].type
!= PLAYLIST_ITEM_BLOCK_BODY
&&
438 app
->playlist
.item
[idx
].type
!= PLAYLIST_ITEM_LOOP_BODY
)
441 app
->playlist
.item
[idx
- 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
- 1].type
|
443 if(idx
+ 1 < app
->playlist
.count
)
444 app
->playlist
.item
[idx
+ 1].type
= (playlist_item_type_t
)(app
->playlist
.item
[idx
+ 1].type
|
445 PLAYLIST_BLOCK_BEGIN
);
448 /* shift playlist items */
451 &app
->playlist
.item
[idx
],
452 &app
->playlist
.item
[idx
+ 1],
453 (app
->playlist
.count
- idx
- 1) * sizeof(playlist_item_t
)
456 /* decrement items count */
457 app
->playlist
.count
--;
459 /* increment servers indexes */
460 for(i
= 0; i
< app
->players
.count
; i
++)
461 if(app
->players
.item
[i
].playlist_start
>= idx
)
462 app
->players
.item
[i
].playlist_start
--;
465 /* redraw playlist */
466 ui_playlist_draw(app
);
470 ui_playlist_select_item(app
, idxs
[0]);
472 pthread_mutex_unlock(&app
->players
.lock
);
473 pthread_mutex_unlock(&app
->playlist
.lock
);
476 void playlist_delete_selected_items(instance_t
* app
)
481 list1
= playlist_get_selected_items_idx(app
, &cnt1
);
484 list2
= (int*)malloc(sizeof(int) * cnt1
);
486 for(i
= 0, cnt2
= 0; i
< cnt1
; i
++)
488 /* check for playing block */
489 if(playlist_idx_cued(app
, list1
[i
], NULL
))
493 list2
[cnt2
++] = list1
[i
];
497 playlist_delete_items(app
, list2
, cnt2
, 1);
503 int playlist_insert_check(instance_t
* app
, int idx
, playlist_item_type_t
* t
)
505 *t
= PLAYLIST_ITEM_BLOCK_SINGLE
;
507 /* before or after playlist */
508 if(!idx
|| idx
== app
->playlist
.count
)
511 /* check for block borders */
512 if( app
->playlist
.item
[idx
- 1].type
& PLAYLIST_BLOCK_END
&&
513 app
->playlist
.item
[idx
+ 0].type
& PLAYLIST_BLOCK_BEGIN
)
516 /* check for playing block */
517 if(playlist_idx_cued(app
, idx
, NULL
))
520 if(app
->playlist
.item
[idx
].type
& PLAYLIST_BLOCK_LOOP
)
521 *t
= PLAYLIST_ITEM_LOOP_BODY
;
523 *t
= PLAYLIST_ITEM_BLOCK_BODY
;
528 void playlist_insert_items(instance_t
* app
, int idx
, playlist_item_t
* items
, int count
)
532 pthread_mutex_lock(&app
->playlist
.lock
);
533 pthread_mutex_lock(&app
->players
.lock
);
535 /* shift playlist items */
538 &app
->playlist
.item
[idx
+ count
],
539 &app
->playlist
.item
[idx
],
540 (app
->playlist
.count
- idx
) * sizeof(playlist_item_t
)
546 &app
->playlist
.item
[idx
],
548 count
* sizeof(playlist_item_t
)
551 /* increment servers indexes */
552 for(i
= 0; i
< app
->players
.count
; i
++)
553 if(app
->players
.item
[i
].playlist_start
>= idx
)
554 app
->players
.item
[i
].playlist_start
+= idx
;
556 /* increment items count */
557 app
->playlist
.count
+= count
;
559 /* redraw playlist */
560 ui_playlist_draw(app
);
563 ui_playlist_select_item(app
, idx
);
565 pthread_mutex_unlock(&app
->players
.lock
);
566 pthread_mutex_unlock(&app
->playlist
.lock
);
571 static int load_file_ply(omnplay_instance_t
* app
, char* filename
)
574 char *ID
, *CH
, *B
, *IN
, *OUT
, *DUR
, *REST
, *l
;
576 playlist_item_t
* items
;
578 /* allocate space for strings and items */
579 items
= malloc(sizeof(playlist_item_t
) * MAX_PLAYLIST_ITEMS
);
580 memset(items
, 0, sizeof(playlist_item_t
) * MAX_PLAYLIST_ITEMS
);
581 ID
= malloc(PATH_MAX
);
582 CH
= malloc(PATH_MAX
);
583 B
= malloc(PATH_MAX
);
584 IN
= malloc(PATH_MAX
);
585 OUT
= malloc(PATH_MAX
);
586 DUR
= malloc(PATH_MAX
);
587 REST
= malloc(PATH_MAX
);
588 l
= malloc(PATH_MAX
);
590 /* open and process file */
591 f
= fopen(filename
, "rt");
599 memset(l
, 0, PATH_MAX
);
600 fgets(l
, PATH_MAX
, f
);
602 /* remove newlines */
603 if( (s
= strchr(l
, '\n')) ) *s
= 0;
604 if( (s
= strchr(l
, '\r')) ) *s
= 0;
605 if( (s
= strchr(l
, '\t')) ) *s
= 0;
607 /* check for empty line */
608 if(l
[0] && l
[0] != '#')
610 if (6 != sscanf(l
, "%128[^,],%128[^,],%128[^,],%128[^,],%128[^,],%128[^,],%s",
611 ID
, CH
, B
, IN
, OUT
, DUR
, REST
))
615 tc2frames(IN
, 25.0, &items
[count
].in
);
616 tc2frames(DUR
, 25.0, &items
[count
].dur
);
617 strncpy(items
[count
].id
, ID
, PATH_MAX
);
618 items
[count
].player
= atol(CH
) - 1;
621 case 1: items
[count
].type
= PLAYLIST_ITEM_BLOCK_SINGLE
; break;
622 case 2: items
[count
].type
= PLAYLIST_ITEM_LOOP_BEGIN
; break;
623 case 3: items
[count
].type
= PLAYLIST_ITEM_LOOP_BODY
; break;
624 case 4: items
[count
].type
= PLAYLIST_ITEM_LOOP_END
; break;
625 case 6: items
[count
].type
= PLAYLIST_ITEM_BLOCK_END
; break;
628 items
[count
].type
= PLAYLIST_ITEM_BLOCK_BEGIN
;
629 else if(items
[count
- 1].type
== PLAYLIST_ITEM_BLOCK_BEGIN
||
630 items
[count
- 1].type
== PLAYLIST_ITEM_BLOCK_BODY
)
631 items
[count
].type
= PLAYLIST_ITEM_BLOCK_BODY
;
633 items
[count
].type
= PLAYLIST_ITEM_BLOCK_BEGIN
;
637 items
[count
].type
= b
- 1024;
642 switch(items
[count
].type
)
644 case PLAYLIST_ITEM_BLOCK_BEGIN
: n
= "BLOCK_BEGIN"; break;
645 case PLAYLIST_ITEM_BLOCK_BODY
: n
= "BLOCK_BODY"; break;
646 case PLAYLIST_ITEM_BLOCK_END
: n
= "BLOCK_END"; break;
647 case PLAYLIST_ITEM_BLOCK_SINGLE
: n
= "BLOCK_SINGLE"; break;
648 case PLAYLIST_ITEM_LOOP_BEGIN
: n
= "LOOP_BEGIN"; break;
649 case PLAYLIST_ITEM_LOOP_BODY
: n
= "LOOP_BODY"; break;
650 case PLAYLIST_ITEM_LOOP_END
: n
= "LOOP_END"; break;
651 case PLAYLIST_ITEM_LOOP_SINGLE
: n
= "LOOP_SINGLE"; break;
653 fprintf(stderr
, "src=[%s]\ndst=[idx=%d,block=%s,block_id=%d,in=%d,out=%d]\n",
654 l
, count
, n
, items
[count
].type
, items
[count
].in
, items
[count
].dur
);
666 /* add loaded items to playlist */
669 pthread_mutex_lock(&app
->playlist
.lock
);
670 for(i
= 0; i
< count
&& app
->playlist
.count
+ 1 < MAX_PLAYLIST_ITEMS
; i
++)
672 omnplay_library_normalize_item(app
, &items
[i
]);
673 app
->playlist
.item
[app
->playlist
.count
++] = items
[i
];
675 app
->playlist
.ver_curr
++;
676 pthread_mutex_unlock(&app
->playlist
.lock
);
692 void omnplay_playlist_load(omnplay_instance_t
* app
)
696 GtkFileFilter
*filter
;
698 dialog
= gtk_file_chooser_dialog_new("Open File",
699 GTK_WINDOW (app
->window
),
700 GTK_FILE_CHOOSER_ACTION_OPEN
,
701 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
702 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
705 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog
),
706 (app
->playlist
.path
)?app
->playlist
.path
:getenv("HOME"));
708 filter
= gtk_file_filter_new();
709 gtk_file_filter_set_name(filter
, "Playlist formatted (*.ply)");
710 gtk_file_filter_add_pattern(filter
, "*.ply");
711 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
712 filter
= gtk_file_filter_new();
713 gtk_file_filter_set_name(filter
, "All types (*.*)");
714 gtk_file_filter_add_pattern(filter
, "*.*");
715 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
717 r
= gtk_dialog_run(GTK_DIALOG(dialog
));
719 if(r
== GTK_RESPONSE_ACCEPT
)
723 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog
));
725 r
= load_file_ply(app
, filename
);
728 omnplay_playlist_draw(app
);
730 if(app
->playlist
.path
)
731 g_free(app
->playlist
.path
);
732 if((app
->playlist
.path
= filename
))
734 char* e
= strrchr(app
->playlist
.path
, '/');
739 gtk_widget_destroy (dialog
);
742 static int save_file_ply(omnplay_instance_t
* app
, char* filename
)
746 char tc1
[12], tc2
[12], tc3
[12];
747 char* fname
= filename
;
749 filename
= (char*)malloc(PATH_MAX
);
750 strncpy(filename
, fname
, PATH_MAX
);
751 i
= strlen(filename
);
752 if(i
< 4 || strcasecmp(filename
+ i
- 4, ".ply"))
753 strcat(filename
, ".ply");
755 if((f
= fopen(filename
, "wt")))
757 for(i
= 0; i
< app
->playlist
.count
; i
++)
758 fprintf(f
, "%s,%d,%d,%s,%s,%s,,,,,,,,\n",
759 app
->playlist
.item
[i
].id
,
760 app
->playlist
.item
[i
].player
+ 1,
761 app
->playlist
.item
[i
].type
+ 1024,
762 frames2tc(app
->playlist
.item
[i
].in
, 25.0, tc1
),
763 frames2tc(app
->playlist
.item
[i
].in
+ app
->playlist
.item
[i
].dur
, 25.0, tc2
),
764 frames2tc(app
->playlist
.item
[i
].dur
, 25.0, tc3
));
772 void omnplay_playlist_save(omnplay_instance_t
* app
)
776 GtkFileFilter
*filter
;
778 dialog
= gtk_file_chooser_dialog_new("Save File",
779 GTK_WINDOW (app
->window
),
780 GTK_FILE_CHOOSER_ACTION_SAVE
,
781 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
782 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
785 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog
), TRUE
);
787 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog
),
788 (app
->playlist
.path
)?app
->playlist
.path
:getenv("HOME"));
790 filter
= gtk_file_filter_new();
791 gtk_file_filter_set_name(filter
, "Playlist formatted (*.ply)");
792 gtk_file_filter_add_pattern(filter
, "*.ply");
793 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
794 g_object_set_data(G_OBJECT(filter
), "id", GINT_TO_POINTER(0));
795 filter
= gtk_file_filter_new();
796 gtk_file_filter_set_name(filter
, "Text (*.txt)");
797 gtk_file_filter_add_pattern(filter
, "*.*");
798 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog
), filter
);
799 g_object_set_data(G_OBJECT(filter
), "id", GINT_TO_POINTER(1));
801 r
= gtk_dialog_run(GTK_DIALOG(dialog
));
803 if(r
== GTK_RESPONSE_ACCEPT
)
807 filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog
));
809 r
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog
))), "id"));
811 r
= save_file_ply(app
, filename
);
813 if(app
->playlist
.path
)
814 g_free(app
->playlist
.path
);
815 if((app
->playlist
.path
= filename
))
817 char* e
= strrchr(app
->playlist
.path
, '/');
822 gtk_widget_destroy (dialog
);
826 void omnplay_playlist_draw(omnplay_instance_t
* app
)
830 char tc1
[12], tc2
[12];
831 GtkListStore
*list_store
;
834 sels
= omnplay_selected_idxs_playlist(app
);
836 list_store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app
->playlist_grid
)));
837 gtk_list_store_clear(list_store
);
839 pthread_mutex_lock(&app
->playlist
.lock
);
841 for(i
= 0;i
< app
->playlist
.count
; i
++)
845 if(PLAYLIST_BLOCK_BEGIN
& app
->playlist
.item
[i
].type
)
846 snprintf(ch
, sizeof(ch
), "%c", 'A' + app
->playlist
.item
[i
].player
);
850 gtk_list_store_append(list_store
, &iter
);
852 gtk_list_store_set(list_store
, &iter
,
854 1, app
->playlist
.block_icons
[app
->playlist
.item
[i
].type
],
856 3, app
->playlist
.item
[i
].id
,
857 4, frames2tc(app
->playlist
.item
[i
].in
, 25.0, tc1
),
858 5, frames2tc(app
->playlist
.item
[i
].dur
, 25.0, tc2
),
859 6, app
->playlist
.item
[i
].title
,
861 8, (app
->playlist
.item
[i
].error
!= 0),
862 9, (app
->playlist
.item
[i
].error
& PLAYLIST_ITEM_ERROR_LIB
)?
"red":"orange",
866 app
->playlist
.ver_prev
= app
->playlist
.ver_curr
;
873 path
= gtk_tree_path_new_from_indices(sels
[1], -1);
874 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app
->playlist_grid
)), path
);
875 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
);
876 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(app
->playlist_grid
), path
, NULL
, FALSE
, 0, 0);
877 gtk_tree_path_free(path
);
882 pthread_mutex_unlock(&app
->playlist
.lock
);
885 typedef struct omnplay_playlist_draw_item_desc
887 GtkListStore
*list_store
;
888 omnplay_instance_t
* app
;
890 } omnplay_playlist_draw_item_t
;
892 static gboolean
omnplay_playlist_draw_item_proc(
893 GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer user_data
)
896 char tc1
[12], tc2
[12];
898 omnplay_playlist_draw_item_t
* item
= (omnplay_playlist_draw_item_t
*)user_data
;
899 omnplay_instance_t
* app
= item
->app
;
901 gtk_tree_model_get(model
, iter
, 7, &i
, -1);
903 if(i
!= item
->idx
) return FALSE
;
905 if(PLAYLIST_BLOCK_BEGIN
& app
->playlist
.item
[i
].type
)
906 snprintf(ch
, sizeof(ch
), "%c", 'A' + app
->playlist
.item
[i
].player
);
910 gtk_list_store_set(item
->list_store
, iter
,
912 1, app
->playlist
.block_icons
[app
->playlist
.item
[i
].type
],
914 3, app
->playlist
.item
[i
].id
,
915 4, frames2tc(app
->playlist
.item
[i
].in
, 25.0, tc1
),
916 5, frames2tc(app
->playlist
.item
[i
].dur
, 25.0, tc2
),
917 6, app
->playlist
.item
[i
].title
,
919 8, (app
->playlist
.item
[i
].error
!= 0),
920 9, (app
->playlist
.item
[i
].error
& PLAYLIST_ITEM_ERROR_LIB
)?
"red":"orange",
926 void omnplay_playlist_draw_item(omnplay_instance_t
* app
, int idx
)
928 GtkListStore
*list_store
;
929 omnplay_playlist_draw_item_t item
;
931 list_store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app
->playlist_grid
)));
933 pthread_mutex_lock(&app
->playlist
.lock
);
937 item
.list_store
= list_store
;
938 gtk_tree_model_foreach(GTK_TREE_MODEL(list_store
), omnplay_playlist_draw_item_proc
, &item
);
940 pthread_mutex_unlock(&app
->playlist
.lock
);
943 static gboolean
omnplay_playlist_draw_item_rem_proc(
944 GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, gpointer user_data
)
947 void** args
= (void**)user_data
;
948 GtkListStore
*list_store
= (GtkListStore
*)args
[1];
949 int idx
= (int)args
[2];
950 char* rem
= (char*)args
[3];
952 gtk_tree_model_get(model
, iter
, 7, &i
, -1);
954 if(i
!= idx
) return FALSE
;
956 gtk_list_store_set(list_store
, iter
, 0, rem
, -1);
961 void omnplay_playlist_draw_item_rem(omnplay_instance_t
* app
, int idx
, char* rem
)
964 GtkListStore
*list_store
;
966 list_store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app
->playlist_grid
)));
968 item
[0] = (void*)app
;
969 item
[1] = (void*)list_store
;
970 item
[2] = (void*)idx
;
971 item
[3] = (void*)rem
;
973 gtk_tree_model_foreach(GTK_TREE_MODEL(list_store
), omnplay_playlist_draw_item_rem_proc
, item
);