c6590f0a299060cb6514b85af49d5c5961198bb2
[colorize.git] / gui / timeline.c
1 #include <gtk/gtk.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <dirent.h> 
5 #include <stdio.h> 
6 #include "../src/mark.h"
7 #include "timeline.h"
8 #include "image.h"
9 #include "main.h"
10 #include "palette.h"
11 #include "../src/settings.h"
12 #include "../src/dir_seperator.h"
13 #ifdef WITH_OPENCV
14 #include "../src/opticalflow.h"
15 #endif
16
17 struct frame_list *frame_list = NULL;
18
19 /* currently loaded image */
20 GdkPixbuf *timeline_pixbuf = NULL;
21 int timeline_selected = 0;
22 int timeline_frames = 0;
23 int timeline_scale = 10;
24 int timeline_width, timeline_height = 30;
25
26 static void draw_timeline_frame(int frame)
27 {
28         int i, j, rs;
29         int r, g, b;
30         guchar *data;
31
32         if (!timeline_pixbuf)
33                 return;
34
35         if (frame == timeline_selected) {
36                 r = 150;
37                 g = 150;
38                 b = 150;
39                 if (frame_list && frame_list[frame].marked) {
40                         r = 100;
41                         g = 100;
42                         b = 200;
43                 }
44         } else {
45                 r = 100;
46                 g = 100;
47                 b = 100;
48                 if (frame_list && frame_list[frame].marked) {
49                         r = 0;
50                         g = 0;
51                         b = 100;
52                 }
53         }
54
55         data = gdk_pixbuf_get_pixels(timeline_pixbuf);
56         rs = gdk_pixbuf_get_rowstride(timeline_pixbuf);
57
58         for (i = 0; i < timeline_height; i++) {
59                 data[rs*i + frame*timeline_scale*3 + 0] = 0;
60                 data[rs*i + frame*timeline_scale*3 + 1] = 0;
61                 data[rs*i + frame*timeline_scale*3 + 2] = 0;
62                 for (j = 1; j < timeline_scale; j++) {
63                         data[rs*i + (frame*timeline_scale+j)*3 + 0] = r;
64                         data[rs*i + (frame*timeline_scale+j)*3 + 1] = g;
65                         data[rs*i + (frame*timeline_scale+j)*3 + 2] = b;
66                 }
67         }
68         if (frame_list && frame_list[frame].keyframe) {
69                 r = 255;
70                 g = 0;
71                 b = 0;
72                 for (i = 0; i < timeline_scale/2; i++) {
73                         for (j = i + 1; j < timeline_scale - i; j++) {
74                                 data[rs*i + (frame*timeline_scale+j)*3 + 0] = r;
75                                 data[rs*i + (frame*timeline_scale+j)*3 + 1] = g;
76                                 data[rs*i + (frame*timeline_scale+j)*3 + 2] = b;
77
78                                 data[rs*(timeline_height-1-i) + (frame*timeline_scale+j)*3 + 0] = r;
79                                 data[rs*(timeline_height-1-i) + (frame*timeline_scale+j)*3 + 1] = g;
80                                 data[rs*(timeline_height-1-i) + (frame*timeline_scale+j)*3 + 2] = b;
81                         }
82                 }
83         }
84 }
85
86 /* load directory and create pixbuf */
87 void create_timeline(const char *filename)
88 {
89         int i;
90         const char *p, *q;
91         char temp[256], name[256], suffix[256];
92         FILE *fp;
93
94         if (filename) {
95                 /* get suffix */
96                 p = filename;
97                 q = NULL;
98                 while ((q = strchr(p, '.')))
99                         p = q + 1;
100                 if (p == filename) {
101                         printerror("File '%s' does not have a 'prefix.suffix' format\n", filename);
102                         return;
103                 }
104                 strcpy(suffix, p - 1);
105
106 #ifndef WITH_MAGICK
107                 if ((strlen(filename) < 5 || !!strcmp(suffix, ".ppm"))) {
108                         printerror("File '%s' does not have '.ppm' suffix\n", filename);
109                         return;
110                 }
111 #endif
112         }
113
114         destroy_timeline();
115         timeline_frames = 0;
116
117         if (filename) {
118                 p = filename + strlen(filename) - strlen(suffix);
119                 while (p != filename) {
120                         p--;
121                         if (*p < '0' || *p > '9') {
122                                 p++;
123                                 break;
124                         }
125                 }
126                 if (*p < '0' || *p > '9') {
127 single_file:
128 //                      printf("single file\n");
129                         frame_list = malloc(sizeof(struct frame_list));
130                         memset(frame_list, 0, sizeof(struct frame_list));
131                         strcpy(frame_list[0].filename, filename);
132                         timeline_frames = 1;
133                 } else {
134                         /* calculate image file name */
135                         int digits = filename + strlen(filename) - strlen(suffix) - p;
136                         int start, count = 0;
137                         strncpy(temp, p, digits);
138                         temp[digits] = '\0';
139                         start = atoi(temp);
140 //                      printf("count digits=%s num=%d start=%d\n", temp, digits, start);
141                         strncpy(temp, filename, p - filename);
142                         temp[p - filename] = '\0';
143 //                      printf("prefix=%s\n", temp);
144                         sprintf(strchr(temp, '\0'), "%%0%dd%s", digits, suffix);
145 //                      printf("complete=%s\n", temp);
146                         /* look back for index */
147                         while (start > 0) {
148                                 sprintf(name, temp, start - 1);
149                                 fp = fopen(name, "r");
150                                 if (!fp)
151                                         break;
152                                 fclose(fp);
153                                 start--;
154                         }
155                         /* count forward index */
156                         for (i = start; ; i++) {
157                                 sprintf(name, temp, start + count);
158                                 fp = fopen(name, "r");
159                                 if (!fp)
160                                         break;
161                                 fclose(fp);
162                                 count++;
163                         }
164                         if (count == 0)
165                                 goto single_file;
166                         frame_list = malloc(sizeof(struct frame_list) * count);
167                         memset(frame_list, 0, sizeof(struct frame_list) * count);
168                         for (i = 0; i < count; i++) {
169                                 sprintf(frame_list[i].filename, temp, start + i);
170                         }
171                         timeline_frames = count;
172                 }
173                 /* get marked frames */
174                 for (i = 0; i < timeline_frames; i++) {
175                         sprintf(temp, "%s_marked", frame_list[i].filename);
176                         frame_list[i].marked = 0;
177                         fp = fopen(temp, "r");
178                         if (!fp)
179                                 continue;
180                         fclose(fp);
181                         frame_list[i].marked = 1;
182                 }
183                 /* get keyframes */
184                 load_sequence();
185         }
186
187         if (timeline_frames == 0)
188                 timeline_frames = 1;
189
190         if (timeline_frames > 1)
191                 gtk_widget_show(timeline_scroll);
192
193         timeline_width = timeline_frames * timeline_scale;
194
195         timeline_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, timeline_width, timeline_height);
196
197         for (i = 0; i < timeline_frames; i++)
198                 draw_timeline_frame(i);
199
200         gtk_widget_set_size_request(timeline_drawing_area, timeline_width, timeline_height);
201
202 #ifdef WITH_OPENCV
203         /* disable optical flow and set default */
204         flow_enable = 0;
205         flow_default();
206 #endif
207
208         if (frame_list) {
209                 int i;
210                 load_settings(frame_list[0].filename);
211                 load_palette(frame_list[0].filename);
212                 for (i = 0; i < 255; i++)
213                         update_color(i);
214         }
215 }
216
217 /* free image */
218 void destroy_timeline(void)
219 {
220         gtk_widget_hide(timeline_scroll);
221
222         if (!timeline_pixbuf)
223                 return;
224
225         g_object_unref(timeline_pixbuf);
226         timeline_pixbuf = NULL;
227
228         free(frame_list);
229         frame_list = NULL;
230
231         timeline_selected = 0;
232 }
233
234 /* draw (area) of pixbuf */
235 void draw_timeline(int x, int y, int w, int h)
236 {
237         GdkDrawable *draw = gtk_widget_get_window(timeline_drawing_area);
238
239         if (!timeline_pixbuf)
240                 return;
241
242         if (x < 0)
243                 x = 0;
244         if (x >= timeline_width)
245                 return;
246         if (y < 0)
247                 y = 0;
248         if (y >= timeline_height)
249                 return;
250         if (x + w > timeline_width)
251                 w = timeline_width - x;
252         if (y + h > timeline_height)
253                 h = timeline_height - y;
254
255         //printf("%d %d %d %d\n", x, y, w, h);
256
257         if (!timeline_pixbuf)
258                 return;
259
260         gdk_draw_pixbuf(draw, NULL, timeline_pixbuf, x, y, x, y, w, h, GDK_RGB_DITHER_NONE, 0, 0);
261 }
262
263 int timeline_select_and_save(int old_frame, int new_frame)
264 {
265
266         /* no frame loaded, no list */
267         if (!frame_list|| !img_pixbuf)
268                 return 0;
269
270         /* save all stuff */
271         if (anything_modified) {
272                 if (img_mark_buffer) {
273                         if (save_marked(img_mark_buffer, img_width, img_height, frame_list[old_frame].filename) > 0)
274                                 frame_list[old_frame].marked = 1;
275                         else
276                                 frame_list[old_frame].marked = 0;
277                 }
278
279                 if (frame_list) {
280                         save_palette(frame_list[0].filename);
281                         if (timeline_frames > 1)
282                                 save_settings(frame_list[0].filename);
283                         save_sequence();
284                 }
285         }
286
287         timeline_selected = new_frame;
288
289         create_image(frame_list[new_frame].filename, 0);
290 #ifdef WITH_OPENCV
291         if (flowview && flow_enable && img_grey_buffer)
292                 create_flow_view(
293                         (new_frame > 0) ? frame_list[new_frame - 1].filename : NULL,
294                         (new_frame < timeline_frames - 1) ? frame_list[new_frame + 1].filename : NULL,
295                         img_grey_buffer,
296                         img_width, img_height,
297                         flow_window,
298                         flow_view_vector,
299                         flow_view_uv);
300 #endif
301
302         if (timeline_frames > 1) {
303                 GdkDrawable *draw = gtk_widget_get_window(timeline_drawing_area);
304                 draw_timeline_frame(old_frame);
305                 draw_timeline_frame(new_frame);
306                 gdk_draw_pixbuf(draw, NULL, timeline_pixbuf, 0, 0, 0, 0, timeline_width, timeline_height, GDK_RGB_DITHER_NONE, 0, 0);
307         }
308
309         /* adjust position of timeline scroll */
310         int w, x;
311         GtkAdjustment *adjustment;
312         double pos;
313         x = new_frame * timeline_scale;
314         w = timeline_scroll->allocation.width - timeline_scale - 4;
315         adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(timeline_scroll));
316         pos = gtk_adjustment_get_value(adjustment);
317         if (x < pos) {
318                 gtk_adjustment_set_value(adjustment, x);
319                 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(timeline_scroll), adjustment);
320         }
321         if (x > pos + w) {
322                 gtk_adjustment_set_value(adjustment, pos + x + - (pos + w));
323                 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(timeline_scroll), adjustment);
324         }
325
326         return 1;
327 }
328
329 /* while pointing at timeline, show current frame that we point to */
330 int timeline_point(int x, int y)
331 {
332         int frame = x / timeline_scale;
333
334         if (x < 0 || y < 0 || frame < 0 || frame >= timeline_frames) {
335                 timeline_show_name(timeline_selected);
336                 return 0;
337         }
338         
339         timeline_show_name(frame);
340         return 0;
341 }
342
343 void timeline_show_name(int frame)
344 {
345         char text[256];
346         const char *p;
347
348         if (!frame_list)
349                 return;
350
351         if (frame != timeline_selected) {
352                 sprintf(text, "Click to select frame %d", frame);
353         } else {
354                 p = frame_list[frame].filename;
355                 while (strchr(p, DIR_SEPERATOR))
356                         p = strchr(p, DIR_SEPERATOR) + 1;
357                 if (timeline_frames > 1)
358                         sprintf(text, "Frame %d: %s", frame, p);
359                 else
360                         strcpy(text, p);
361                 if (img_scale_x != 16)
362                         sprintf(strchr(text, '\0'), " (%d%%)", img_scale_x*100/16);
363         }
364         gtk_label_set_text(img_label, text);
365 }
366
367 int timeline_clicked(int x, int y)
368 {
369         int old_frame = timeline_selected;
370         int new_frame = x / timeline_scale;
371
372         if (new_frame < 0)
373                 return 0;
374         if (new_frame >= timeline_frames)
375                 return 0;
376
377         if (old_frame == new_frame)
378                 return 0;
379
380         return timeline_select_and_save(old_frame, new_frame);
381
382 }
383
384 /* get filename of first grey image directory */
385 static char *get_filename(const char *filename)
386 {
387         static char name[256];
388
389         /* copy name */
390         strcpy(name, filename);
391         /* remove until DIR_SEPERATOR */
392         while (name[0]) {
393                 if (name[strlen(name) - 1] == DIR_SEPERATOR)
394                         break;
395                 name[strlen(name) - 1] = '\0';
396         }
397         /* add palette name */
398         strcat(name, "sequence");
399
400         return name;
401 }
402
403 int save_sequence(void)
404 {
405         char *name, *p;
406         int i;
407         FILE *fp;
408
409         if (!frame_list)
410                 return 0;
411
412         if (timeline_frames <= 1)
413                 return 0;
414
415         name = get_filename(frame_list[0].filename);
416 //      printf("save sequence '%s'\n", name);
417         fp = fopen(name, "w");
418         if (!fp) {
419                 printf("failed to save sequence '%s'\n", name);
420                 return -1;
421         }
422         for (i = 0; i < timeline_frames; i++) {
423                 p = frame_list[i].filename;
424                 while (p && strchr(p, DIR_SEPERATOR))
425                         p = strchr(p, DIR_SEPERATOR) + 1;
426                 fprintf(fp, "\"%s\"%s\n", p, (frame_list[i].keyframe) ? " keyframe" : "");
427         }
428         fclose(fp);
429
430         return 1;
431 }
432
433 int load_sequence(void)
434 {
435         char *name;
436         char buffer[256];
437         FILE *fp;
438         int i;
439         char *rc, *p;
440
441         if (!frame_list)
442                 return 0;
443
444         if (timeline_frames <= 1)
445                 return 0;
446
447         name = get_filename(frame_list[0].filename);
448 //      printf("load sequence '%s'\n", name);
449         fp = fopen(name, "r");
450         if (!fp) {
451                 printf("failed to load sequence '%s'\n", name);
452                 return -1;
453         }
454         for (i = 0; i < timeline_frames; i++) {
455                 rc = fgets(buffer, sizeof(buffer), fp);
456                 if (!rc)
457                         break;
458                 p = strchr(buffer + 1, '\"');
459                 if (!p)
460                         break;
461                 p++;
462                 if (strstr(p, "keyframe"))
463                         frame_list[i].keyframe = 1;
464                 else
465                         frame_list[i].keyframe = 0;
466         }
467         fclose(fp);
468
469         return 0;
470 }
471
472 void toggle_keyframe(void)
473 {
474         if (!frame_list|| !img_pixbuf)
475                 return;
476
477         anything_modified = 1;
478         
479         GdkDrawable *draw = gtk_widget_get_window(timeline_drawing_area);
480
481         frame_list[timeline_selected].keyframe = 1 - frame_list[timeline_selected].keyframe;
482         draw_timeline_frame(timeline_selected);
483         gdk_draw_pixbuf(draw, NULL, timeline_pixbuf, 0, 0, 0, 0, timeline_width, timeline_height, GDK_RGB_DITHER_NONE, 0, 0);
484 }
485