Import version 0.1 to GIT
[colorize.git] / gui / main.c
1 #include <gtk/gtk.h>
2 #include <gdk/gdkkeysyms.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6 #include "../src/mark.h"
7 #ifdef WITH_OPENCV
8 #include "../src/opticalflow.h"
9 #endif
10 #include "main.h"
11 #include "image.h"
12 #include "palette.h"
13 #include "timeline.h"
14 #include "colorize.h"
15 #include "brightcontrast.h"
16 #include "level.h"
17 #include "fill.h"
18 #ifdef WITH_OPENCV
19 #include "flow.h"
20 #endif
21
22 #define CC_APP_TITLE "Colorize GTK"
23 GtkWidget *main_window;
24 GtkWidget *img_drawing_area = NULL;
25 GtkWidget *timeline_drawing_area;
26 GtkWidget *timeline_scroll;
27 GtkWidget *palette_treeview = NULL;
28 GtkLabel *img_label;
29 GtkToggleButton *show_highlighted_button, *show_preview_button, *show_colorized_button;
30 #ifdef WITH_OPENCV
31 GtkToggleButton *show_flow_button;
32 #endif
33 int button_down = 0, button_down_x = -1000, button_down_y = -1000, shift_pressed = 0, button_num = 1;
34 int brush_size;
35 int highlight = 0, preview = 0, rendered = 0, move_mode = 0, fill_mode = 0, flowview = 0;
36 int mouse_over_palette_area = 0, mouse_over_drawing_area = 0, mouse_over_timeline_area = 0;
37 #define min(x,y) ((x < y) ? x : y)
38 #define abs(x,y) ((x < y) ? y - x : x - y)
39
40 /* the labels are used to identify menu and button items */
41 enum toggle_label {
42         TOGGLE_LABEL_NONE = 0,
43         TOGGLE_LABEL_HIGHLIGHT,
44         TOGGLE_LABEL_PREVIEW,
45         TOGGLE_LABEL_RENDERED,
46         TOGGLE_LABEL_FLOWVIEW,
47         TOGGLE_LABEL_ZOOMFIELDS,
48 };
49
50 static void set_button_toggel_by_label(enum toggle_label label, gboolean active);
51
52 /* error requester */
53 void printerror(const char *fmt, ...)
54 {
55         char buffer[4096];
56         va_list args;
57
58         va_start(args,fmt);
59         vsprintf(buffer,fmt,args);
60         buffer[sizeof(buffer)-1]=0;
61         va_end(args);
62
63         GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
64                 GTK_DIALOG_DESTROY_WITH_PARENT,
65                 GTK_MESSAGE_ERROR,
66                 GTK_BUTTONS_CLOSE,
67                 "%s", buffer);
68         gtk_dialog_run (GTK_DIALOG (dialog));
69         gtk_widget_destroy (dialog);
70 }
71
72 static int already_destroyed = 0;
73
74 /* exit program and save current mask / palette */
75 void main_destroy(void)
76 {
77         if (anything_modified) {
78                 int ret;
79                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
80                         GTK_DIALOG_DESTROY_WITH_PARENT,
81                         GTK_MESSAGE_ERROR,
82                         GTK_BUTTONS_OK_CANCEL,
83                         "Image has been changed, really quit?");
84                 ret = gtk_dialog_run(GTK_DIALOG (dialog));
85                 gtk_widget_destroy(dialog);
86                 if (ret != GTK_RESPONSE_OK)
87                         return;
88         }
89         already_destroyed = 1;
90         gtk_main_quit();
91 }
92
93
94 static void destroy(GtkWidget *widget, gpointer data)
95 {
96         if (!already_destroyed)
97                 main_destroy();
98 }
99
100 /*
101  * keypress
102  */
103
104 static void undo_event(gpointer priv);
105 static void redo_event(gpointer priv);
106 static void copy_event(gpointer priv);
107 static void paste_event(gpointer priv);
108
109 /* event handler for main window keys */
110 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
111 {
112         int frame;
113
114 //      if (mouse_over_palette_area)
115         if (!mouse_over_drawing_area && !mouse_over_timeline_area)
116                 return FALSE;
117
118         switch (event->keyval) {
119         case GDK_q:
120         case GDK_w:
121                 if (event->state & GDK_CONTROL_MASK) {
122                         main_destroy();
123                         return TRUE;
124                 }
125                 break;
126         case GDK_Right:
127                 frame = timeline_selected + 1;
128                 if (event->state & GDK_SHIFT_MASK) {
129                         while(frame < timeline_frames && frame_list[frame].marked == 0 && frame_list[frame].keyframe == 0)
130                                 frame++;
131                 }
132                 if (frame < timeline_frames)
133                         timeline_select_and_save(timeline_selected, frame);
134                 return TRUE;
135         case GDK_Left:
136                 frame = timeline_selected - 1;
137                 if (event->state & GDK_SHIFT_MASK) {
138                         while(frame >= 0 && frame_list[frame].marked == 0 && frame_list[frame].keyframe == 0)
139                                 frame--;
140                 }
141                 if (frame >= 0)
142                         timeline_select_and_save(timeline_selected, frame);
143                 return TRUE;
144         case GDK_Home:
145                 frame = 0;
146                 timeline_select_and_save(timeline_selected, frame);
147                 return TRUE;
148         case GDK_End:
149                 frame = timeline_frames - 1;
150                 timeline_select_and_save(timeline_selected, frame);
151                 return TRUE;
152         case GDK_u:
153         case GDK_z:
154                 undo_event(NULL);
155                 return TRUE;
156         case GDK_r:
157                 redo_event(NULL);
158                 return TRUE;
159         case GDK_c:
160                 if (event->state & GDK_CONTROL_MASK) {
161                         copy_event(NULL);
162                         return TRUE;
163                 }
164                 break;
165         case GDK_v:
166                 if (event->state & GDK_CONTROL_MASK) {
167                         paste_event(NULL);
168                         return TRUE;
169                 }
170                 break;
171         case GDK_k:
172                 toggle_keyframe();
173                 return TRUE;
174         case GDK_Shift_L:
175         case GDK_Shift_R:
176                 shift_pressed = 1;
177                 break;
178 //      default:
179 //              printf("press %x\n", event->keyval);
180         }
181
182         return FALSE;
183 }
184
185 /* event handler for main window keys */
186 static gboolean on_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
187 {
188         switch (event->keyval) {
189         case GDK_Shift_L:
190         case GDK_Shift_R:
191                 shift_pressed = 0;
192                 break;
193 //      default:
194 //              printf("release %x\n", event->keyval);
195         }
196
197         return FALSE;
198 }
199
200 /*
201  * image area
202  */
203
204 /* events if mouse is over palette area */
205 static gboolean enter_palette_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
206 {
207         mouse_over_palette_area = 1;
208         return FALSE;
209 }
210 static gboolean leave_palette_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
211 {
212         mouse_over_palette_area = 0;
213         return FALSE;
214 }
215
216 /* events if mouse is over image area */
217 static gboolean enter_drawing_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
218 {
219         mouse_over_drawing_area = 1;
220         return FALSE;
221 }
222 static gboolean leave_drawing_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
223 {
224         mouse_over_drawing_area = 0;
225         return FALSE;
226 }
227
228 /* events if mouse is over timeline area */
229 static gboolean enter_timeline_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
230 {
231         mouse_over_timeline_area = 1;
232         return FALSE;
233 }
234 static gboolean leave_timeline_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
235 {
236         mouse_over_timeline_area = 0;
237         timeline_point(-1, -1);
238         return FALSE;
239 }
240
241 /* ugly non-bresenham.... */
242 static void draw_line(int x, int y, int paint)
243 {
244         double step_x = 0, step_y = 0;
245
246         if (abs(x,button_down_x) > abs(y,button_down_y)) {
247                 while(42) {
248                         if (button_down_x < x) {
249                                 step_x++;
250                                 step_y += (double)(button_down_y - y) / (double)(button_down_x - x);
251                         } else {
252                                 step_x--;
253                                 step_y -= (double)(button_down_y - y) / (double)(button_down_x - x);
254                         }
255                         paint_brush(button_down_x+step_x, button_down_y+step_y, brush_size, paint);
256                         draw_image(button_down_x+step_x-(brush_size*img_scale_x/16)+1, button_down_y+step_y-(brush_size*img_scale_y/16)+1, brush_size*2*img_scale_x/16, brush_size*2*img_scale_y/16);
257                         if (x == button_down_x+step_x)
258                                 break;
259                 }
260         } else {
261                 while(42) {
262                         if (y == button_down_y) /* no move at all */
263                                 break;
264                         if (button_down_y < y) {
265                                 step_y++;
266                                 step_x += (double)(button_down_x - x) / (double)(button_down_y - y);
267                         } else {
268                                 step_y--;
269                                 step_x -= (double)(button_down_x - x) / (double)(button_down_y - y);
270                         }
271                         paint_brush(button_down_x+step_x, button_down_y+step_y, brush_size, paint);
272                         draw_image(button_down_x+step_x-(brush_size*img_scale_x/16)+1, button_down_y+(step_y-brush_size*img_scale_y/16)+1, brush_size*2*img_scale_x/16, brush_size*2*img_scale_y/16);
273                         if (y == button_down_y+step_y)
274                                 break;
275                 }
276         }
277         paint_brush(x, y, brush_size, paint);
278         draw_image(x-(brush_size*img_scale_x/16)+1, y-(brush_size*img_scale_y/16)+1, brush_size*2*img_scale_x/16, brush_size*2*img_scale_y/16);
279         button_down_x = x;
280         button_down_y = y;
281 }
282
283 /* notify movement of mouse inside image area */
284 static gint motion_notify_event( GtkWidget *widget,
285                                  GdkEventMotion *event )
286 {
287         int x, y;
288         GdkModifierType state;
289
290         if (event->is_hint)
291                 gdk_window_get_pointer (event->window, &x, &y, &state);
292         else
293         {
294                 x = event->x;
295                 y = event->y;
296                 state = event->state;
297         }
298
299         if ((state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))) {
300                 if (button_down) {
301                         if (move_mode) {
302                                 move_mark((x-button_down_x)*16/img_scale_x, (y-button_down_y)*16/img_scale_y);
303                                 draw_image(0, 0, -1, -1);
304                         } else {
305                                 draw_line(x, y, button_num == 1);
306                         }
307                 }
308         } else {
309                 button_down = 0;
310         }
311                                                                                    
312         return TRUE;
313 }
314
315 /* button press event inside image area */
316 static gint button_press_event (GtkWidget *widget, GdkEventButton *event)
317 {
318         int x,y;
319
320         x = event->x;
321         y = event->y;
322         button_num = event->button;
323
324         if (!button_down)
325                 copy_mark_to_undo();
326         if (fill_mode) {
327                 fill(x, y, event->button != 1);
328                 draw_image(0, 0, -1, -1);
329         } else
330         if (move_mode) {
331                 if (button_down)
332                         return TRUE;
333                 button_down_x = x;
334                 button_down_y = y;
335         } else {
336                 /* if not shift, draw a dot and not a line */
337                 if (!shift_pressed || button_down_x == -1000) {
338                         button_down_x = x;
339                         button_down_y = y;
340                 }
341                 draw_line(x, y, button_num == 1);
342         }
343         button_down = 1;
344         return TRUE;
345 }
346
347 /* redraw event of image area */
348 static gint img_expose_event (GtkWidget *widget, GdkEventExpose *event)
349 {
350         draw_image(event->area.x, event->area.y, event->area.width, event->area.height);
351
352         return FALSE;
353 }
354
355 /*
356  * timeline
357  */
358
359 /* mouse move event inside timeline */
360 static gint timeline_motion_notify_event( GtkWidget *widget,
361                                  GdkEventMotion *event )
362 {
363         int x, y;
364         GdkModifierType state;
365
366         if (event->is_hint)
367                 gdk_window_get_pointer (event->window, &x, &y, &state);
368         else
369         {
370                 x = event->x;
371                 y = event->y;
372                 state = event->state;
373         }
374
375         timeline_point(x, y);
376
377         if ((state & GDK_BUTTON1_MASK)) {
378                 timeline_clicked(x, y);
379
380         }
381                                                                                    
382         return TRUE;
383 }
384
385 /* button press event inside timeline area */
386 static gint timeline_press_event (GtkWidget *widget, GdkEventButton *event)
387 {
388         int x,y;
389
390         x = event->x;
391         y = event->y;
392         timeline_clicked(x, y);
393
394         return TRUE;
395 }
396
397 /* redraw event of timeline area */
398 static gint timeline_expose_event (GtkWidget *widget, GdkEventExpose *event)
399 {
400         draw_timeline(event->area.x, event->area.y, event->area.width, event->area.height);
401
402         return FALSE;
403 }
404
405 /*
406  * colorselection
407  */
408
409 /* color selection's buttons have been pressed */
410 GtkWidget *colorseldlg = NULL;
411 GtkColorSelection *colorsel;
412 static void color_response(GtkDialog *dialog, gint response_id, gpointer user_data)
413 {
414         if (response_id == GTK_RESPONSE_CANCEL) {
415                 gtk_widget_destroy(colorseldlg);
416                 colorseldlg = NULL;
417         }
418         if (response_id == GTK_RESPONSE_OK) {
419                 GdkColor ncolor;
420
421                 anything_modified = 1;
422
423                 gtk_color_selection_get_current_color(colorsel, &ncolor);
424                 gtk_color_selection_set_previous_color(colorsel, &ncolor);
425                 mark_palette[mark_selected].r = ncolor.red / 256;
426                 mark_palette[mark_selected].g = ncolor.green / 256;
427                 mark_palette[mark_selected].b = ncolor.blue / 256;
428                 update_color(mark_selected);
429                 draw_image(0, 0, -1, -1);
430         }
431 }
432
433 /*
434  * menus
435  */
436
437 static void open_event(gpointer priv)
438 {
439         GtkWidget *dialog;
440         char *filename = NULL;
441         
442         dialog = gtk_file_chooser_dialog_new("Select first grey image",
443                 GTK_WINDOW(main_window),
444                 GTK_FILE_CHOOSER_ACTION_OPEN,
445                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
446                 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
447                 NULL);
448
449         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
450                 filename = strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)));
451         }
452
453         gtk_widget_destroy(dialog);
454
455         if (filename) {
456                 timeline_select_and_save(timeline_selected, timeline_selected);
457                 
458                 create_timeline(filename);
459                 if (frame_list)
460                         create_image(frame_list[timeline_selected].filename);
461                 free(filename);
462         }
463
464 }
465
466 static void save_event(gpointer priv)
467 {
468         timeline_select_and_save(timeline_selected, timeline_selected);
469 }
470
471 static void exit_event(gpointer priv)
472 {
473         main_destroy();
474 }
475
476 static void color_changed(GtkWidget *widget, GtkColorSelection *colorsel)
477 {
478 }
479
480 static void undo_event(gpointer priv)
481 {
482         copy_undo_to_mark(0);
483         draw_image(0, 0, -1, -1);
484 }
485
486 static void redo_event(gpointer priv)
487 {
488         copy_undo_to_mark(1);
489         draw_image(0, 0, -1, -1);
490 }
491
492 static void copy_event(gpointer priv)
493 {
494         copy_color(mark_selected + 1);
495 }
496
497 static void copy_all_event(gpointer priv)
498 {
499         copy_color(0);
500 }
501
502 static void paste_event(gpointer priv)
503 {
504         copy_mark_to_undo();
505         paste_color();
506         draw_image(0, 0, -1, -1);
507 }
508
509 static void color_destroy(GtkWidget *widget, gpointer data)
510 {
511         colorseldlg = NULL;
512 }
513
514 static void palette_event(gpointer priv)
515 {
516         GdkColor color;
517
518         if (colorseldlg) {
519                 gtk_widget_destroy(colorseldlg);
520                 colorseldlg = NULL;
521                 return;
522         }
523
524         color.red = mark_palette[mark_selected].r * 256 + 128;
525         color.green = mark_palette[mark_selected].g * 256 + 128;
526         color.blue = mark_palette[mark_selected].b * 256 + 128;
527
528         colorseldlg = gtk_color_selection_dialog_new("Select Color");
529         colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (colorseldlg)->colorsel);
530         gtk_color_selection_set_previous_color (colorsel, &color);
531         gtk_color_selection_set_current_color (colorsel, &color);
532         g_signal_connect(G_OBJECT(colorsel), "color_changed", G_CALLBACK(color_changed), (gpointer)colorsel);
533         g_signal_connect(G_OBJECT(colorseldlg), "response", G_CALLBACK(color_response), NULL);
534         g_signal_connect(G_OBJECT(colorseldlg), "destroy", G_CALLBACK(color_destroy), NULL);
535
536
537         gtk_widget_show(colorseldlg);
538 }
539
540 static void keyframe_event(gpointer priv)
541 {
542         toggle_keyframe();
543 }
544
545 static void erase_event(gpointer priv)
546 {
547         copy_mark_to_undo();
548         erase_mark(0);
549         draw_image(0, 0, -1, -1);
550 }
551
552 static void erase_color_event(gpointer priv)
553 {
554         copy_mark_to_undo();
555         erase_mark(mark_selected + 1);
556         draw_image(0, 0, -1, -1);
557 }
558
559 static void zoom_in_event(gpointer priv)
560 {
561         if (img_scale_x < 64) {
562                 int aspect = img_scale_y / img_scale_x;
563                 img_scale_x += 4;
564                 img_scale_y = img_scale_x * aspect;
565                 create_or_reset_pixbuf();
566         }
567 }
568
569 static void zoom_out_event(gpointer priv)
570 {
571         if (img_scale_x > 4) {
572                 int aspect = img_scale_y / img_scale_x;
573                 img_scale_x -= 4;
574                 img_scale_y = img_scale_x * aspect;
575                 create_or_reset_pixbuf();
576         }
577 }
578
579 static void zoom_100_event(gpointer priv)
580 {
581         img_scale_x = 16;
582         img_scale_y = 16;
583         create_or_reset_pixbuf();
584 }
585
586 static void zoom_field_event(gpointer priv)
587 {
588         if (gtk_check_menu_item_get_active((GtkCheckMenuItem *)priv))
589                 img_scale_y = img_scale_x*2;
590         else
591                 img_scale_y = img_scale_x;
592         create_or_reset_pixbuf();
593 }
594
595 static void show_highlighted_event(gpointer priv)
596 {
597         highlight = gtk_check_menu_item_get_active((GtkCheckMenuItem *)priv);
598         set_button_toggel_by_label(TOGGLE_LABEL_HIGHLIGHT, highlight);
599 }
600
601 static void show_preview_event(gpointer priv)
602 {
603         preview = gtk_check_menu_item_get_active((GtkCheckMenuItem *)priv);
604         set_button_toggel_by_label(TOGGLE_LABEL_PREVIEW, preview);
605 }
606
607 static void colorize_event(gpointer priv)
608 {
609         if (rendered) {
610                 printerror("Disable colorized view first.");
611                 return;
612         }
613 #ifdef WITH_OPENCV
614         if (flowview) {
615                 printerror("Disable flow view first.");
616                 return;
617         }
618 #endif
619         if (img_mark_buffer)
620                 colorize_image();
621 }
622
623 static void show_colorized_event(gpointer priv)
624 {
625         if (timeline_frames > 1)
626                 rendered = gtk_check_menu_item_get_active((GtkCheckMenuItem *)priv);
627         else
628                 rendered = 0;
629         gtk_check_menu_item_set_active((GtkCheckMenuItem *)priv, rendered);
630         set_button_toggel_by_label(TOGGLE_LABEL_RENDERED, rendered);
631 }
632
633 #ifdef WITH_OPENCV
634 static void show_flow_event(gpointer priv)
635 {
636         if (flow_enable && timeline_frames > 1)
637                 flowview = gtk_check_menu_item_get_active((GtkCheckMenuItem *)priv);
638         else
639                 flowview = 0;
640         gtk_check_menu_item_set_active((GtkCheckMenuItem *)priv, flowview);
641         set_button_toggel_by_label(TOGGLE_LABEL_FLOWVIEW, flowview);
642 }
643 #endif
644
645 static void dummy_event(gpointer priv)
646 {
647 }
648
649 struct my_menu_item {
650         enum toggle_label label;
651         GtkWidget *widget;
652         const char *text;
653         void (*handler)(gpointer priv);
654         gchar *stock;
655 };
656
657 struct my_menu {
658         const char *text;
659         struct my_menu_item *items;
660 };
661
662 struct my_menu_item file_menu_items[] = {
663         { TOGGLE_LABEL_NONE, NULL, "Open", open_event, GTK_STOCK_OPEN },
664         { TOGGLE_LABEL_NONE, NULL, "Save", save_event, GTK_STOCK_SAVE },
665         { TOGGLE_LABEL_NONE, NULL, "", dummy_event, NULL },
666         { TOGGLE_LABEL_NONE, NULL, "Exit", exit_event, GTK_STOCK_QUIT },
667         { TOGGLE_LABEL_NONE, NULL, NULL, NULL }
668 };
669
670 struct my_menu_item edit_menu_items[] = {
671         { TOGGLE_LABEL_NONE, NULL, "Undo", undo_event, GTK_STOCK_UNDO },
672         { TOGGLE_LABEL_NONE, NULL, "Redo", redo_event, GTK_STOCK_REDO },
673         { TOGGLE_LABEL_NONE, NULL, "", dummy_event, NULL },
674         { TOGGLE_LABEL_NONE, NULL, "Copy", copy_event, GTK_STOCK_COPY },
675         { TOGGLE_LABEL_NONE, NULL, "Copy All", copy_all_event, NULL },
676         { TOGGLE_LABEL_NONE, NULL, "Paste", paste_event, GTK_STOCK_PASTE },
677         { TOGGLE_LABEL_NONE, NULL, "", dummy_event, NULL },
678         { TOGGLE_LABEL_NONE, NULL, "Palette", palette_event, NULL },
679         { TOGGLE_LABEL_NONE, NULL, "Bright/Contrast", bc_event, NULL },
680         { TOGGLE_LABEL_NONE, NULL, "Adjust Levels", level_event, NULL },
681 #ifdef WITH_OPENCV
682         { TOGGLE_LABEL_NONE, NULL, "Optical Flow", flow_event, NULL },
683 #endif
684         { TOGGLE_LABEL_NONE, NULL, "", dummy_event, NULL },
685         { TOGGLE_LABEL_NONE, NULL, "Keyframe", keyframe_event, NULL },
686         { TOGGLE_LABEL_NONE, NULL, "", dummy_event, NULL },
687         { TOGGLE_LABEL_NONE, NULL, "Clear", erase_event, GTK_STOCK_CLEAR },
688         { TOGGLE_LABEL_NONE, NULL, "Clear Color", erase_color_event, NULL },
689         { TOGGLE_LABEL_NONE, NULL, NULL, NULL }
690 };
691
692 struct my_menu_item view_menu_items[] = {
693         { TOGGLE_LABEL_NONE, NULL, "Zoom In", zoom_in_event, GTK_STOCK_ZOOM_IN },
694         { TOGGLE_LABEL_NONE, NULL, "Zoom Out", zoom_out_event, GTK_STOCK_ZOOM_OUT },
695         { TOGGLE_LABEL_NONE, NULL, "Zoom 100", zoom_100_event, GTK_STOCK_ZOOM_100 },
696         { TOGGLE_LABEL_ZOOMFIELDS, NULL, "Zoom Field", zoom_field_event, NULL },
697         { TOGGLE_LABEL_NONE, NULL, "", dummy_event, NULL },
698         { TOGGLE_LABEL_HIGHLIGHT, NULL, "Highlight color", show_highlighted_event, NULL },
699         { TOGGLE_LABEL_PREVIEW, NULL, "Preview color", show_preview_event, NULL },
700         { TOGGLE_LABEL_RENDERED, NULL, "Show colorized", show_colorized_event, NULL },
701 #ifdef WITH_OPENCV
702         { TOGGLE_LABEL_FLOWVIEW, NULL, "Show flow", show_flow_event, NULL },
703 #endif
704         { TOGGLE_LABEL_NONE, NULL, NULL, NULL }
705 };
706
707 struct my_menu_item render_menu_items[] = {
708         { TOGGLE_LABEL_NONE, NULL, "Colorize Image", colorize_event, NULL },
709         { TOGGLE_LABEL_NONE, NULL, NULL, NULL }
710 };
711
712 struct my_menu menus[] = {
713         { "_File", file_menu_items },
714         { "_Edit", edit_menu_items },
715         { "_View", view_menu_items },
716         { "_Render", render_menu_items },
717         { NULL, NULL }
718 };
719
720 /* create menu bar */
721 static void create_menus(GtkWidget *menu_bar)
722 {
723         GtkWidget *root_menu;
724         GtkWidget *menu;
725         GtkWidget *menu_item;
726         struct my_menu_item *items;
727         int i, j;
728
729         /* create vbox and add menu_bar */
730         for (i = 0; menus[i].text; i++) {
731                 /* create menu with items */
732                 items = menus[i].items;
733                 menu = gtk_menu_new();
734                 for (j = 0; items[j].text; j++) {
735                         if (!items[j].text[0])
736                                 menu_item = gtk_separator_menu_item_new();
737                         else if (items[j].stock)
738                                 menu_item = gtk_image_menu_item_new_from_stock(items[j].stock, NULL);
739                         else if (items[j].label != TOGGLE_LABEL_NONE)
740                                 menu_item = gtk_check_menu_item_new_with_label(items[j].text);
741                         else
742                                 menu_item = gtk_menu_item_new_with_label(items[j].text);
743                         items[j].widget = menu_item;
744                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
745                         g_signal_connect_swapped(menu_item, "activate", G_CALLBACK(items[j].handler), menu_item);
746                         gtk_widget_show(menu_item);
747                 }
748                 /* create root menu and add to menu_bar */
749                 root_menu = gtk_menu_item_new_with_mnemonic(menus[i].text);
750                 gtk_widget_show(root_menu);
751                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(root_menu), menu);
752                 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), root_menu);
753         }
754
755 }
756
757 static void set_menu_toggel_by_label(enum toggle_label label, gboolean active)
758 {
759         struct my_menu_item *items;
760         int i, j;
761
762         for (i = 0; menus[i].text; i++) {
763                 items = menus[i].items;
764                 for (j = 0; items[j].text; j++) {
765                         if (items[j].label == label)
766                                 gtk_check_menu_item_set_active((GtkCheckMenuItem *)items[j].widget, active);
767                 }
768         }
769 }
770
771 /*
772  * palette
773  */
774
775 /* palette entry has been clicked */
776 void palette_change(GtkTreeSelection *selection, gpointer data)
777 {
778         GtkTreeModel     *model;
779         GtkTreeIter       iter;
780
781         if (gtk_tree_selection_get_selected(selection, &model, &iter))
782         {
783                 gchar *name;
784
785                 gtk_tree_model_get (model, &iter, 0/*column*/, &name, -1);
786                 mark_selected = atoi(name) - 1;
787                 g_free(name);
788
789                 if (colorseldlg) {
790                         GdkColor color;
791
792                         color.red = mark_palette[mark_selected].r * 256 + 128;
793                         color.green = mark_palette[mark_selected].g * 256 + 128;
794                         color.blue = mark_palette[mark_selected].b * 256 + 128;
795
796                         if (colorseldlg)
797                                 gtk_color_selection_set_current_color (colorsel, &color);
798                 }
799
800                 /* set current color for bightness+contrast window */
801                 bc_set_current();
802
803                 /* set current levels in window */
804                 level_set_current();
805
806                 if (highlight || preview)
807                         draw_image(0, 0, -1, -1);
808         }
809 }
810
811 /* name of palette entry has been entered */
812 void palette_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, GtkTreeView *treeview)
813 {
814         anything_modified = 1;
815
816         /* copy string */
817         strncpy(mark_palette[mark_selected].name, new_text, sizeof(mark_palette[mark_selected].name));
818         mark_palette[mark_selected].name[sizeof(mark_palette[mark_selected].name)-1] = '\0';
819
820         /* store string */
821         GtkTreeIter iter;
822         GtkTreeModel *model;
823
824         model = gtk_tree_view_get_model (treeview);
825         if (gtk_tree_model_get_iter_from_string (model, &iter, path))
826                 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2/*column*/, mark_palette[mark_selected].name, -1);
827
828         if (preview)
829                 draw_image(0, 0, -1, -1);
830 }
831
832 /*
833  * tool bar
834  */
835
836 extern const guint8 img_size_1[];
837 extern const guint8 img_size_3[];
838 extern const guint8 img_size_5[];
839 extern const guint8 img_size_9[];
840 extern const guint8 img_size_11[];
841 extern const guint8 img_size_19[];
842 extern const guint8 img_fill[];
843 extern const guint8 img_move[];
844
845 struct paint_buttons {
846         const guint8 *data;
847         GtkToggleButton *button;
848         int toggle_state;
849         int size;
850         int move;
851         int fill;
852         const char *tooltip;
853 } paint_buttons[] = {
854         { img_size_1, NULL, FALSE, 1, 0, 0, "Set pen size to 1" },
855         { img_size_3, NULL, TRUE, 2, 0, 0, "Set pen size to 3" },
856         { img_size_5, NULL, FALSE, 3, 0, 0, "Set pen size to 5" },
857         { img_size_9, NULL, FALSE, 5, 0, 0, "Set pen size to 9" },
858         { img_size_11, NULL, FALSE, 6, 0, 0, "Set pen size to 11" },
859         { img_size_19, NULL, FALSE, 10, 0, 0, "Set pen size to 19" },
860         { img_fill, NULL, FALSE, 0, 0, 1, "FILL marked area" },
861         { img_move, NULL, FALSE, 0, 1, 0, "Move marked pixles" },
862         { NULL, NULL, 0, 0, 0, 0, NULL },
863 };
864
865 void paint_button_toggled(GtkToggleButton *togglebutton, gpointer index)
866 {
867         int i;
868
869         if (paint_buttons[(long)index].toggle_state == gtk_toggle_button_get_active(togglebutton)) {
870                 return;
871         }
872
873         for (i = 0; paint_buttons[i].button; i++) {
874                 if ((long)index == i) {
875                         paint_buttons[i].toggle_state = TRUE;
876                         gtk_toggle_button_set_active(paint_buttons[i].button, TRUE);
877                         brush_size = paint_buttons[i].size;
878                         move_mode = paint_buttons[i].move;
879                         fill_mode = paint_buttons[i].fill;
880                 } else {
881                         paint_buttons[i].toggle_state = FALSE;
882                         gtk_toggle_button_set_active(paint_buttons[i].button, FALSE);
883                 }
884         }
885
886 }
887
888 void zoomin_button_clicked(GtkButton *button, gpointer index)
889 {
890         zoom_in_event(NULL);
891 }
892
893 void zoomout_button_clicked(GtkButton *button, gpointer index)
894 {
895         zoom_out_event(NULL);
896 }
897
898 void highlight_button_toggled(GtkButton *button, gpointer index)
899 {
900         highlight = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
901         set_menu_toggel_by_label(TOGGLE_LABEL_HIGHLIGHT, highlight);
902         draw_image(0, 0, -1, -1);
903 }
904
905 void preview_button_toggled(GtkButton *button, gpointer index)
906 {
907         preview = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
908         set_menu_toggel_by_label(TOGGLE_LABEL_PREVIEW, preview);
909         draw_image(0, 0, -1, -1);
910 }
911
912 void palette_button_clicked(GtkButton *button, gpointer index)
913 {
914         palette_event(NULL);
915 }
916
917 void bc_button_clicked(GtkButton *button, gpointer index)
918 {
919         bc_event(NULL);
920 }
921
922 void colorize_button_clicked(GtkButton *button, gpointer index)
923 {
924         colorize_event(NULL);
925 }
926
927 void view_colorized_button_toggled(GtkButton *button, gpointer index)
928 {
929         if (timeline_frames > 1)
930                 rendered = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
931         else
932                 rendered = 0;
933         gtk_toggle_button_set_active(show_colorized_button, rendered);
934         set_menu_toggel_by_label(TOGGLE_LABEL_RENDERED, rendered);
935         timeline_select_and_save(timeline_selected, timeline_selected);
936 }
937
938 #ifdef WITH_OPENCV
939 void view_flow_button_toggled(GtkButton *button, gpointer index)
940 {
941         if (flow_enable && timeline_frames > 1)
942                 flowview = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
943         else
944                 flowview = 0;
945         gtk_toggle_button_set_active(show_flow_button, flowview);
946         set_menu_toggel_by_label(TOGGLE_LABEL_FLOWVIEW, flowview);
947         timeline_select_and_save(timeline_selected, timeline_selected);
948 }
949 #endif
950
951 extern const guint8 img_zoomin[];
952 extern const guint8 img_zoomout[];
953 extern const guint8 img_pal[];
954 extern const guint8 img_bc[];
955 extern const guint8 img_highlight[];
956 extern const guint8 img_preview[];
957 extern const guint8 img_eye[];
958 extern const guint8 img_col[];
959 extern const guint8 img_flow[];
960
961 struct tool_buttons {
962         enum toggle_label label;
963         GtkWidget *widget;
964         const guint8 *data;
965         int toggle;
966         void (*handler)(GtkButton *togglebutton, gpointer priv);
967         GtkToggleButton **button;
968         const char *tooltip;
969 } tool_buttons[] = {
970         { TOGGLE_LABEL_NONE, NULL, img_zoomin, 0, zoomin_button_clicked, NULL, "Zoom in" },
971         { TOGGLE_LABEL_NONE, NULL, img_zoomout, 0, zoomout_button_clicked, NULL, "Zoom out" },
972         { TOGGLE_LABEL_NONE, NULL, img_pal, 0, palette_button_clicked, NULL, "Palette dialog" },
973         { TOGGLE_LABEL_NONE, NULL, img_bc, 0, bc_button_clicked, NULL, "Brightness+Contrast dialog" },
974         { TOGGLE_LABEL_HIGHLIGHT, NULL, img_highlight, 1, highlight_button_toggled, &show_highlighted_button, "Highlight selected mark color" },
975         { TOGGLE_LABEL_PREVIEW, NULL, img_preview, 1, preview_button_toggled, &show_preview_button, "Show preview of selected mark color" },
976         { TOGGLE_LABEL_RENDERED, NULL, img_eye, 1, view_colorized_button_toggled, &show_colorized_button, "Show result of a rendered sequence" },
977 #ifdef WITH_OPENCV
978         { TOGGLE_LABEL_FLOWVIEW, NULL, img_flow, 1, view_flow_button_toggled, &show_flow_button, "Show optical flow" },
979 #endif
980         { TOGGLE_LABEL_NONE, NULL, img_col, 0, colorize_button_clicked, NULL, "Colorize current image" },
981         { TOGGLE_LABEL_NONE, NULL, NULL, 0, NULL, NULL, NULL },
982 };
983
984 static void set_button_toggel_by_label(enum toggle_label label, gboolean active)
985 {
986         int i;
987
988         for (i = 0; tool_buttons[i].data; i++) {
989                 if (tool_buttons[i].label == label)
990                         gtk_toggle_button_set_active((GtkToggleButton *)tool_buttons[i].widget, active);
991         }
992 }
993
994 /*
995  * creation of main window
996  */
997
998 int main(int argc, char *argv[])
999 {
1000         GtkWidget *vbox, *tool_box;
1001         GtkWidget *scroll;
1002         GtkWidget *menu_bar;
1003         GtkWidget *separator;
1004         GtkTreeSelection *selection;
1005         GtkTreeViewColumn *palette_column;
1006         GtkCellRenderer *palette_renderer;
1007         GtkToggleButton *button;
1008         GtkWidget *image;
1009         GdkPixbuf *pixbuf;
1010         GtkTooltips *tooltips;
1011
1012         int i;
1013
1014         gtk_init(&argc, &argv);
1015
1016         main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1017         gtk_widget_set_size_request(GTK_WIDGET(main_window), 400, 200);
1018         gtk_window_set_default_size(GTK_WINDOW(main_window), 800, 600);
1019         gtk_window_set_title(GTK_WINDOW(main_window), CC_APP_TITLE " Version "
1020 #include "../version.h"
1021         );
1022         g_signal_connect(main_window, "delete-event", G_CALLBACK(destroy), NULL);
1023         g_signal_connect(main_window, "destroy", G_CALLBACK(destroy), NULL);
1024         g_signal_connect(main_window, "key-press-event", G_CALLBACK(on_key_press), NULL);
1025         g_signal_connect(main_window, "key-release-event", G_CALLBACK(on_key_release), NULL);
1026
1027
1028         gtk_container_set_border_width (GTK_CONTAINER (main_window), 2);
1029
1030         /* create vbox (complete window) */
1031         vbox = gtk_vbox_new(FALSE, 0);
1032         gtk_container_add(GTK_CONTAINER(main_window), vbox);
1033         gtk_widget_show(vbox);
1034
1035         /* add menu to vbox (top of vbox) */
1036         menu_bar = gtk_menu_bar_new();
1037         gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
1038         gtk_widget_show(menu_bar);
1039         create_menus(menu_bar);
1040
1041         /* add tool_box to vbox (bottom part of palette box) */
1042         tool_box = gtk_hbox_new(FALSE, 0);
1043         gtk_box_pack_start(GTK_BOX(vbox), tool_box, FALSE, FALSE, 2);
1044         gtk_widget_show(tool_box);
1045
1046         for (i = 0; paint_buttons[i].data; i++) {
1047                 pixbuf = gdk_pixbuf_new_from_inline(-1, paint_buttons[i].data, FALSE, NULL);
1048                 image = gtk_image_new_from_pixbuf(pixbuf);
1049                 gtk_widget_show(GTK_WIDGET(image));
1050                 paint_buttons[i].button = button = (GtkToggleButton *) gtk_toggle_button_new();
1051                 if (paint_buttons[i].toggle_state) {
1052                         gtk_toggle_button_set_active(button, TRUE);
1053                         brush_size = paint_buttons[i].size;
1054                 }
1055                 g_signal_connect(button, "toggled", G_CALLBACK(paint_button_toggled), (void *)((long)i));
1056                 tooltips = gtk_tooltips_new();
1057                 gtk_tooltips_set_tip(tooltips, GTK_WIDGET(button), paint_buttons[i].tooltip, NULL);
1058                 gtk_container_add (GTK_CONTAINER (button), image);
1059                 gtk_widget_show(GTK_WIDGET(button));
1060                 gtk_box_pack_start(GTK_BOX(tool_box), GTK_WIDGET(button), FALSE, FALSE, 2);
1061         }
1062
1063         for (i = 0; tool_buttons[i].data; i++) {
1064                 if (i == 0 || i == 2) {
1065                         /* add vertical seperation to hbox */
1066                         separator = gtk_vseparator_new();
1067                         gtk_widget_show(separator);
1068                         gtk_box_pack_start(GTK_BOX(tool_box), separator, FALSE, FALSE, 3);
1069                 }
1070                 pixbuf = gdk_pixbuf_new_from_inline(-1, tool_buttons[i].data, FALSE, NULL);
1071                 image = gtk_image_new_from_pixbuf(pixbuf);
1072                 gtk_widget_show(GTK_WIDGET(image));
1073                 if (tool_buttons[i].toggle) {
1074                         button = (GtkToggleButton *) gtk_toggle_button_new();
1075                         g_signal_connect(button, "toggled", G_CALLBACK(tool_buttons[i].handler), NULL);
1076                 } else {
1077                         button = (GtkToggleButton *) gtk_button_new();
1078                         g_signal_connect(button, "clicked", G_CALLBACK(tool_buttons[i].handler), NULL);
1079                 }
1080                 tool_buttons[i].widget = (GtkWidget *)button;
1081                 tooltips = gtk_tooltips_new();
1082                 gtk_tooltips_set_tip(tooltips, GTK_WIDGET(button), tool_buttons[i].tooltip, NULL);
1083                 if (tool_buttons[i].button)
1084                         *(tool_buttons[i].button) = button;
1085                 gtk_container_add (GTK_CONTAINER (button), image);
1086                 gtk_widget_show(GTK_WIDGET(button));
1087                 gtk_box_pack_start(GTK_BOX(tool_box), GTK_WIDGET(button), FALSE, FALSE, 2);
1088         }
1089
1090         /* add paned view to vbox (middle part of vbox) */
1091         GtkWidget *paned = gtk_hpaned_new ();
1092         gtk_widget_show(paned);
1093         gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 2);
1094         gtk_paned_set_position(GTK_PANED (paned), 250);
1095
1096         /* add palette treeview to hbox (top part of palette box) */
1097         palette_treeview = gtk_tree_view_new();
1098         gtk_widget_set_size_request(palette_treeview, 250, 400);
1099         g_signal_connect(palette_treeview, "enter_notify_event", G_CALLBACK(enter_palette_area), NULL);
1100         g_signal_connect(palette_treeview, "leave_notify_event", G_CALLBACK(leave_palette_area), NULL);
1101         gtk_widget_set_events(palette_treeview, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1102         gtk_widget_show(palette_treeview);
1103
1104         scroll = gtk_scrolled_window_new(NULL, NULL);
1105         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1106         gtk_widget_show(scroll);
1107         gtk_container_add(GTK_CONTAINER(scroll), palette_treeview);
1108
1109         palette_renderer = gtk_cell_renderer_text_new();
1110         g_object_set(G_OBJECT(palette_renderer), "editable", FALSE, NULL);
1111         palette_column = gtk_tree_view_column_new_with_attributes("", palette_renderer, "text", 0/*column*/, NULL);
1112         gtk_tree_view_insert_column(GTK_TREE_VIEW(palette_treeview), GTK_TREE_VIEW_COLUMN(palette_column), 0/*column*/);
1113
1114         palette_renderer = gtk_cell_renderer_pixbuf_new();
1115         palette_column = gtk_tree_view_column_new_with_attributes("", palette_renderer, "pixbuf", 1/*column*/, NULL);
1116         gtk_tree_view_insert_column(GTK_TREE_VIEW(palette_treeview), GTK_TREE_VIEW_COLUMN(palette_column), 1/*column*/);
1117
1118         palette_renderer = gtk_cell_renderer_text_new();
1119         g_object_set(G_OBJECT(palette_renderer), "editable", TRUE, NULL);
1120         g_signal_connect(palette_renderer, "edited", (GCallback) palette_edited, palette_treeview);
1121         palette_column = gtk_tree_view_column_new_with_attributes("", palette_renderer, "text", 2/*column*/, NULL);
1122         gtk_tree_view_insert_column(GTK_TREE_VIEW(palette_treeview), GTK_TREE_VIEW_COLUMN(palette_column), 2/*column*/);
1123
1124         create_palette();
1125
1126         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(palette_treeview));
1127         g_signal_connect(selection, "changed", G_CALLBACK(palette_change), NULL);
1128         gtk_paned_pack1 (GTK_PANED (paned), scroll, TRUE, TRUE);
1129
1130         /* add drawing area (right of hbox) */
1131         img_drawing_area = gtk_drawing_area_new ();
1132         gtk_signal_connect(GTK_OBJECT(img_drawing_area), "motion_notify_event", (GtkSignalFunc)motion_notify_event, NULL);
1133         gtk_signal_connect(GTK_OBJECT (img_drawing_area), "button_press_event", (GtkSignalFunc)button_press_event, NULL);
1134         gtk_signal_connect(GTK_OBJECT (img_drawing_area), "expose_event", (GtkSignalFunc)img_expose_event, NULL); 
1135         g_signal_connect(img_drawing_area, "enter_notify_event", G_CALLBACK(enter_drawing_area), NULL);
1136         g_signal_connect(img_drawing_area, "leave_notify_event", G_CALLBACK(leave_drawing_area), NULL);
1137         gtk_widget_set_events(img_drawing_area, GDK_EXPOSURE_MASK
1138                 | GDK_ENTER_NOTIFY_MASK
1139                 | GDK_LEAVE_NOTIFY_MASK
1140                 | GDK_BUTTON_PRESS_MASK
1141                 | GDK_POINTER_MOTION_MASK
1142                 | GDK_POINTER_MOTION_HINT_MASK);
1143         gtk_widget_show(img_drawing_area);
1144
1145         scroll = gtk_scrolled_window_new(NULL, NULL);
1146         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1147         gtk_widget_show(scroll);
1148         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), img_drawing_area);
1149         gtk_paned_pack2 (GTK_PANED (paned), scroll, TRUE, TRUE);
1150
1151 #if 0
1152         /* add horizontal seperation to vbox */
1153         separator = gtk_hseparator_new();
1154         gtk_widget_show(separator);
1155         gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 3);
1156 #endif
1157
1158         /* add timeline (bottom of vbox) */
1159         timeline_drawing_area = gtk_drawing_area_new ();
1160         gtk_widget_set_size_request(timeline_drawing_area, 10, 10);
1161         gtk_signal_connect(GTK_OBJECT(timeline_drawing_area), "motion_notify_event", (GtkSignalFunc)timeline_motion_notify_event, NULL);
1162         gtk_signal_connect(GTK_OBJECT(timeline_drawing_area), "button_press_event", (GtkSignalFunc)timeline_press_event, NULL);
1163         gtk_signal_connect(GTK_OBJECT(timeline_drawing_area), "expose_event", (GtkSignalFunc)timeline_expose_event, NULL); 
1164         g_signal_connect(timeline_drawing_area, "enter_notify_event", G_CALLBACK(enter_timeline_area), NULL);
1165         g_signal_connect(timeline_drawing_area, "leave_notify_event", G_CALLBACK(leave_timeline_area), NULL);
1166         gtk_widget_set_events(timeline_drawing_area, GDK_EXPOSURE_MASK
1167                 | GDK_ENTER_NOTIFY_MASK
1168                 | GDK_LEAVE_NOTIFY_MASK
1169                 | GDK_BUTTON_PRESS_MASK
1170                 | GDK_POINTER_MOTION_MASK
1171                 | GDK_POINTER_MOTION_HINT_MASK);
1172         gtk_widget_show(timeline_drawing_area);
1173         timeline_scroll = gtk_scrolled_window_new(NULL, NULL);
1174         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(timeline_scroll), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1175 //      gtk_widget_show(timeline_scroll);
1176         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(timeline_scroll), timeline_drawing_area);
1177         gtk_box_pack_start(GTK_BOX(vbox), timeline_scroll, FALSE, FALSE, 0);
1178
1179         create_timeline(NULL);
1180
1181         /* label */
1182         img_label = GTK_LABEL(gtk_label_new(NULL));
1183         gtk_widget_show(GTK_WIDGET(img_label));
1184         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(img_label), FALSE, FALSE, 0);
1185
1186         /* show window */
1187         gtk_widget_show(main_window);
1188
1189         if (argc > 1) {
1190                 create_timeline(argv[1]);
1191                 if (frame_list)
1192                         create_image(frame_list[timeline_selected].filename);
1193         }
1194
1195         gtk_main();
1196
1197         // FIXME: destroy
1198
1199         return 0;
1200 }
1201