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