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