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