gqview.h -> main.h
[geeqie.git] / src / pan-folder.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12
13 #include "main.h"
14 #include "pan-types.h"
15
16 #include <math.h>
17
18
19 static void pan_flower_size(PanWindow *pw, gint *width, gint *height)
20 {
21         GList *work;
22         gint x1, y1, x2, y2;
23
24         x1 = 0;
25         y1 = 0;
26         x2 = 0;
27         y2 = 0;
28
29         work = pw->list;
30         while (work)
31                 {
32                 PanItem *pi;
33
34                 pi = work->data;
35                 work = work->next;
36
37                 if (x1 > pi->x) x1 = pi->x;
38                 if (y1 > pi->y) y1 = pi->y;
39                 if (x2 < pi->x + pi->width) x2 = pi->x + pi->width;
40                 if (y2 < pi->y + pi->height) y2 = pi->y + pi->height;
41                 }
42
43         x1 -= PAN_BOX_BORDER;
44         y1 -= PAN_BOX_BORDER;
45         x2 += PAN_BOX_BORDER;
46         y2 += PAN_BOX_BORDER;
47
48         work = pw->list;
49         while (work)
50                 {
51                 PanItem *pi;
52
53                 pi = work->data;
54                 work = work->next;
55
56                 pi->x -= x1;
57                 pi->y -= y1;
58
59                 if (pi->type == PAN_ITEM_TRIANGLE && pi->data)
60                         {
61                         gint *coord;
62
63                         coord = pi->data;
64                         coord[0] -= x1;
65                         coord[1] -= y1;
66                         coord[2] -= x1;
67                         coord[3] -= y1;
68                         coord[4] -= x1;
69                         coord[5] -= y1;
70                         }
71                 }
72
73         if (width) *width = x2 - x1;
74         if (height) *height = y2 - y1;
75 }
76
77 typedef struct _FlowerGroup FlowerGroup;
78 struct _FlowerGroup {
79         GList *items;
80         GList *children;
81         gint x;
82         gint y;
83         gint width;
84         gint height;
85
86         gdouble angle;
87         gint circumference;
88         gint diameter;
89 };
90
91 static void pan_flower_move(FlowerGroup *group, gint x, gint y)
92 {
93         GList *work;
94
95         work = group->items;
96         while (work)
97                 {
98                 PanItem *pi;
99
100                 pi = work->data;
101                 work = work->next;
102
103                 pi->x += x;
104                 pi->y += y;
105                 }
106
107         group->x += x;
108         group->y += y;
109 }
110
111 #define PI 3.14159
112
113 static void pan_flower_position(FlowerGroup *group, FlowerGroup *parent,
114                                                              gint *result_x, gint *result_y)
115 {
116         gint x, y;
117         gint radius;
118         gdouble a;
119
120         radius = parent->circumference / (2*PI);
121         radius = MAX(radius, parent->diameter / 2 + group->diameter / 2);
122
123         a = 2*PI * group->diameter / parent->circumference;
124
125         x = (gint)((double)radius * cos(parent->angle + a / 2));
126         y = (gint)((double)radius * sin(parent->angle + a / 2));
127
128         parent->angle += a;
129
130         x += parent->x;
131         y += parent->y;
132
133         x += parent->width / 2;
134         y += parent->height / 2;
135
136         x -= group->width / 2;
137         y -= group->height / 2;
138
139         *result_x = x;
140         *result_y = y;
141 }
142
143 static void pan_flower_build(PanWindow *pw, FlowerGroup *group, FlowerGroup *parent)
144 {
145         GList *work;
146         gint x, y;
147
148         if (!group) return;
149
150         if (parent && parent->children)
151                 {
152                 pan_flower_position(group, parent, &x, &y);
153                 }
154         else
155                 {
156                 x = 0;
157                 y = 0;
158                 }
159
160         pan_flower_move(group, x, y);
161
162         if (parent)
163                 {
164                 PanItem *pi;
165                 gint px, py, gx, gy;
166                 gint x1, y1, x2, y2;
167
168                 px = parent->x + parent->width / 2;
169                 py = parent->y + parent->height / 2;
170
171                 gx = group->x + group->width / 2;
172                 gy = group->y + group->height / 2;
173
174                 x1 = MIN(px, gx);
175                 y1 = MIN(py, gy);
176
177                 x2 = MAX(px, gx + 5);
178                 y2 = MAX(py, gy + 5);
179
180                 pi = pan_item_tri_new(pw, NULL, x1, y1, x2 - x1, y2 - y1,
181                                       px, py, gx, gy, gx + 5, gy + 5,
182                                       255, 40, 40, 128);
183                 pan_item_tri_border(pi, PAN_BORDER_1 | PAN_BORDER_3,
184                                     255, 0, 0, 128);
185                 }
186
187         pw->list = g_list_concat(group->items, pw->list);
188         group->items = NULL;
189
190         group->circumference = 0;
191         work = group->children;
192         while (work)
193                 {
194                 FlowerGroup *child;
195
196                 child = work->data;
197                 work = work->next;
198
199                 group->circumference += child->diameter;
200                 }
201
202         work = g_list_last(group->children);
203         while (work)
204                 {
205                 FlowerGroup *child;
206
207                 child = work->data;
208                 work = work->prev;
209
210                 pan_flower_build(pw, child, group);
211                 }
212
213         g_list_free(group->children);
214         g_free(group);
215 }
216
217 static FlowerGroup *pan_flower_group(PanWindow *pw, const gchar *path, gint x, gint y)
218 {
219         FlowerGroup *group;
220         GList *f;
221         GList *d;
222         GList *work;
223         PanItem *pi_box;
224         gint x_start;
225         gint y_height;
226         gint grid_size;
227         gint grid_count;
228
229         if (!filelist_read(path, &f, &d)) return NULL;
230         if (!f && !d) return NULL;
231
232         f = filelist_sort(f, SORT_NAME, TRUE);
233         d = filelist_sort(d, SORT_NAME, TRUE);
234
235         pi_box = pan_item_text_new(pw, x, y, path, PAN_TEXT_ATTR_NONE,
236                                    PAN_TEXT_BORDER_SIZE,
237                                    PAN_TEXT_COLOR, 255);
238
239         y += pi_box->height;
240
241         pi_box = pan_item_box_new(pw, file_data_new_simple(path),
242                                   x, y,
243                                   PAN_BOX_BORDER * 2, PAN_BOX_BORDER * 2,
244                                   PAN_BOX_OUTLINE_THICKNESS,
245                                   PAN_BOX_COLOR, PAN_BOX_ALPHA,
246                                   PAN_BOX_OUTLINE_COLOR, PAN_BOX_OUTLINE_ALPHA);
247
248         x += PAN_BOX_BORDER;
249         y += PAN_BOX_BORDER;
250
251         grid_size = (gint)(sqrt(g_list_length(f)) + 0.9);
252         grid_count = 0;
253         x_start = x;
254         y_height = y;
255
256         work = f;
257         while (work)
258                 {
259                 FileData *fd;
260                 PanItem *pi;
261
262                 fd = work->data;
263                 work = work->next;
264
265                 if (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE)
266                         {
267                         pi = pan_item_image_new(pw, fd, x, y, 10, 10);
268                         x += pi->width + PAN_THUMB_GAP;
269                         if (pi->height > y_height) y_height = pi->height;
270                         }
271                 else
272                         {
273                         pi = pan_item_thumb_new(pw, fd, x, y);
274                         x += PAN_THUMB_SIZE + PAN_THUMB_GAP;
275                         y_height = PAN_THUMB_SIZE;
276                         }
277
278                 grid_count++;
279                 if (grid_count >= grid_size)
280                         {
281                         grid_count = 0;
282                         x = x_start;
283                         y += y_height + PAN_THUMB_GAP;
284                         y_height = 0;
285                         }
286
287                 pan_item_size_by_item(pi_box, pi, PAN_BOX_BORDER);
288                 }
289
290         group = g_new0(FlowerGroup, 1);
291         group->items = pw->list;
292         pw->list = NULL;
293
294         group->width = pi_box->width;
295         group->height = pi_box->y + pi_box->height;
296         group->diameter = (int)sqrt(group->width * group->width + group->height * group->height);
297
298         group->children = NULL;
299
300         work = d;
301         while (work)
302                 {
303                 FileData *fd;
304                 FlowerGroup *child;
305
306                 fd = work->data;
307                 work = work->next;
308
309                 if (!pan_is_ignored(fd->path, pw->ignore_symlinks))
310                         {
311                         child = pan_flower_group(pw, fd->path, 0, 0);
312                         if (child) group->children = g_list_prepend(group->children, child);
313                         }
314                 }
315
316         if (!f && !group->children)
317                 {
318                 work = group->items;
319                 while (work)
320                         {
321                         PanItem *pi;
322
323                         pi = work->data;
324                         work = work->next;
325
326                         pan_item_free(pi);
327                         }
328
329                 g_list_free(group->items);
330                 g_free(group);
331                 group = NULL;
332                 }
333
334         g_list_free(f);
335         filelist_free(d);
336
337         return group;
338 }
339
340 void pan_flower_compute(PanWindow *pw, const gchar *path,
341                         gint *width, gint *height,
342                         gint *scroll_x, gint *scroll_y)
343 {
344         FlowerGroup *group;
345         GList *list;
346
347         group = pan_flower_group(pw, path, 0, 0);
348         pan_flower_build(pw, group, NULL);
349
350         pan_flower_size(pw, width, height);
351
352         list = pan_item_find_by_path(pw, PAN_ITEM_BOX, path, FALSE, FALSE);
353         if (list)
354                 {
355                 PanItem *pi = list->data;
356                 *scroll_x = pi->x + pi->width / 2;
357                 *scroll_y = pi->y + pi->height / 2;
358                 }
359         g_list_free(list);
360 }
361
362 static void pan_folder_tree_path(PanWindow *pw, const gchar *path,
363                                  gint *x, gint *y, gint *level,
364                                  PanItem *parent,
365                                  gint *width, gint *height)
366 {
367         GList *f;
368         GList *d;
369         GList *work;
370         PanItem *pi_box;
371         gint y_height = 0;
372
373         if (!filelist_read(path, &f, &d)) return;
374         if (!f && !d) return;
375
376         f = filelist_sort(f, SORT_NAME, TRUE);
377         d = filelist_sort(d, SORT_NAME, TRUE);
378
379         *x = PAN_BOX_BORDER + ((*level) * MAX(PAN_BOX_BORDER, PAN_THUMB_GAP));
380
381         pi_box = pan_item_text_new(pw, *x, *y, path, PAN_TEXT_ATTR_NONE,
382                                    PAN_TEXT_BORDER_SIZE,
383                                    PAN_TEXT_COLOR, 255);
384
385         *y += pi_box->height;
386
387         pi_box = pan_item_box_new(pw, file_data_new_simple(path),
388                                   *x, *y,
389                                   PAN_BOX_BORDER, PAN_BOX_BORDER,
390                                   PAN_BOX_OUTLINE_THICKNESS,
391                                   PAN_BOX_COLOR, PAN_BOX_ALPHA,
392                                   PAN_BOX_OUTLINE_COLOR, PAN_BOX_OUTLINE_ALPHA);
393
394         *x += PAN_BOX_BORDER;
395         *y += PAN_BOX_BORDER;
396
397         work = f;
398         while (work)
399                 {
400                 FileData *fd;
401                 PanItem *pi;
402
403                 fd = work->data;
404                 work = work->next;
405
406                 if (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE)
407                         {
408                         pi = pan_item_image_new(pw, fd, *x, *y, 10, 10);
409                         *x += pi->width + PAN_THUMB_GAP;
410                         if (pi->height > y_height) y_height = pi->height;
411                         }
412                 else
413                         {
414                         pi = pan_item_thumb_new(pw, fd, *x, *y);
415                         *x += PAN_THUMB_SIZE + PAN_THUMB_GAP;
416                         y_height = PAN_THUMB_SIZE;
417                         }
418
419                 pan_item_size_by_item(pi_box, pi, PAN_BOX_BORDER);
420                 }
421
422         if (f) *y = pi_box->y + pi_box->height;
423
424         g_list_free(f);
425
426         work = d;
427         while (work)
428                 {
429                 FileData *fd;
430
431                 fd = work->data;
432                 work = work->next;
433
434                 if (!pan_is_ignored(fd->path, pw->ignore_symlinks))
435                         {
436                         *level = *level + 1;
437                         pan_folder_tree_path(pw, fd->path, x, y, level, pi_box, width, height);
438                         *level = *level - 1;
439                         }
440                 }
441
442         filelist_free(d);
443
444         pan_item_size_by_item(parent, pi_box, PAN_BOX_BORDER);
445
446         if (*y < pi_box->y + pi_box->height + PAN_BOX_BORDER)
447                 *y = pi_box->y + pi_box->height + PAN_BOX_BORDER;
448
449         pan_item_size_coordinates(pi_box, PAN_BOX_BORDER, width, height);
450 }
451
452 void pan_folder_tree_compute(PanWindow *pw, const gchar *path, gint *width, gint *height)
453 {
454         gint x, y;
455         gint level;
456         gint w, h;
457
458         level = 0;
459         x = PAN_BOX_BORDER;
460         y = PAN_BOX_BORDER;
461         w = PAN_BOX_BORDER * 2;
462         h = PAN_BOX_BORDER * 2;
463
464         pan_folder_tree_path(pw, path, &x, &y, &level, NULL, &w, &h);
465
466         if (width) *width = w;
467         if (height) *height = h;
468 }
469
470