b7c230ea162948c9d430124add7bee0f6860f773
[melted_gui] / src / ui.c
1 /*
2 * ui.c -- GTK+ 2 melted gui
3 * Copyright (C) 2012 Maksym Veremeyenko <verem@m1stereo.tv>
4 *
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.
9 *
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.
14 *
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.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #include <gdk/gdkkeysyms.h>
31 #include <gtk/gtk.h>
32
33 #include "ui.h"
34 #include "ui_utils.h"
35 #include "ui_buttons.h"
36 #include "support.h"
37 #include "timecode.h"
38 #include "playlist.h"
39
40 typedef struct column_desc
41 {
42 char* title;
43 GType type;
44 } column_desc_t;
45
46 static const column_desc_t playlist_columns[] =
47 {
48 {
49 "REM",
50 G_TYPE_STRING
51 },
52 {
53 "B",
54 G_TYPE_OBJECT
55 },
56 {
57 "CH",
58 G_TYPE_STRING
59 },
60 {
61 "ID",
62 G_TYPE_STRING
63 },
64 {
65 "IN",
66 G_TYPE_STRING
67 },
68 {
69 "DUR",
70 G_TYPE_STRING
71 },
72 {
73 "TITLE",
74 G_TYPE_STRING
75 },
76 {
77 NULL,
78 G_TYPE_STRING
79 }
80 };
81
82 const static column_desc_t library_columns[] =
83 {
84 {
85 "TYPE",
86 G_TYPE_OBJECT
87 },
88 {
89 "DUR",
90 G_TYPE_STRING
91 },
92 {
93 "NAME",
94 G_TYPE_STRING
95 },
96 {
97 NULL,
98 G_TYPE_STRING
99 }
100 };
101
102
103 static GtkWidget* create_label(GtkWidget* top, char* text, char* reg, GtkJustification jtype)
104 {
105 GtkWidget* label;
106
107 label = gtk_label_new ("");
108 gtk_widget_show (label);
109
110 if(jtype)
111 gtk_label_set_justify (GTK_LABEL (label), jtype);
112
113 if(reg)
114 GLADE_HOOKUP_OBJECT (top, label, reg);
115
116 if(text)
117 gtk_label_set_text(GTK_LABEL (label), text);
118
119 return label;
120 };
121
122 static GtkWidget* create_treeview_list(GtkWidget* top, char* name, const column_desc_t columns[])
123 {
124 int i, count;
125
126 GtkWidget *treeview;
127 GtkTreeSelection *selection;
128 GtkCellRenderer *renderer;
129 GtkTreeViewColumn *column;
130 GtkListStore *list_store;
131 GType list_store_types[32];
132
133 treeview = gtk_tree_view_new ();
134 gtk_widget_show (treeview);
135 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
136 gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(treeview), GTK_TREE_VIEW_GRID_LINES_BOTH);
137
138 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
139 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
140
141 for(i = 0, count = 0; columns[i].title; i++, count++)
142 list_store_types[i] = (columns[i].type == G_TYPE_OBJECT)?GDK_TYPE_PIXBUF:columns[i].type;
143 list_store_types[count] = G_TYPE_INT;
144 list_store_types[count + 1] = G_TYPE_BOOLEAN;
145 list_store_types[count + 2] = G_TYPE_STRING;
146
147 list_store = gtk_list_store_newv(count + 3, list_store_types);
148
149 gtk_tree_view_set_model( GTK_TREE_VIEW( treeview ), GTK_TREE_MODEL( list_store ) );
150
151 for(i = 0; columns[i].title; i++)
152 {
153 char* prop;
154 column = NULL;
155
156 if(columns[i].type == G_TYPE_OBJECT)
157 {
158 renderer = gtk_cell_renderer_pixbuf_new();
159 gtk_cell_renderer_set_padding(renderer, 0, 0);
160 prop = "pixbuf";
161 }
162 else if(columns[i].type == G_TYPE_BOOLEAN)
163 {
164 renderer = gtk_cell_renderer_toggle_new();
165 prop = "active";
166 }
167 else
168 {
169 renderer = gtk_cell_renderer_text_new();
170 prop = "text";
171
172 column = gtk_tree_view_column_new_with_attributes(
173 columns[i].title, renderer,
174 prop, i,
175 "background-set", count + 1,
176 "background", count + 2,
177 NULL);
178 }
179
180 if(!column)
181 column = gtk_tree_view_column_new_with_attributes(
182 columns[i].title, renderer,
183 prop, i,
184 NULL);
185
186 gtk_tree_view_append_column(GTK_TREE_VIEW( treeview ), column);
187 };
188
189 g_object_unref(list_store);
190
191 GLADE_HOOKUP_OBJECT (top, treeview, name);
192
193 return treeview;
194 };
195
196 static GtkWidget* create_treeview_tree(GtkWidget* top, char* name, const column_desc_t columns[])
197 {
198 int i, count;
199
200 GtkWidget *treeview;
201 GtkTreeSelection *selection;
202 GtkCellRenderer *renderer;
203 GtkTreeViewColumn *column;
204 GtkTreeStore *tree_store;
205 GType tree_store_types[32];
206
207 treeview = gtk_tree_view_new ();
208 gtk_widget_show (treeview);
209 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
210 gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(treeview), GTK_TREE_VIEW_GRID_LINES_BOTH);
211
212 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
213 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
214
215 for(i = 0, count = 0; columns[i].title; i++, count++)
216 tree_store_types[i] = (columns[i].type == G_TYPE_OBJECT)?GDK_TYPE_PIXBUF:columns[i].type;
217 tree_store_types[count + 0] = G_TYPE_POINTER;
218 tree_store_types[count + 1] = G_TYPE_POINTER;
219 tree_store_types[count + 2] = G_TYPE_BOOLEAN;
220 tree_store_types[count + 3] = G_TYPE_STRING;
221
222 tree_store = gtk_tree_store_newv(count + 4, tree_store_types);
223
224 gtk_tree_view_set_model( GTK_TREE_VIEW( treeview ), GTK_TREE_MODEL( tree_store ) );
225
226 for(i = 0; columns[i].title; i++)
227 {
228 char* prop;
229 column = NULL;
230
231 if(columns[i].type == G_TYPE_OBJECT)
232 {
233 renderer = gtk_cell_renderer_pixbuf_new();
234 gtk_cell_renderer_set_padding(renderer, 0, 0);
235 prop = "pixbuf";
236 }
237 else if(columns[i].type == G_TYPE_BOOLEAN)
238 {
239 renderer = gtk_cell_renderer_toggle_new();
240 prop = "active";
241 }
242 else
243 {
244 renderer = gtk_cell_renderer_text_new();
245 prop = "text";
246
247 column = gtk_tree_view_column_new_with_attributes(
248 columns[i].title, renderer,
249 prop, i,
250 "background-set", count + 2,
251 "background", count + 3,
252 NULL);
253 }
254
255 if(!column)
256 column = gtk_tree_view_column_new_with_attributes(
257 columns[i].title, renderer,
258 prop, i,
259 NULL);
260
261 gtk_tree_view_append_column(GTK_TREE_VIEW( treeview ), column);
262 };
263
264 g_object_unref(tree_store);
265
266 GLADE_HOOKUP_OBJECT (top, treeview, name);
267
268 return treeview;
269 };
270
271 static GtkWidget* pane_library_tree(GtkWidget* top, instance_t* app)
272 {
273 GtkWidget *scrolledwindow;
274
275 scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
276 gtk_widget_show (scrolledwindow);
277 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
278 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
279
280 gtk_container_add (GTK_CONTAINER (scrolledwindow),
281 app->library_tree = create_treeview_tree(top, "treeview_library", library_columns));
282
283 return scrolledwindow;
284 }
285
286 static GtkWidget* pane_library_buttons(GtkWidget* top, instance_t* app)
287 {
288 GtkWidget* hbox;
289
290 hbox = gtk_hbox_new (FALSE, 0);
291 gtk_widget_show (hbox);
292
293 /* playlist modify buttons */
294 gtk_box_pack_start (GTK_BOX (hbox),
295 ui_create_button(top, app, BUTTON_LIBRARY_ADD),
296 FALSE, FALSE, 0);
297 gtk_box_pack_start (GTK_BOX (hbox),
298 ui_create_button(top, app, BUTTON_LIBRARY_REFRESH),
299 FALSE, FALSE, 0);
300
301 /* spacer */
302 gtk_box_pack_start (GTK_BOX (hbox),
303 create_label(top, NULL, NULL, GTK_JUSTIFY_CENTER),
304 TRUE, TRUE, 0);
305
306 return hbox;
307 }
308
309 static GtkWidget* pane_library_search_buttons(GtkWidget* top, instance_t* app)
310 {
311 GtkWidget* hbox;
312
313 hbox = gtk_hbox_new (FALSE, 0);
314 gtk_widget_show (hbox);
315
316 /* text entry */
317 gtk_box_pack_start (GTK_BOX (hbox),
318 app->library.search = gtk_entry_new(),
319 TRUE, TRUE, 0);
320 gtk_widget_show(app->library.search);
321
322 /* playlist modify buttons */
323 gtk_box_pack_start (GTK_BOX (hbox),
324 ui_create_button(top, app, BUTTON_LIBRARY_FIND),
325 FALSE, FALSE, 0);
326 gtk_box_pack_start (GTK_BOX (hbox),
327 ui_create_button(top, app, BUTTON_LIBRARY_FIND_NEXT),
328 FALSE, FALSE, 0);
329
330 return hbox;
331 }
332
333 static GtkWidget* pane_library(GtkWidget* top, instance_t* app)
334 {
335 GtkWidget* vbox;
336
337 vbox = gtk_vbox_new (FALSE, 0);
338 gtk_widget_show (vbox);
339 gtk_widget_set_size_request(vbox, 300, -1);
340
341 /* add buttons box */
342 gtk_box_pack_start (GTK_BOX (vbox),
343 pane_library_buttons(top, app),
344 FALSE, FALSE, 0);
345
346 /* add grid */
347 gtk_box_pack_start (GTK_BOX (vbox),
348 pane_library_tree(top, app),
349 TRUE, TRUE, 0);
350
351 /* add search buttons */
352 gtk_box_pack_start (GTK_BOX (vbox),
353 pane_library_search_buttons(top, app),
354 FALSE, FALSE, 0);
355
356 return vbox;
357 }
358
359 static GtkWidget* create_channel_status(GtkWidget* top, instance_t* app, int idx)
360 {
361 GtkWidget* vbox;
362 GtkWidget* hbox;
363 GtkWidget* frame;
364 char name[PATH_MAX];
365 player_t* player;
366
367 player = &app->players.item[idx];
368
369 snprintf(name, sizeof(name), "unit %d [%c]", player->unit, idx + 'A');
370
371 frame = gtk_frame_new(name);
372 gtk_widget_show(frame);
373
374 vbox = gtk_vbox_new(FALSE, 0);
375 gtk_container_add(GTK_CONTAINER(frame), vbox);
376 gtk_widget_show(vbox);
377
378 /* status label */
379 gtk_box_pack_start(GTK_BOX (vbox),
380 player->label_status = create_label(top, "OFFLINE", NULL, GTK_JUSTIFY_LEFT),
381 FALSE, FALSE, 0);
382
383 /* spacel label */
384 gtk_box_pack_start(GTK_BOX (vbox),
385 create_label(top, " ", NULL, GTK_JUSTIFY_CENTER),
386 FALSE, FALSE, 0);
387
388 /* clip label */
389 gtk_box_pack_start (GTK_BOX (vbox),
390 player->label_clip = create_label(top, "U0002323", NULL, GTK_JUSTIFY_LEFT),
391 FALSE, FALSE, 0);
392
393 /* block state/current timecode */
394 gtk_box_pack_start(GTK_BOX (vbox),
395 hbox = gtk_hbox_new(TRUE, 0),
396 FALSE, FALSE, 0);
397 gtk_widget_show(hbox);
398
399 {
400 /* clip state */
401 gtk_box_pack_start(GTK_BOX (hbox),
402 player->label_state = create_label(top, "PLAYING", NULL, GTK_JUSTIFY_LEFT),
403 TRUE, TRUE, 0);
404
405 /* current timecode */
406 gtk_box_pack_start(GTK_BOX (hbox),
407 player->label_tc_cur = create_label(top, "00:00:00:00", NULL, GTK_JUSTIFY_LEFT),
408 TRUE, TRUE, 0);
409 };
410
411 /* block remain label/remain timecode */
412 gtk_box_pack_start(GTK_BOX (vbox),
413 hbox = gtk_hbox_new(TRUE, 0),
414 FALSE, FALSE, 0);
415 gtk_widget_show (hbox);
416
417 {
418 /* label */
419 gtk_box_pack_start(GTK_BOX (hbox),
420 create_label(top, "remain:", NULL, GTK_JUSTIFY_LEFT),
421 TRUE, TRUE, 0);
422
423 /* remaining timecode */
424 gtk_box_pack_start(GTK_BOX (hbox),
425 player->label_tc_rem = create_label(top, "00:00:00:00", NULL, GTK_JUSTIFY_LEFT),
426 TRUE, TRUE, 0);
427 };
428
429 return frame;
430 }
431
432 static GtkWidget* pane_operate_status(GtkWidget* top, instance_t* app)
433 {
434 int i;
435 GtkWidget* vbox;
436
437 vbox = gtk_vbox_new (FALSE, 0);
438 gtk_widget_show (vbox);
439 gtk_widget_set_size_request(vbox, 250, -1);
440
441 for(i = 0; i < app->players.count; i++)
442 {
443 gtk_box_pack_start (GTK_BOX (vbox),
444 create_channel_status(top, app, i),
445 FALSE, FALSE, 0);
446
447 /* spacer */
448 gtk_box_pack_start (GTK_BOX (vbox),
449 create_label(top, NULL, NULL, GTK_JUSTIFY_CENTER),
450 FALSE, FALSE, 0);
451 }
452
453 /* spacer */
454 gtk_box_pack_start (GTK_BOX (vbox),
455 create_label(top, NULL, NULL, GTK_JUSTIFY_CENTER),
456 TRUE, TRUE, 0);
457
458 return vbox;
459 }
460
461 static GtkWidget* pane_operate_buttons_playlist(GtkWidget* top, instance_t* app)
462 {
463 GtkWidget* hbox;
464
465 hbox = gtk_hbox_new (FALSE, 0);
466 gtk_widget_show (hbox);
467
468 /* playlist load/save buttons */
469 gtk_box_pack_start (GTK_BOX (hbox),
470 ui_create_button(top, app, BUTTON_PLAYLIST_LOAD),
471 FALSE, FALSE, 0);
472 gtk_box_pack_start (GTK_BOX (hbox),
473 ui_create_button(top, app, BUTTON_PLAYLIST_SAVE),
474 FALSE, FALSE, 0);
475
476 /* spacer */
477 gtk_box_pack_start (GTK_BOX (hbox),
478 create_label(top, " ", NULL, GTK_JUSTIFY_CENTER),
479 FALSE, FALSE, 0);
480
481 /* playlist modify buttons */
482 gtk_box_pack_start (GTK_BOX (hbox),
483 ui_create_button(top, app, BUTTON_PLAYLIST_ITEM_ADD),
484 FALSE, FALSE, 0);
485 gtk_box_pack_start (GTK_BOX (hbox),
486 ui_create_button(top, app, BUTTON_PLAYLIST_ITEM_EDIT),
487 FALSE, FALSE, 0);
488 gtk_box_pack_start (GTK_BOX (hbox),
489 ui_create_button(top, app, BUTTON_PLAYLIST_ITEM_DEL),
490 FALSE, FALSE, 0);
491
492 /* spacer */
493 gtk_box_pack_start (GTK_BOX (hbox),
494 create_label(top, " ", NULL, GTK_JUSTIFY_CENTER),
495 FALSE, FALSE, 0);
496
497 /* playlist block buttons */
498 gtk_box_pack_start (GTK_BOX (hbox),
499 ui_create_button(top, app, BUTTON_PLAYLIST_BLOCK_SINGLE),
500 FALSE, FALSE, 0);
501 gtk_box_pack_start (GTK_BOX (hbox),
502 ui_create_button(top, app, BUTTON_PLAYLIST_BLOCK_LOOP),
503 FALSE, FALSE, 0);
504
505 /* spacer */
506 gtk_box_pack_start (GTK_BOX (hbox),
507 create_label(top, " ", NULL, GTK_JUSTIFY_CENTER),
508 FALSE, FALSE, 0);
509
510 /* playlist move items buttons */
511 gtk_box_pack_start (GTK_BOX (hbox),
512 ui_create_button(top, app, BUTTON_PLAYLIST_ITEM_UP),
513 FALSE, FALSE, 0);
514 gtk_box_pack_start (GTK_BOX (hbox),
515 ui_create_button(top, app, BUTTON_PLAYLIST_ITEM_DOWN),
516 FALSE, FALSE, 0);
517
518 /* spacer */
519 gtk_box_pack_start (GTK_BOX (hbox),
520 create_label(top, " ", NULL, GTK_JUSTIFY_CENTER),
521 FALSE, FALSE, 0);
522
523 /* playlist relink */
524 gtk_box_pack_start (GTK_BOX (hbox),
525 ui_create_button(top, app, BUTTON_PLAYLIST_RELINK),
526 FALSE, FALSE, 0);
527
528 return hbox;
529 }
530
531 static GtkWidget* pane_operate_grid(GtkWidget* top, instance_t* app)
532 {
533 GtkWidget *scrolledwindow;
534
535 scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
536 gtk_widget_show (scrolledwindow);
537 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
538 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
539
540 gtk_container_add (GTK_CONTAINER (scrolledwindow),
541 app->playlist_grid = create_treeview_list(top, "treeview_playlist", playlist_columns));
542
543 return scrolledwindow;
544 }
545
546 static GtkWidget* pane_operate_buttons_operate(GtkWidget* top, instance_t* app)
547 {
548 GtkWidget* hbox;
549
550 hbox = gtk_hbox_new (FALSE, 0);
551 gtk_widget_show (hbox);
552
553 /* spacer */
554 gtk_box_pack_start (GTK_BOX (hbox),
555 create_label(top, NULL, NULL, GTK_JUSTIFY_CENTER),
556 TRUE, TRUE, 0);
557
558 /* playlist modify buttons */
559 gtk_box_pack_start (GTK_BOX (hbox),
560 ui_create_button(top, app, BUTTON_PLAYER_CUE),
561 FALSE, FALSE, 0);
562 gtk_box_pack_start (GTK_BOX (hbox),
563 ui_create_button(top, app, BUTTON_PLAYER_PLAY),
564 FALSE, FALSE, 0);
565 gtk_box_pack_start (GTK_BOX (hbox),
566 ui_create_button(top, app, BUTTON_PLAYER_PAUSE),
567 FALSE, FALSE, 0);
568 gtk_box_pack_start (GTK_BOX (hbox),
569 ui_create_button(top, app, BUTTON_PLAYER_STOP),
570 FALSE, FALSE, 0);
571
572 /* spacer */
573 gtk_box_pack_start (GTK_BOX (hbox),
574 create_label(top, NULL, NULL, GTK_JUSTIFY_CENTER),
575 TRUE, TRUE, 0);
576
577 return hbox;
578 }
579
580 static GtkWidget* pane_operate_operate(GtkWidget* top, instance_t* app)
581 {
582 GtkWidget* vbox;
583
584 vbox = gtk_vbox_new (FALSE, 0);
585 gtk_widget_show (vbox);
586
587 /* add buttons box #1 */
588 gtk_box_pack_start (GTK_BOX (vbox),
589 pane_operate_buttons_playlist(top, app),
590 FALSE, FALSE, 0);
591
592 /* add buttons box */
593 gtk_box_pack_start (GTK_BOX (vbox),
594 pane_operate_grid(top, app),
595 TRUE, TRUE, 0);
596
597 /* add buttons box #1 */
598 gtk_box_pack_start (GTK_BOX (vbox),
599 pane_operate_buttons_operate(top, app),
600 FALSE, FALSE, 0);
601
602 return vbox;
603
604 }
605
606 static GtkWidget* pane_operate(GtkWidget* top, instance_t* app)
607 {
608 GtkWidget* hbox;
609
610 hbox = gtk_hbox_new (FALSE, 0);
611 gtk_widget_show (hbox);
612
613 /* add buttons box */
614 gtk_box_pack_start (GTK_BOX (hbox),
615 pane_operate_status(top, app),
616 FALSE, FALSE, 0);
617
618 /* add buttons box */
619 gtk_box_pack_start (GTK_BOX (hbox),
620 pane_operate_operate(top, app),
621 TRUE, TRUE, 0);
622
623 return hbox;
624
625 };
626
627 static GtkWidget* pane_top(GtkWidget* top, instance_t* app)
628 {
629 GtkWidget* pane;
630
631 pane = gtk_hpaned_new ();
632 gtk_widget_show (pane);
633
634 gtk_paned_set_position (GTK_PANED (pane), 800);
635
636 gtk_paned_pack1 (GTK_PANED (pane),
637 pane_operate(top, app),
638 TRUE, FALSE);
639
640 gtk_paned_pack2 (GTK_PANED (pane),
641 pane_library(top, app),
642 FALSE, FALSE);
643
644 return pane;
645 }
646
647 GtkWidget* ui_create(instance_t* app)
648 {
649 GtkWidget *wnd;
650 GtkWidget* vbox;
651
652 wnd = gtk_window_new (GTK_WINDOW_TOPLEVEL);
653 GLADE_HOOKUP_OBJECT_NO_REF (wnd, wnd, PACKAGE "_window");
654
655 gtk_window_set_title (GTK_WINDOW (wnd), _(PRODUCT_NAME));
656 gtk_window_set_default_size (GTK_WINDOW (wnd), 1024, 768);
657
658 vbox = gtk_vbox_new(FALSE, 0);
659 gtk_widget_show(vbox);
660
661 gtk_container_add(GTK_CONTAINER(wnd), vbox);
662
663 gtk_box_pack_start (GTK_BOX (vbox),
664 pane_top(wnd, app),
665 TRUE, TRUE, 0);
666 gtk_box_pack_start (GTK_BOX (vbox),
667 app->status_label = create_label(wnd, "started", NULL, GTK_JUSTIFY_LEFT),
668 FALSE, FALSE, 0);
669
670 app->playlist.block_icons[PLAYLIST_ITEM_BLOCK_BEGIN] =
671 create_pixbuf("block_type_block_start_16x16.png");
672 app->playlist.block_icons[PLAYLIST_ITEM_BLOCK_BODY] =
673 create_pixbuf("block_type_block_middle_16x16.png");
674 app->playlist.block_icons[PLAYLIST_ITEM_BLOCK_END] =
675 create_pixbuf("block_type_block_end_16x16.png");
676 app->playlist.block_icons[PLAYLIST_ITEM_BLOCK_SINGLE] =
677 create_pixbuf("block_type_block_single_16x16.png");
678 app->playlist.block_icons[PLAYLIST_ITEM_LOOP_BEGIN] =
679 create_pixbuf("block_type_loop_start_16x16.png");
680 app->playlist.block_icons[PLAYLIST_ITEM_LOOP_BODY] =
681 create_pixbuf("block_type_loop_middle_16x16.png");
682 app->playlist.block_icons[PLAYLIST_ITEM_LOOP_END] =
683 create_pixbuf("block_type_loop_end_16x16.png");
684 app->playlist.block_icons[PLAYLIST_ITEM_LOOP_SINGLE] =
685 create_pixbuf("block_type_block_loop_16x16.png");
686
687 return wnd;
688 }
689
690 int ui_playlist_item_dialog(instance_t* app, playlist_item_t* item)
691 {
692 int r, c;
693 char tc[32];
694 GtkWidget *dlg;
695 gint response;
696 GtkWidget *box, *table;
697 GtkWidget *entry[4], *combo;
698
699 dlg = gtk_dialog_new_with_buttons(
700 "Playlist item",
701 GTK_WINDOW(app->window),
702 GTK_DIALOG_MODAL,
703 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
704 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
705 NULL);
706
707 box = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
708
709 table = gtk_table_new(5, 2, TRUE);
710 gtk_widget_show(table);
711 gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
712
713 gtk_table_attach(GTK_TABLE(table),
714 create_label(NULL, "ID:", NULL, 0),
715 0, 1, 0, 1,
716 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
717
718 gtk_table_attach(GTK_TABLE(table),
719 create_label(NULL, "IN:", NULL, GTK_JUSTIFY_RIGHT),
720 0, 1, 1, 2,
721 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
722
723 gtk_table_attach(GTK_TABLE(table),
724 create_label(NULL, "DUR:", NULL, GTK_JUSTIFY_RIGHT),
725 0, 1, 2, 3,
726 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
727
728 gtk_table_attach(GTK_TABLE(table),
729 create_label(NULL, "TITLE:", NULL, GTK_JUSTIFY_RIGHT),
730 0, 1, 3, 4,
731 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
732
733 gtk_table_attach(GTK_TABLE(table),
734 create_label(NULL, "CHANNEL:", NULL, GTK_JUSTIFY_RIGHT),
735 0, 1, 4, 5,
736 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
737
738
739 gtk_table_attach(GTK_TABLE(table),
740 entry[0] = gtk_entry_new_with_max_length(32),
741 1, 2, 0, 1,
742 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
743
744 gtk_table_attach(GTK_TABLE(table),
745 entry[1] = gtk_entry_new_with_max_length(12),
746 1, 2, 1, 2,
747 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
748
749 gtk_table_attach(GTK_TABLE(table),
750 entry[2] = gtk_entry_new_with_max_length(12),
751 1, 2, 2, 3,
752 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
753
754 gtk_table_attach(GTK_TABLE(table),
755 entry[3] = gtk_entry_new_with_max_length(128),
756 1, 2, 3, 4,
757 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
758
759 gtk_table_attach(GTK_TABLE(table),
760 combo = gtk_combo_box_new_text(),
761 1, 2, 4, 5,
762 GTK_FILL/* | GTK_SHRINK */, GTK_FILL | GTK_SHRINK, 5, 5);
763
764
765 /* setup data */
766 gtk_entry_set_text(GTK_ENTRY(entry[0]), item->id);
767 gtk_entry_set_text(GTK_ENTRY(entry[1]), frames2tc(item->in, 25.0, tc));
768 gtk_entry_set_text(GTK_ENTRY(entry[2]), frames2tc(item->dur, 25.0, tc));
769 gtk_entry_set_text(GTK_ENTRY(entry[3]), item->title);
770 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "A");
771 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "B");
772 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "C");
773 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "D");
774 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), item->player);
775
776 gtk_widget_show_all(dlg);
777
778 /* Run dialog */
779 for(c = 1; c;)
780 {
781 response = gtk_dialog_run(GTK_DIALOG(dlg));
782
783 if( GTK_RESPONSE_REJECT == response ||
784 GTK_RESPONSE_DELETE_EVENT == response ||
785 GTK_RESPONSE_CANCEL == response)
786 {
787 r = 0;
788 c = 0;
789 }
790 else
791 {
792 r = 1;
793
794 /* get item data back */
795 strncpy(item->id, gtk_entry_get_text(GTK_ENTRY(entry[0])), PATH_MAX);
796 tc2frames((char*)gtk_entry_get_text(GTK_ENTRY(entry[1])), 25.0, &item->in);
797 tc2frames((char*)gtk_entry_get_text(GTK_ENTRY(entry[2])), 25.0, &item->dur);
798 strncpy(item->title, gtk_entry_get_text(GTK_ENTRY(entry[3])), PATH_MAX);
799 item->player = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
800
801 /* check if all data entered correctly */
802 if(item->id[0])
803 c = 0;
804 };
805 };
806
807 gtk_widget_hide(dlg);
808 gtk_widget_destroy(dlg);
809
810 return r;
811 };
812
813 /********************************************************************************/
814
815 void ui_update_player(player_t* player, char *tc_cur, char *tc_rem, char *state, char *status, char *clip)
816 {
817 /* update status in status page */
818 gdk_threads_enter();
819 gtk_label_set_text(GTK_LABEL (player->label_tc_cur), tc_cur);
820 gtk_label_set_text(GTK_LABEL (player->label_tc_rem), tc_rem);
821 gtk_label_set_text(GTK_LABEL (player->label_state), state);
822 gtk_label_set_text(GTK_LABEL (player->label_status), status);
823 gtk_label_set_text(GTK_LABEL (player->label_clip), clip);
824 gdk_flush();
825 gdk_threads_leave();
826 };
827
828 static gboolean ui_playlist_draw_item_rem_proc(
829 GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
830 {
831 int i;
832 void** args = (void**)user_data;
833 GtkListStore *list_store = (GtkListStore *)args[1];
834 int idx = (int)args[2];
835 char* rem = (char*)args[3];
836
837 gtk_tree_model_get(model, iter, 7, &i, -1);
838
839 if(i != idx) return FALSE;
840
841 gtk_list_store_set(list_store, iter, 0, rem, -1);
842
843 return TRUE;
844 };
845
846 void ui_playlist_draw_item_rem(instance_t* app, int idx, char* rem)
847 {
848 void* item[4];
849 GtkListStore *list_store;
850
851 gdk_threads_enter();
852
853 list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app->playlist_grid)));
854
855 item[0] = (void*)app;
856 item[1] = (void*)list_store;
857 item[2] = (void*)idx;
858 item[3] = (void*)rem;
859
860 gtk_tree_model_foreach(GTK_TREE_MODEL(list_store), ui_playlist_draw_item_rem_proc, item);
861
862 gdk_flush();
863 gdk_threads_leave();
864 };
865
866 void ui_playlist_select_item(instance_t* app, int idx)
867 {
868 GtkTreePath* path;
869
870 path = gtk_tree_path_new_from_indices(idx, -1);
871
872 gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(app->playlist_grid)), path);
873 gtk_tree_view_set_cursor(GTK_TREE_VIEW(app->playlist_grid), path, NULL, FALSE);
874 gtk_tree_path_free(path);
875 };
876
877 void ui_playlist_draw(instance_t* app)
878 {
879 int i;
880 int sel;
881 char tc1[12], tc2[12];
882 GtkListStore *list_store;
883 GtkTreeIter iter;
884
885 sel = playlist_get_first_selected_item_idx(app);
886
887 list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app->playlist_grid)));
888 gtk_list_store_clear(list_store);
889
890 pthread_mutex_lock(&app->playlist.lock);
891
892 for(i = 0;i < app->playlist.count; i++)
893 {
894 char ch[3];
895
896 if(PLAYLIST_BLOCK_BEGIN & app->playlist.item[i].type)
897 snprintf(ch, sizeof(ch), "%c", 'A' + app->playlist.item[i].player);
898 else
899 ch[0] = 0;
900
901 gtk_list_store_append(list_store, &iter);
902
903 gtk_list_store_set(list_store, &iter,
904 0, "",
905 1, app->playlist.block_icons[app->playlist.item[i].type],
906 2, ch,
907 3, app->playlist.item[i].id,
908 4, frames2tc(app->playlist.item[i].in, 25.0, tc1),
909 5, frames2tc(app->playlist.item[i].dur, 25.0, tc2),
910 6, app->playlist.item[i].title,
911 7, i,
912 8, (app->playlist.item[i].error != 0),
913 9, (app->playlist.item[i].error & PLAYLIST_ITEM_ERROR_LIB)?"red":"orange",
914 -1 );
915 }
916
917 app->playlist.ver_prev = app->playlist.ver_curr;
918
919 if(sel >= 0)
920 ui_playlist_select_item(app, sel);
921
922 pthread_mutex_unlock(&app->playlist.lock);
923 };
924
925 typedef struct ui_playlist_draw_item_desc
926 {
927 GtkListStore *list_store;
928 instance_t* app;
929 int idx;
930 } ui_playlist_draw_item_t;
931
932 static gboolean ui_playlist_draw_item_iter
933 (
934 GtkTreeModel *model,
935 GtkTreePath *path,
936 GtkTreeIter *iter,
937 gpointer user_data
938 )
939 {
940 int i;
941 char tc1[12], tc2[12];
942 char ch[3];
943 ui_playlist_draw_item_t* item = (ui_playlist_draw_item_t*)user_data;
944 instance_t* app = item->app;
945
946 gtk_tree_model_get(model, iter, 7, &i, -1);
947
948 if(i != item->idx) return FALSE;
949
950 if(PLAYLIST_BLOCK_BEGIN & app->playlist.item[i].type)
951 snprintf(ch, sizeof(ch), "%c", 'A' + app->playlist.item[i].player);
952 else
953 ch[0] = 0;
954
955 gtk_list_store_set(item->list_store, iter,
956 0, "",
957 1, app->playlist.block_icons[app->playlist.item[i].type],
958 2, ch,
959 3, app->playlist.item[i].id,
960 4, frames2tc(app->playlist.item[i].in, 25.0, tc1),
961 5, frames2tc(app->playlist.item[i].dur, 25.0, tc2),
962 6, app->playlist.item[i].title,
963 7, i,
964 8, (app->playlist.item[i].error != 0),
965 9, (app->playlist.item[i].error & PLAYLIST_ITEM_ERROR_LIB)?"red":"orange",
966 -1 );
967
968 return TRUE;
969 };
970
971 void ui_playlist_draw_item(instance_t* app, int idx)
972 {
973 GtkListStore *list_store;
974 ui_playlist_draw_item_t item;
975
976 list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app->playlist_grid)));
977
978 pthread_mutex_lock(&app->playlist.lock);
979
980 item.idx = idx;
981 item.app = app;
982 item.list_store = list_store;
983 gtk_tree_model_foreach(GTK_TREE_MODEL(list_store), ui_playlist_draw_item_iter, &item);
984
985 pthread_mutex_unlock(&app->playlist.lock);
986 };