Move GTK menu bar and functions into seperate file
[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 "menu.h"
12 #include "image.h"
13 #include "palette.h"
14 #include "timeline.h"
15 #include "colorize.h"
16 #include "brightcontrast.h"
17 #include "level.h"
18 #include "fill.h"
19 #ifdef WITH_OPENCV
20 #include "flow.h"
21 #endif
22
23 #define CC_APP_TITLE "Colorize GTK"
24 GtkWidget *main_window;
25 GtkWidget *img_scroll;
26 GtkWidget *img_drawing_area = NULL;
27 GtkWidget *timeline_drawing_area;
28 GtkWidget *timeline_scroll;
29 GtkWidget *palette_treeview = NULL;
30 GtkLabel *img_label;
31 GtkToggleButton *show_highlighted_button, *show_preview_button, *show_colorized_button;
32 #ifdef WITH_OPENCV
33 GtkToggleButton *show_flow_button;
34 #endif
35 int button_down = 0, button_down_x = -1000, button_down_y = -1000, shift_pressed = 0, button_num = 1;
36 int brush_size;
37 int highlight = 0, preview = 0, rendered = 0, move_mode = 0, fill_mode = 0, flowview = 0;
38 int mouse_over_palette_area = 0, mouse_over_drawing_area = 0, mouse_over_timeline_area = 0;
39 #define min(x,y) ((x < y) ? x : y)
40 #define abs(x,y) ((x < y) ? y - x : x - y)
41
42 /* error requester */
43 void printerror(const char *fmt, ...)
44 {
45         char buffer[4096];
46         va_list args;
47
48         va_start(args,fmt);
49         vsprintf(buffer,fmt,args);
50         buffer[sizeof(buffer)-1]=0;
51         va_end(args);
52
53         GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
54                 GTK_DIALOG_DESTROY_WITH_PARENT,
55                 GTK_MESSAGE_ERROR,
56                 GTK_BUTTONS_CLOSE,
57                 "%s", buffer);
58         gtk_dialog_run (GTK_DIALOG (dialog));
59         gtk_widget_destroy (dialog);
60 }
61
62 static int already_destroyed = 0;
63
64 /* exit program and save current mask / palette */
65 void main_destroy(void)
66 {
67         if (anything_modified) {
68                 int ret;
69                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(main_window),
70                         GTK_DIALOG_DESTROY_WITH_PARENT,
71                         GTK_MESSAGE_ERROR,
72                         GTK_BUTTONS_OK_CANCEL,
73                         "Image has been changed, really quit?");
74                 ret = gtk_dialog_run(GTK_DIALOG (dialog));
75                 gtk_widget_destroy(dialog);
76                 if (ret != GTK_RESPONSE_OK)
77                         return;
78         }
79         already_destroyed = 1;
80         gtk_main_quit();
81 }
82
83
84 static void destroy(GtkWidget *widget, gpointer data)
85 {
86         if (!already_destroyed)
87                 main_destroy();
88 }
89
90 /*
91  * keypress
92  */
93
94 /* event handler for main window keys */
95 static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
96 {
97         int frame;
98
99 //      if (mouse_over_palette_area)
100         if (!mouse_over_drawing_area && !mouse_over_timeline_area)
101                 return FALSE;
102
103         switch (event->keyval) {
104         case GDK_q:
105         case GDK_w:
106                 if (event->state & GDK_CONTROL_MASK) {
107                         main_destroy();
108                         return TRUE;
109                 }
110                 break;
111         case GDK_Right:
112                 frame = timeline_selected + 1;
113                 if (event->state & GDK_SHIFT_MASK) {
114                         while(frame < timeline_frames && frame_list[frame].marked == 0 && frame_list[frame].keyframe == 0)
115                                 frame++;
116                 }
117                 if (frame < timeline_frames)
118                         timeline_select_and_save(timeline_selected, frame);
119                 return TRUE;
120         case GDK_Left:
121                 frame = timeline_selected - 1;
122                 if (event->state & GDK_SHIFT_MASK) {
123                         while(frame >= 0 && frame_list[frame].marked == 0 && frame_list[frame].keyframe == 0)
124                                 frame--;
125                 }
126                 if (frame >= 0)
127                         timeline_select_and_save(timeline_selected, frame);
128                 return TRUE;
129         case GDK_Home:
130                 frame = 0;
131                 timeline_select_and_save(timeline_selected, frame);
132                 return TRUE;
133         case GDK_End:
134                 frame = timeline_frames - 1;
135                 timeline_select_and_save(timeline_selected, frame);
136                 return TRUE;
137         case GDK_u:
138         case GDK_z:
139                 undo_event(NULL);
140                 return TRUE;
141         case GDK_r:
142                 redo_event(NULL);
143                 return TRUE;
144         case GDK_c:
145                 if (event->state & GDK_CONTROL_MASK) {
146                         copy_event(NULL);
147                         return TRUE;
148                 }
149                 break;
150         case GDK_v:
151                 if (event->state & GDK_CONTROL_MASK) {
152                         paste_event(NULL);
153                         return TRUE;
154                 }
155                 break;
156         case GDK_k:
157                 toggle_keyframe();
158                 return TRUE;
159         case GDK_Shift_L:
160         case GDK_Shift_R:
161                 shift_pressed = 1;
162                 break;
163 //      default:
164 //              printf("press %x\n", event->keyval);
165         }
166
167         return FALSE;
168 }
169
170 /* event handler for main window keys */
171 static gboolean on_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
172 {
173         switch (event->keyval) {
174         case GDK_Shift_L:
175         case GDK_Shift_R:
176                 shift_pressed = 0;
177                 break;
178 //      default:
179 //              printf("release %x\n", event->keyval);
180         }
181
182         return FALSE;
183 }
184
185 /*
186  * image area
187  */
188
189 /* events if mouse is over palette area */
190 static gboolean enter_palette_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
191 {
192         mouse_over_palette_area = 1;
193         return FALSE;
194 }
195 static gboolean leave_palette_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
196 {
197         mouse_over_palette_area = 0;
198         return FALSE;
199 }
200
201 /* events if mouse is over image area */
202 static gboolean enter_drawing_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
203 {
204         mouse_over_drawing_area = 1;
205         return FALSE;
206 }
207 static gboolean leave_drawing_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
208 {
209         mouse_over_drawing_area = 0;
210         return FALSE;
211 }
212
213 /* events if mouse is over timeline area */
214 static gboolean enter_timeline_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
215 {
216         mouse_over_timeline_area = 1;
217         return FALSE;
218 }
219 static gboolean leave_timeline_area(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
220 {
221         mouse_over_timeline_area = 0;
222         timeline_point(-1, -1);
223         return FALSE;
224 }
225
226 /* ugly non-bresenham.... */
227 static void draw_line(int x, int y, int paint)
228 {
229         double step_x = 0, step_y = 0;
230
231         if (abs(x,button_down_x) > abs(y,button_down_y)) {
232                 while(42) {
233                         if (button_down_x < x) {
234                                 step_x++;
235                                 step_y += (double)(button_down_y - y) / (double)(button_down_x - x);
236                         } else {
237                                 step_x--;
238                                 step_y -= (double)(button_down_y - y) / (double)(button_down_x - x);
239                         }
240                         paint_brush(button_down_x+step_x, button_down_y+step_y, brush_size, paint);
241                         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);
242                         if (x == button_down_x+step_x)
243                                 break;
244                 }
245         } else {
246                 while(42) {
247                         if (y == button_down_y) /* no move at all */
248                                 break;
249                         if (button_down_y < y) {
250                                 step_y++;
251                                 step_x += (double)(button_down_x - x) / (double)(button_down_y - y);
252                         } else {
253                                 step_y--;
254                                 step_x -= (double)(button_down_x - x) / (double)(button_down_y - y);
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 (y == button_down_y+step_y)
259                                 break;
260                 }
261         }
262         paint_brush(x, y, brush_size, paint);
263         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);
264         button_down_x = x;
265         button_down_y = y;
266 }
267
268 /* notify movement of mouse inside image area */
269 static gint motion_notify_event( GtkWidget *widget,
270                                  GdkEventMotion *event )
271 {
272         int x, y;
273         GdkModifierType state;
274
275         if (event->is_hint)
276                 gdk_window_get_pointer (event->window, &x, &y, &state);
277         else
278         {
279                 x = event->x;
280                 y = event->y;
281                 state = event->state;
282         }
283
284         if ((state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))) {
285                 if (button_down) {
286                         if (move_mode) {
287                                 move_mark((x-button_down_x)*16/img_scale_x, (y-button_down_y)*16/img_scale_y);
288                                 draw_image(0, 0, -1, -1);
289                         } else {
290                                 draw_line(x, y, button_num == 1);
291                         }
292                 }
293         } else {
294                 button_down = 0;
295         }
296                                                                                    
297         return TRUE;
298 }
299
300 /* button press event inside image area */
301 static gint button_press_event (GtkWidget *widget, GdkEventButton *event)
302 {
303         int x,y;
304
305         x = event->x;
306         y = event->y;
307         button_num = event->button;
308
309         if (!button_down)
310                 copy_mark_to_undo();
311         if (fill_mode) {
312                 fill(x, y, event->button != 1);
313                 draw_image(0, 0, -1, -1);
314         } else
315         if (move_mode) {
316                 if (button_down)
317                         return TRUE;
318                 button_down_x = x;
319                 button_down_y = y;
320         } else {
321                 /* if not shift, draw a dot and not a line */
322                 if (!shift_pressed || button_down_x == -1000) {
323                         button_down_x = x;
324                         button_down_y = y;
325                 }
326                 draw_line(x, y, button_num == 1);
327         }
328         button_down = 1;
329         return TRUE;
330 }
331
332 /* redraw event of image area */
333 static gint img_expose_event (GtkWidget *widget, GdkEventExpose *event)
334 {
335         draw_image(event->area.x, event->area.y, event->area.width, event->area.height);
336
337         return FALSE;
338 }
339
340 /*
341  * timeline
342  */
343
344 /* mouse move event inside timeline */
345 static gint timeline_motion_notify_event( GtkWidget *widget,
346                                  GdkEventMotion *event )
347 {
348         int x, y;
349         GdkModifierType state;
350
351         if (event->is_hint)
352                 gdk_window_get_pointer (event->window, &x, &y, &state);
353         else
354         {
355                 x = event->x;
356                 y = event->y;
357                 state = event->state;
358         }
359
360         timeline_point(x, y);
361
362         if ((state & GDK_BUTTON1_MASK)) {
363                 timeline_clicked(x, y);
364
365         }
366                                                                                    
367         return TRUE;
368 }
369
370 /* button press event inside timeline area */
371 static gint timeline_press_event (GtkWidget *widget, GdkEventButton *event)
372 {
373         int x,y;
374
375         x = event->x;
376         y = event->y;
377         timeline_clicked(x, y);
378
379         return TRUE;
380 }
381
382 /* redraw event of timeline area */
383 static gint timeline_expose_event (GtkWidget *widget, GdkEventExpose *event)
384 {
385         draw_timeline(event->area.x, event->area.y, event->area.width, event->area.height);
386
387         return FALSE;
388 }
389
390 /*
391  * colorselection
392  */
393
394 GtkWidget *colorseldlg = NULL;
395 GtkColorSelection *colorsel;
396 /* color selection's buttons have been pressed */
397 void color_response(GtkDialog *dialog, gint response_id, gpointer user_data)
398 {
399         GdkColor ncolor;
400
401         switch (response_id) {
402         case GTK_RESPONSE_CANCEL:
403                 gtk_color_selection_get_previous_color(colorsel, &ncolor);
404 new_color:
405                 anything_modified = 1;
406
407                 mark_palette[mark_selected].r = ncolor.red / 256;
408                 mark_palette[mark_selected].g = ncolor.green / 256;
409                 mark_palette[mark_selected].b = ncolor.blue / 256;
410                 update_color(mark_selected);
411                 draw_image(0, 0, -1, -1);
412                 break;
413         case GTK_RESPONSE_OK:
414                 gtk_color_selection_get_current_color(colorsel, &ncolor);
415                 goto new_color;
416         }
417 }
418
419 /*
420  * palette
421  */
422
423 /* palette entry has been clicked */
424 void palette_change(GtkTreeSelection *selection, gpointer data)
425 {
426         GtkTreeModel     *model;
427         GtkTreeIter       iter;
428
429         if (gtk_tree_selection_get_selected(selection, &model, &iter))
430         {
431                 gchar *name;
432
433                 gtk_tree_model_get (model, &iter, 0/*column*/, &name, -1);
434                 mark_selected = atoi(name) - 1;
435                 g_free(name);
436
437                 if (colorseldlg) {
438                         GdkColor color;
439
440                         color.red = mark_palette[mark_selected].r * 256 + 128;
441                         color.green = mark_palette[mark_selected].g * 256 + 128;
442                         color.blue = mark_palette[mark_selected].b * 256 + 128;
443
444                         if (colorseldlg) {
445                                 gtk_color_selection_set_previous_color (colorsel, &color);
446                                 gtk_color_selection_set_current_color (colorsel, &color);
447                         }
448                 }
449
450                 /* set current color for bightness+contrast window */
451                 bc_set_current();
452
453                 /* set current levels in window */
454                 level_set_current();
455
456                 if (highlight || preview)
457                         draw_image(0, 0, -1, -1);
458         }
459 }
460
461 /* name of palette entry has been entered */
462 void palette_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, GtkTreeView *treeview)
463 {
464         anything_modified = 1;
465
466         /* copy string */
467         strncpy(mark_palette[mark_selected].name, new_text, sizeof(mark_palette[mark_selected].name));
468         mark_palette[mark_selected].name[sizeof(mark_palette[mark_selected].name)-1] = '\0';
469
470         /* store string */
471         GtkTreeIter iter;
472         GtkTreeModel *model;
473
474         model = gtk_tree_view_get_model (treeview);
475         if (gtk_tree_model_get_iter_from_string (model, &iter, path))
476                 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2/*column*/, mark_palette[mark_selected].name, -1);
477
478         if (preview)
479                 draw_image(0, 0, -1, -1);
480 }
481
482 /*
483  * tool bar
484  */
485
486 extern const guint8 img_size_1[];
487 extern const guint8 img_size_3[];
488 extern const guint8 img_size_5[];
489 extern const guint8 img_size_9[];
490 extern const guint8 img_size_11[];
491 extern const guint8 img_size_19[];
492 extern const guint8 img_fill[];
493 extern const guint8 img_move[];
494
495 struct paint_buttons {
496         const guint8 *data;
497         GtkToggleButton *button;
498         int toggle_state;
499         int size;
500         int move;
501         int fill;
502         const char *tooltip;
503 } paint_buttons[] = {
504         { img_size_1, NULL, FALSE, 1, 0, 0, "Set pen size to 1" },
505         { img_size_3, NULL, TRUE, 2, 0, 0, "Set pen size to 3" },
506         { img_size_5, NULL, FALSE, 3, 0, 0, "Set pen size to 5" },
507         { img_size_9, NULL, FALSE, 5, 0, 0, "Set pen size to 9" },
508         { img_size_11, NULL, FALSE, 6, 0, 0, "Set pen size to 11" },
509         { img_size_19, NULL, FALSE, 10, 0, 0, "Set pen size to 19" },
510         { img_fill, NULL, FALSE, 0, 0, 1, "FILL marked area" },
511         { img_move, NULL, FALSE, 0, 1, 0, "Move marked pixles" },
512         { NULL, NULL, 0, 0, 0, 0, NULL },
513 };
514
515 void paint_button_toggled(GtkToggleButton *togglebutton, gpointer index)
516 {
517         int i;
518
519         if (paint_buttons[(long)index].toggle_state == gtk_toggle_button_get_active(togglebutton)) {
520                 return;
521         }
522
523         for (i = 0; paint_buttons[i].button; i++) {
524                 if ((long)index == i) {
525                         paint_buttons[i].toggle_state = TRUE;
526                         gtk_toggle_button_set_active(paint_buttons[i].button, TRUE);
527                         brush_size = paint_buttons[i].size;
528                         move_mode = paint_buttons[i].move;
529                         fill_mode = paint_buttons[i].fill;
530                 } else {
531                         paint_buttons[i].toggle_state = FALSE;
532                         gtk_toggle_button_set_active(paint_buttons[i].button, FALSE);
533                 }
534         }
535
536 }
537
538 void zoomin_button_clicked(GtkButton *button, gpointer index)
539 {
540         zoom_in_event(NULL);
541 }
542
543 void zoomout_button_clicked(GtkButton *button, gpointer index)
544 {
545         zoom_out_event(NULL);
546 }
547
548 void highlight_button_toggled(GtkButton *button, gpointer index)
549 {
550         highlight = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
551         set_menu_toggel_by_label(TOGGLE_LABEL_HIGHLIGHT, highlight);
552         draw_image(0, 0, -1, -1);
553 }
554
555 void preview_button_toggled(GtkButton *button, gpointer index)
556 {
557         preview = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
558         set_menu_toggel_by_label(TOGGLE_LABEL_PREVIEW, preview);
559         draw_image(0, 0, -1, -1);
560 }
561
562 void palette_button_clicked(GtkButton *button, gpointer index)
563 {
564         palette_event(NULL);
565 }
566
567 void bc_button_clicked(GtkButton *button, gpointer index)
568 {
569         bc_event(NULL);
570 }
571
572 void colorize_button_clicked(GtkButton *button, gpointer index)
573 {
574         colorize_event(NULL);
575 }
576
577 void view_colorized_button_toggled(GtkButton *button, gpointer index)
578 {
579         if (timeline_frames > 1)
580                 rendered = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
581         else
582                 rendered = 0;
583         gtk_toggle_button_set_active(show_colorized_button, rendered);
584         set_menu_toggel_by_label(TOGGLE_LABEL_RENDERED, rendered);
585         timeline_select_and_save(timeline_selected, timeline_selected);
586 }
587
588 #ifdef WITH_OPENCV
589 void view_flow_button_toggled(GtkButton *button, gpointer index)
590 {
591         if (flow_enable && timeline_frames > 1)
592                 flowview = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
593         else
594                 flowview = 0;
595         gtk_toggle_button_set_active(show_flow_button, flowview);
596         set_menu_toggel_by_label(TOGGLE_LABEL_FLOWVIEW, flowview);
597         timeline_select_and_save(timeline_selected, timeline_selected);
598 }
599 #endif
600
601 extern const guint8 img_zoomin[];
602 extern const guint8 img_zoomout[];
603 extern const guint8 img_pal[];
604 extern const guint8 img_bc[];
605 extern const guint8 img_highlight[];
606 extern const guint8 img_preview[];
607 extern const guint8 img_eye[];
608 extern const guint8 img_col[];
609 extern const guint8 img_flow[];
610
611 struct tool_buttons {
612         enum toggle_label label;
613         GtkWidget *widget;
614         const guint8 *data;
615         int toggle;
616         void (*handler)(GtkButton *togglebutton, gpointer priv);
617         GtkToggleButton **button;
618         const char *tooltip;
619 } tool_buttons[] = {
620         { TOGGLE_LABEL_NONE, NULL, img_zoomin, 0, zoomin_button_clicked, NULL, "Zoom in" },
621         { TOGGLE_LABEL_NONE, NULL, img_zoomout, 0, zoomout_button_clicked, NULL, "Zoom out" },
622         { TOGGLE_LABEL_NONE, NULL, img_pal, 0, palette_button_clicked, NULL, "Palette dialog" },
623         { TOGGLE_LABEL_NONE, NULL, img_bc, 0, bc_button_clicked, NULL, "Brightness+Contrast dialog" },
624         { TOGGLE_LABEL_HIGHLIGHT, NULL, img_highlight, 1, highlight_button_toggled, &show_highlighted_button, "Highlight selected mark color" },
625         { TOGGLE_LABEL_PREVIEW, NULL, img_preview, 1, preview_button_toggled, &show_preview_button, "Show preview of selected mark color" },
626         { TOGGLE_LABEL_RENDERED, NULL, img_eye, 1, view_colorized_button_toggled, &show_colorized_button, "Show result of a rendered sequence" },
627 #ifdef WITH_OPENCV
628         { TOGGLE_LABEL_FLOWVIEW, NULL, img_flow, 1, view_flow_button_toggled, &show_flow_button, "Show optical flow" },
629 #endif
630         { TOGGLE_LABEL_NONE, NULL, img_col, 0, colorize_button_clicked, NULL, "Colorize current image" },
631         { TOGGLE_LABEL_NONE, NULL, NULL, 0, NULL, NULL, NULL },
632 };
633
634 void set_button_toggel_by_label(enum toggle_label label, gboolean active)
635 {
636         int i;
637
638         for (i = 0; tool_buttons[i].data; i++) {
639                 if (tool_buttons[i].label == label)
640                         gtk_toggle_button_set_active((GtkToggleButton *)tool_buttons[i].widget, active);
641         }
642 }
643
644 /*
645  * creation of main window
646  */
647
648 int main(int argc, char *argv[])
649 {
650         GtkWidget *vbox, *tool_box;
651         GtkWidget *paned;
652         GtkWidget *pal_scroll;
653         GtkWidget *menu_bar;
654         GtkWidget *separator;
655         GtkTreeSelection *selection;
656         GtkTreeViewColumn *palette_column;
657         GtkCellRenderer *palette_renderer;
658         GtkToggleButton *button;
659         GtkWidget *image;
660         GdkPixbuf *pixbuf;
661         GtkTooltips *tooltips;
662
663         int i;
664
665         gtk_init(&argc, &argv);
666
667         main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
668         gtk_widget_set_size_request(GTK_WIDGET(main_window), 400, 200);
669         gtk_window_set_default_size(GTK_WINDOW(main_window), 800, 500);
670         gtk_window_set_title(GTK_WINDOW(main_window), CC_APP_TITLE " Version "
671 #include "../version.h"
672         );
673         g_signal_connect(main_window, "delete-event", G_CALLBACK(destroy), NULL);
674         g_signal_connect(main_window, "destroy", G_CALLBACK(destroy), NULL);
675         g_signal_connect(main_window, "key-press-event", G_CALLBACK(on_key_press), NULL);
676         g_signal_connect(main_window, "key-release-event", G_CALLBACK(on_key_release), NULL);
677
678
679         gtk_container_set_border_width (GTK_CONTAINER (main_window), 2);
680
681         /* create vbox (complete window) */
682         vbox = gtk_vbox_new(FALSE, 0);
683         gtk_container_add(GTK_CONTAINER(main_window), vbox);
684         gtk_widget_show(vbox);
685
686         /* add menu to vbox (top of vbox) */
687         menu_bar = gtk_menu_bar_new();
688         gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
689         gtk_widget_show(menu_bar);
690         create_menus(menu_bar);
691
692         /* add tool_box to vbox (bottom part of palette box) */
693         tool_box = gtk_hbox_new(FALSE, 0);
694         gtk_box_pack_start(GTK_BOX(vbox), tool_box, FALSE, FALSE, 2);
695         gtk_widget_show(tool_box);
696
697         for (i = 0; paint_buttons[i].data; i++) {
698                 pixbuf = gdk_pixbuf_new_from_inline(-1, paint_buttons[i].data, FALSE, NULL);
699                 image = gtk_image_new_from_pixbuf(pixbuf);
700                 gtk_widget_show(GTK_WIDGET(image));
701                 paint_buttons[i].button = button = (GtkToggleButton *) gtk_toggle_button_new();
702                 if (paint_buttons[i].toggle_state) {
703                         gtk_toggle_button_set_active(button, TRUE);
704                         brush_size = paint_buttons[i].size;
705                 }
706                 g_signal_connect(button, "toggled", G_CALLBACK(paint_button_toggled), (void *)((long)i));
707                 tooltips = gtk_tooltips_new();
708                 gtk_tooltips_set_tip(tooltips, GTK_WIDGET(button), paint_buttons[i].tooltip, NULL);
709                 gtk_container_add (GTK_CONTAINER (button), image);
710                 gtk_widget_show(GTK_WIDGET(button));
711                 gtk_box_pack_start(GTK_BOX(tool_box), GTK_WIDGET(button), FALSE, FALSE, 2);
712         }
713
714         for (i = 0; tool_buttons[i].data; i++) {
715                 if (i == 0 || i == 2) {
716                         /* add vertical seperation to hbox */
717                         separator = gtk_vseparator_new();
718                         gtk_widget_show(separator);
719                         gtk_box_pack_start(GTK_BOX(tool_box), separator, FALSE, FALSE, 3);
720                 }
721                 pixbuf = gdk_pixbuf_new_from_inline(-1, tool_buttons[i].data, FALSE, NULL);
722                 image = gtk_image_new_from_pixbuf(pixbuf);
723                 gtk_widget_show(GTK_WIDGET(image));
724                 if (tool_buttons[i].toggle) {
725                         button = (GtkToggleButton *) gtk_toggle_button_new();
726                         g_signal_connect(button, "toggled", G_CALLBACK(tool_buttons[i].handler), NULL);
727                 } else {
728                         button = (GtkToggleButton *) gtk_button_new();
729                         g_signal_connect(button, "clicked", G_CALLBACK(tool_buttons[i].handler), NULL);
730                 }
731                 tool_buttons[i].widget = (GtkWidget *)button;
732                 tooltips = gtk_tooltips_new();
733                 gtk_tooltips_set_tip(tooltips, GTK_WIDGET(button), tool_buttons[i].tooltip, NULL);
734                 if (tool_buttons[i].button)
735                         *(tool_buttons[i].button) = button;
736                 gtk_container_add (GTK_CONTAINER (button), image);
737                 gtk_widget_show(GTK_WIDGET(button));
738                 gtk_box_pack_start(GTK_BOX(tool_box), GTK_WIDGET(button), FALSE, FALSE, 2);
739         }
740
741         /* add paned view to vbox (middle part of vbox) */
742         paned = gtk_hpaned_new ();
743         gtk_widget_show(paned);
744         gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 2);
745         gtk_paned_set_position(GTK_PANED (paned), 250);
746
747         /* add palette treeview to hbox (top part of palette box) */
748         palette_treeview = gtk_tree_view_new();
749         gtk_widget_set_size_request(palette_treeview, 250, 400);
750         g_signal_connect(palette_treeview, "enter_notify_event", G_CALLBACK(enter_palette_area), NULL);
751         g_signal_connect(palette_treeview, "leave_notify_event", G_CALLBACK(leave_palette_area), NULL);
752         gtk_widget_set_events(palette_treeview, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
753         gtk_widget_show(palette_treeview);
754
755         pal_scroll = gtk_scrolled_window_new(NULL, NULL);
756         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pal_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
757         gtk_widget_show(pal_scroll);
758         gtk_container_add(GTK_CONTAINER(pal_scroll), palette_treeview);
759
760         palette_renderer = gtk_cell_renderer_text_new();
761         g_object_set(G_OBJECT(palette_renderer), "editable", FALSE, NULL);
762         palette_column = gtk_tree_view_column_new_with_attributes("", palette_renderer, "text", 0/*column*/, NULL);
763         gtk_tree_view_insert_column(GTK_TREE_VIEW(palette_treeview), GTK_TREE_VIEW_COLUMN(palette_column), 0/*column*/);
764
765         palette_renderer = gtk_cell_renderer_pixbuf_new();
766         palette_column = gtk_tree_view_column_new_with_attributes("", palette_renderer, "pixbuf", 1/*column*/, NULL);
767         gtk_tree_view_insert_column(GTK_TREE_VIEW(palette_treeview), GTK_TREE_VIEW_COLUMN(palette_column), 1/*column*/);
768
769         palette_renderer = gtk_cell_renderer_text_new();
770         g_object_set(G_OBJECT(palette_renderer), "editable", TRUE, NULL);
771         g_signal_connect(palette_renderer, "edited", (GCallback) palette_edited, palette_treeview);
772         palette_column = gtk_tree_view_column_new_with_attributes("", palette_renderer, "text", 2/*column*/, NULL);
773         gtk_tree_view_insert_column(GTK_TREE_VIEW(palette_treeview), GTK_TREE_VIEW_COLUMN(palette_column), 2/*column*/);
774
775         create_palette();
776
777         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(palette_treeview));
778         g_signal_connect(selection, "changed", G_CALLBACK(palette_change), NULL);
779         gtk_paned_pack1 (GTK_PANED (paned), pal_scroll, FALSE, TRUE);
780
781         /* add drawing area (right of hbox) */
782         img_drawing_area = gtk_drawing_area_new ();
783         gtk_signal_connect(GTK_OBJECT(img_drawing_area), "motion_notify_event", (GtkSignalFunc)motion_notify_event, NULL);
784         gtk_signal_connect(GTK_OBJECT (img_drawing_area), "button_press_event", (GtkSignalFunc)button_press_event, NULL);
785         gtk_signal_connect(GTK_OBJECT (img_drawing_area), "expose_event", (GtkSignalFunc)img_expose_event, NULL); 
786         g_signal_connect(img_drawing_area, "enter_notify_event", G_CALLBACK(enter_drawing_area), NULL);
787         g_signal_connect(img_drawing_area, "leave_notify_event", G_CALLBACK(leave_drawing_area), NULL);
788         gtk_widget_set_events(img_drawing_area, GDK_EXPOSURE_MASK
789                 | GDK_ENTER_NOTIFY_MASK
790                 | GDK_LEAVE_NOTIFY_MASK
791                 | GDK_BUTTON_PRESS_MASK
792                 | GDK_POINTER_MOTION_MASK
793                 | GDK_POINTER_MOTION_HINT_MASK);
794         gtk_widget_show(img_drawing_area);
795
796         img_scroll = gtk_scrolled_window_new(NULL, NULL);
797         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(img_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
798         gtk_widget_show(img_scroll);
799         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(img_scroll), img_drawing_area);
800         gtk_paned_pack2 (GTK_PANED (paned), img_scroll, TRUE, TRUE);
801
802 #if 0
803         /* add horizontal seperation to vbox */
804         separator = gtk_hseparator_new();
805         gtk_widget_show(separator);
806         gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 3);
807 #endif
808
809         /* add timeline (bottom of vbox) */
810         timeline_drawing_area = gtk_drawing_area_new ();
811         gtk_widget_set_size_request(timeline_drawing_area, 10, 10);
812         gtk_signal_connect(GTK_OBJECT(timeline_drawing_area), "motion_notify_event", (GtkSignalFunc)timeline_motion_notify_event, NULL);
813         gtk_signal_connect(GTK_OBJECT(timeline_drawing_area), "button_press_event", (GtkSignalFunc)timeline_press_event, NULL);
814         gtk_signal_connect(GTK_OBJECT(timeline_drawing_area), "expose_event", (GtkSignalFunc)timeline_expose_event, NULL); 
815         g_signal_connect(timeline_drawing_area, "enter_notify_event", G_CALLBACK(enter_timeline_area), NULL);
816         g_signal_connect(timeline_drawing_area, "leave_notify_event", G_CALLBACK(leave_timeline_area), NULL);
817         gtk_widget_set_events(timeline_drawing_area, GDK_EXPOSURE_MASK
818                 | GDK_ENTER_NOTIFY_MASK
819                 | GDK_LEAVE_NOTIFY_MASK
820                 | GDK_BUTTON_PRESS_MASK
821                 | GDK_POINTER_MOTION_MASK
822                 | GDK_POINTER_MOTION_HINT_MASK);
823         gtk_widget_show(timeline_drawing_area);
824         timeline_scroll = gtk_scrolled_window_new(NULL, NULL);
825         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(timeline_scroll), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
826 //      gtk_widget_show(timeline_scroll);
827         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(timeline_scroll), timeline_drawing_area);
828         gtk_box_pack_start(GTK_BOX(vbox), timeline_scroll, FALSE, FALSE, 0);
829
830         create_timeline(NULL);
831
832         /* label */
833         img_label = GTK_LABEL(gtk_label_new(NULL));
834         gtk_widget_show(GTK_WIDGET(img_label));
835         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(img_label), FALSE, FALSE, 0);
836
837         /* show window */
838         gtk_widget_show(main_window);
839
840         if (argc > 1) {
841                 create_timeline(argv[1]);
842                 if (frame_list)
843                         create_image(frame_list[timeline_selected].filename, 1);
844         }
845
846         gtk_main();
847
848         // FIXME: destroy
849
850         return 0;
851 }
852