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