Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_file / space_file.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_file/space_file.c
28  *  \ingroup spfile
29  */
30
31 #include <string.h>
32 #include <stdio.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BIF_gl.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_fileops_types.h"
41
42
43 #include "BKE_appdir.h"
44 #include "BKE_context.h"
45 #include "BKE_screen.h"
46 #include "BKE_global.h"
47
48 #include "RNA_access.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52 #include "WM_message.h"
53
54 #include "ED_space_api.h"
55 #include "ED_screen.h"
56 #include "ED_fileselect.h"
57
58 #include "IMB_imbuf_types.h"
59 #include "IMB_thumbs.h"
60
61 #include "UI_resources.h"
62 #include "UI_view2d.h"
63
64
65 #include "file_intern.h"    // own include
66 #include "fsmenu.h"
67 #include "filelist.h"
68 #include "GPU_framebuffer.h"
69
70 /* ******************** default callbacks for file space ***************** */
71
72 static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
73 {
74         ARegion *ar;
75         SpaceFile *sfile;
76
77         sfile = MEM_callocN(sizeof(SpaceFile), "initfile");
78         sfile->spacetype = SPACE_FILE;
79
80         /* header */
81         ar = MEM_callocN(sizeof(ARegion), "header for file");
82         BLI_addtail(&sfile->regionbase, ar);
83         ar->regiontype = RGN_TYPE_HEADER;
84         ar->alignment = RGN_ALIGN_TOP;
85
86         /* Tools region */
87         ar = MEM_callocN(sizeof(ARegion), "tools region for file");
88         BLI_addtail(&sfile->regionbase, ar);
89         ar->regiontype = RGN_TYPE_TOOLS;
90         ar->alignment = RGN_ALIGN_LEFT;
91
92         /* Tool props (aka operator) region */
93         ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
94         BLI_addtail(&sfile->regionbase, ar);
95         ar->regiontype = RGN_TYPE_TOOL_PROPS;
96         ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
97
98         /* ui list region */
99         ar = MEM_callocN(sizeof(ARegion), "ui region for file");
100         BLI_addtail(&sfile->regionbase, ar);
101         ar->regiontype = RGN_TYPE_UI;
102         ar->alignment = RGN_ALIGN_TOP;
103
104         /* main region */
105         ar = MEM_callocN(sizeof(ARegion), "main region for file");
106         BLI_addtail(&sfile->regionbase, ar);
107         ar->regiontype = RGN_TYPE_WINDOW;
108         ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
109         ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
110         ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
111         ar->v2d.keeptot = V2D_KEEPTOT_STRICT;
112         ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f;
113
114         return (SpaceLink *)sfile;
115 }
116
117 /* not spacelink itself */
118 static void file_free(SpaceLink *sl)
119 {
120         SpaceFile *sfile = (SpaceFile *) sl;
121
122         BLI_assert(sfile->previews_timer == NULL);
123
124         if (sfile->files) {
125                 // XXXXX would need to do thumbnails_stop here, but no context available
126                 filelist_freelib(sfile->files);
127                 filelist_free(sfile->files);
128                 MEM_freeN(sfile->files);
129                 sfile->files = NULL;
130         }
131
132         if (sfile->folders_prev) {
133                 folderlist_free(sfile->folders_prev);
134                 MEM_freeN(sfile->folders_prev);
135                 sfile->folders_prev = NULL;
136         }
137
138         if (sfile->folders_next) {
139                 folderlist_free(sfile->folders_next);
140                 MEM_freeN(sfile->folders_next);
141                 sfile->folders_next = NULL;
142         }
143
144         if (sfile->params) {
145                 MEM_freeN(sfile->params);
146                 sfile->params = NULL;
147         }
148
149         if (sfile->layout) {
150                 MEM_freeN(sfile->layout);
151                 sfile->layout = NULL;
152         }
153 }
154
155
156 /* spacetype; init callback, area size changes, screen set, etc */
157 static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
158 {
159         SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
160
161         /* refresh system directory list */
162         fsmenu_refresh_system_category(ED_fsmenu_get());
163
164         /* Update bookmarks 'valid' state.
165          * Done here, because it seems BLI_is_dir() can have huge impact on performances
166          * in some cases, on win systems... See T43684.
167          */
168         fsmenu_refresh_bookmarks_status(ED_fsmenu_get());
169
170         if (sfile->layout) sfile->layout->dirty = true;
171 }
172
173 static void file_exit(wmWindowManager *wm, ScrArea *sa)
174 {
175         SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
176
177         if (sfile->previews_timer) {
178                 WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer);
179                 sfile->previews_timer = NULL;
180         }
181
182         ED_fileselect_exit(wm, sa, sfile);
183 }
184
185 static SpaceLink *file_duplicate(SpaceLink *sl)
186 {
187         SpaceFile *sfileo = (SpaceFile *)sl;
188         SpaceFile *sfilen = MEM_dupallocN(sl);
189
190         /* clear or remove stuff from old */
191         sfilen->op = NULL; /* file window doesn't own operators */
192
193         sfilen->previews_timer = NULL;
194         sfilen->smoothscroll_timer = NULL;
195
196         if (sfileo->params) {
197                 sfilen->files = filelist_new(sfileo->params->type);
198                 sfilen->params = MEM_dupallocN(sfileo->params);
199                 filelist_setdir(sfilen->files, sfilen->params->dir);
200         }
201
202         if (sfileo->folders_prev)
203                 sfilen->folders_prev = folderlist_duplicate(sfileo->folders_prev);
204
205         if (sfileo->folders_next)
206                 sfilen->folders_next = folderlist_duplicate(sfileo->folders_next);
207
208         if (sfileo->layout) {
209                 sfilen->layout = MEM_dupallocN(sfileo->layout);
210         }
211         return (SpaceLink *)sfilen;
212 }
213
214 static void file_refresh(const bContext *C, ScrArea *sa)
215 {
216         wmWindowManager *wm = CTX_wm_manager(C);
217         SpaceFile *sfile = CTX_wm_space_file(C);
218         FileSelectParams *params = ED_fileselect_get_params(sfile);
219         struct FSMenu *fsmenu = ED_fsmenu_get();
220
221         if (!sfile->folders_prev) {
222                 sfile->folders_prev = folderlist_new();
223         }
224         if (!sfile->files) {
225                 sfile->files = filelist_new(params->type);
226                 params->highlight_file = -1; /* added this so it opens nicer (ton) */
227         }
228         filelist_setdir(sfile->files, params->dir);
229         filelist_setrecursion(sfile->files, params->recursion_level);
230         filelist_setsorting(sfile->files, params->sort);
231         filelist_setfilter_options(sfile->files, (params->flag & FILE_FILTER) != 0,
232                                                  (params->flag & FILE_HIDE_DOT) != 0,
233                                                  false, /* TODO hide_parent, should be controllable? */
234                                                  params->filter,
235                                                  params->filter_id,
236                                                  params->filter_glob,
237                                                  params->filter_search);
238
239         /* Update the active indices of bookmarks & co. */
240         sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
241         sfile->system_bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, params->dir);
242         sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir);
243         sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir);
244
245         if (filelist_force_reset(sfile->files)) {
246                 filelist_readjob_stop(wm, sa);
247                 filelist_clear(sfile->files);
248         }
249
250         if (filelist_empty(sfile->files)) {
251                 if (!filelist_pending(sfile->files)) {
252                         filelist_readjob_start(sfile->files, C);
253                 }
254         }
255
256         filelist_sort(sfile->files);
257         filelist_filter(sfile->files);
258
259         if (params->display == FILE_IMGDISPLAY) {
260                 filelist_cache_previews_set(sfile->files, true);
261         }
262         else {
263                 filelist_cache_previews_set(sfile->files, false);
264                 if (sfile->previews_timer) {
265                         WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer);
266                         sfile->previews_timer = NULL;
267                 }
268         }
269
270         if (params->renamefile[0] != '\0') {
271                 int idx = filelist_file_findpath(sfile->files, params->renamefile);
272                 if (idx >= 0) {
273                         FileDirEntry *file = filelist_file(sfile->files, idx);
274                         if (file) {
275                                 filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
276                         }
277                 }
278                 BLI_strncpy(sfile->params->renameedit, sfile->params->renamefile, sizeof(sfile->params->renameedit));
279                 /* File listing is now async, do not clear renamefile if matching entry not found
280                  * and dirlist is not finished! */
281                 if (idx >= 0 || filelist_is_ready(sfile->files)) {
282                         params->renamefile[0] = '\0';
283                 }
284         }
285
286         if (sfile->layout) {
287                 sfile->layout->dirty = true;
288         }
289
290         /* Might be called with NULL sa, see file_main_region_draw() below. */
291         if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
292                 /* Create TOOLS/TOOL_PROPS regions. */
293                 file_tools_region(sa);
294
295                 ED_area_initialize(wm, CTX_wm_window(C), sa);
296         }
297
298         ED_area_tag_redraw(sa);
299 }
300
301 static void file_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
302 {
303         SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
304
305         /* context changes */
306         switch (wmn->category) {
307                 case NC_SPACE:
308                         switch (wmn->data) {
309                                 case ND_SPACE_FILE_LIST:
310                                         ED_area_tag_refresh(sa);
311                                         break;
312                                 case ND_SPACE_FILE_PARAMS:
313                                         ED_area_tag_refresh(sa);
314                                         break;
315                                 case ND_SPACE_FILE_PREVIEW:
316                                         if (sfile->files && filelist_cache_previews_update(sfile->files)) {
317                                                 ED_area_tag_refresh(sa);
318                                         }
319                                         break;
320                         }
321                         break;
322         }
323 }
324
325 /* add handlers, stuff you only do once or on area/region changes */
326 static void file_main_region_init(wmWindowManager *wm, ARegion *ar)
327 {
328         wmKeyMap *keymap;
329
330         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
331
332         /* own keymaps */
333         keymap = WM_keymap_find(wm->defaultconf, "File Browser", SPACE_FILE, 0);
334         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
335
336         keymap = WM_keymap_find(wm->defaultconf, "File Browser Main", SPACE_FILE, 0);
337         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
338 }
339
340 static void file_main_region_listener(
341         wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
342         wmNotifier *wmn, const Scene *UNUSED(scene))
343 {
344         /* context changes */
345         switch (wmn->category) {
346                 case NC_SPACE:
347                         switch (wmn->data) {
348                                 case ND_SPACE_FILE_LIST:
349                                         ED_region_tag_redraw(ar);
350                                         break;
351                                 case ND_SPACE_FILE_PARAMS:
352                                         ED_region_tag_redraw(ar);
353                                         break;
354                         }
355                         break;
356         }
357 }
358
359 static void file_main_region_message_subscribe(
360         const struct bContext *UNUSED(C),
361         struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
362         struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
363         struct wmMsgBus *mbus)
364 {
365         SpaceFile *sfile = sa->spacedata.first;
366         FileSelectParams *params = ED_fileselect_get_params(sfile);
367         /* This is a bit odd that a region owns the subscriber for an area,
368          * keep for now since all subscribers for WM are regions.
369          * May be worth re-visiting later. */
370         wmMsgSubscribeValue msg_sub_value_area_tag_refresh = {
371                 .owner = ar,
372                 .user_data = sa,
373                 .notify = ED_area_do_msg_notify_tag_refresh,
374         };
375
376         /* SpaceFile itself. */
377         {
378                 PointerRNA ptr;
379                 RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr);
380
381                 /* All properties for this space type. */
382                 WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
383         }
384
385         /* FileSelectParams */
386         {
387                 PointerRNA ptr;
388                 RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr);
389
390                 /* All properties for this space type. */
391                 WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
392         }
393 }
394
395 static void file_main_region_draw(const bContext *C, ARegion *ar)
396 {
397         /* draw entirely, view changes should be handled here */
398         SpaceFile *sfile = CTX_wm_space_file(C);
399         FileSelectParams *params = ED_fileselect_get_params(sfile);
400
401         View2D *v2d = &ar->v2d;
402         View2DScrollers *scrollers;
403         float col[3];
404
405         /* Needed, because filelist is not initialized on loading */
406         if (!sfile->files || filelist_empty(sfile->files))
407                 file_refresh(C, NULL);
408
409         /* clear and setup matrix */
410         UI_GetThemeColor3fv(TH_BACK, col);
411         GPU_clear_color(col[0], col[1], col[2], 0.0);
412         GPU_clear(GPU_COLOR_BIT);
413
414         /* Allow dynamically sliders to be set, saves notifiers etc. */
415
416         if (params->display == FILE_IMGDISPLAY) {
417                 v2d->scroll = V2D_SCROLL_RIGHT;
418                 v2d->keepofs &= ~V2D_LOCKOFS_Y;
419                 v2d->keepofs |= V2D_LOCKOFS_X;
420         }
421         else {
422                 v2d->scroll = V2D_SCROLL_BOTTOM;
423                 v2d->keepofs &= ~V2D_LOCKOFS_X;
424                 v2d->keepofs |= V2D_LOCKOFS_Y;
425
426                 /* XXX this happens on scaling down Screen (like from startup.blend) */
427                 /* view2d has no type specific for filewindow case, which doesnt scroll vertically */
428                 if (v2d->cur.ymax < 0) {
429                         v2d->cur.ymin -= v2d->cur.ymax;
430                         v2d->cur.ymax = 0;
431                 }
432         }
433         /* v2d has initialized flag, so this call will only set the mask correct */
434         UI_view2d_region_reinit(v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
435
436         /* sets tile/border settings in sfile */
437         file_calc_previews(C, ar);
438
439         /* set view */
440         UI_view2d_view_ortho(v2d);
441
442         /* on first read, find active file */
443         if (params->highlight_file == -1) {
444                 wmEvent *event = CTX_wm_window(C)->eventstate;
445                 file_highlight_set(sfile, ar, event->x, event->y);
446         }
447
448         file_draw_list(C, ar);
449
450         /* reset view matrix */
451         UI_view2d_view_restore(C);
452
453         /* scrollers */
454         scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
455         UI_view2d_scrollers_draw(C, v2d, scrollers);
456         UI_view2d_scrollers_free(scrollers);
457
458 }
459
460 static void file_operatortypes(void)
461 {
462         WM_operatortype_append(FILE_OT_select);
463         WM_operatortype_append(FILE_OT_select_walk);
464         WM_operatortype_append(FILE_OT_select_all);
465         WM_operatortype_append(FILE_OT_select_border);
466         WM_operatortype_append(FILE_OT_select_bookmark);
467         WM_operatortype_append(FILE_OT_highlight);
468         WM_operatortype_append(FILE_OT_execute);
469         WM_operatortype_append(FILE_OT_cancel);
470         WM_operatortype_append(FILE_OT_parent);
471         WM_operatortype_append(FILE_OT_previous);
472         WM_operatortype_append(FILE_OT_next);
473         WM_operatortype_append(FILE_OT_refresh);
474         WM_operatortype_append(FILE_OT_bookmark_toggle);
475         WM_operatortype_append(FILE_OT_bookmark_add);
476         WM_operatortype_append(FILE_OT_bookmark_delete);
477         WM_operatortype_append(FILE_OT_bookmark_cleanup);
478         WM_operatortype_append(FILE_OT_bookmark_move);
479         WM_operatortype_append(FILE_OT_reset_recent);
480         WM_operatortype_append(FILE_OT_hidedot);
481         WM_operatortype_append(FILE_OT_filenum);
482         WM_operatortype_append(FILE_OT_directory_new);
483         WM_operatortype_append(FILE_OT_delete);
484         WM_operatortype_append(FILE_OT_rename);
485         WM_operatortype_append(FILE_OT_smoothscroll);
486         WM_operatortype_append(FILE_OT_filepath_drop);
487 }
488
489 /* NOTE: do not add .blend file reading on this level */
490 static void file_keymap(struct wmKeyConfig *keyconf)
491 {
492         wmKeyMapItem *kmi;
493         /* keys for all regions */
494         wmKeyMap *keymap = WM_keymap_find(keyconf, "File Browser", SPACE_FILE, 0);
495
496         /* More common 'fliebrowser-like navigation' shortcuts. */
497         WM_keymap_add_item(keymap, "FILE_OT_parent", UPARROWKEY, KM_PRESS, KM_ALT, 0);
498         WM_keymap_add_item(keymap, "FILE_OT_previous", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
499         WM_keymap_add_item(keymap, "FILE_OT_next", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
500         WM_keymap_add_item(keymap, "FILE_OT_refresh", RKEY, KM_PRESS, 0, 0);
501
502         WM_keymap_add_item(keymap, "FILE_OT_parent", PKEY, KM_PRESS, 0, 0);
503         WM_keymap_add_item(keymap, "FILE_OT_previous", BACKSPACEKEY, KM_PRESS, 0, 0);
504         WM_keymap_add_item(keymap, "FILE_OT_next", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0);
505         kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", HKEY, KM_PRESS, 0, 0);
506         RNA_string_set(kmi->ptr, "data_path", "space_data.params.show_hidden");
507         WM_keymap_add_item(keymap, "FILE_OT_directory_new", IKEY, KM_PRESS, 0, 0);
508
509         WM_keymap_add_item(keymap, "FILE_OT_delete", XKEY, KM_PRESS, 0, 0);
510         WM_keymap_add_item(keymap, "FILE_OT_delete", DELKEY, KM_PRESS, 0, 0);
511
512         WM_keymap_verify_item(keymap, "FILE_OT_smoothscroll", TIMER1, KM_ANY, KM_ANY, 0);
513
514         WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", TKEY, KM_PRESS, 0, 0);
515         WM_keymap_add_item(keymap, "FILE_OT_bookmark_add", BKEY, KM_PRESS, KM_CTRL, 0);
516
517         /* keys for main region */
518         keymap = WM_keymap_find(keyconf, "File Browser Main", SPACE_FILE, 0);
519         kmi = WM_keymap_add_item(keymap, "FILE_OT_execute", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
520         RNA_boolean_set(kmi->ptr, "need_active", true);
521
522         WM_keymap_add_item(keymap, "FILE_OT_refresh", PADPERIOD, KM_PRESS, 0, 0);
523
524         /* left mouse selects and opens */
525         WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0);
526         kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
527         RNA_boolean_set(kmi->ptr, "extend", true);
528         kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
529         RNA_boolean_set(kmi->ptr, "extend", true);
530         RNA_boolean_set(kmi->ptr, "fill", true);
531
532         /* right mouse selects without opening */
533         kmi = WM_keymap_add_item(keymap, "FILE_OT_select", RIGHTMOUSE, KM_CLICK, 0, 0);
534         RNA_boolean_set(kmi->ptr, "open", false);
535         kmi = WM_keymap_add_item(keymap, "FILE_OT_select", RIGHTMOUSE, KM_CLICK, KM_SHIFT, 0);
536         RNA_boolean_set(kmi->ptr, "extend", true);
537         RNA_boolean_set(kmi->ptr, "open", false);
538         kmi = WM_keymap_add_item(keymap, "FILE_OT_select", RIGHTMOUSE, KM_CLICK, KM_ALT, 0);
539         RNA_boolean_set(kmi->ptr, "extend", true);
540         RNA_boolean_set(kmi->ptr, "fill", true);
541         RNA_boolean_set(kmi->ptr, "open", false);
542
543
544         /* arrow keys navigation (walk selecting) */
545         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, 0, 0);
546         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
547         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT, 0);
548         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
549         RNA_boolean_set(kmi->ptr, "extend", true);
550         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
551         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
552         RNA_boolean_set(kmi->ptr, "extend", true);
553         RNA_boolean_set(kmi->ptr, "fill", true);
554
555         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, 0, 0);
556         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
557         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0);
558         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
559         RNA_boolean_set(kmi->ptr, "extend", true);
560         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
561         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
562         RNA_boolean_set(kmi->ptr, "extend", true);
563         RNA_boolean_set(kmi->ptr, "fill", true);
564
565         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, 0, 0);
566         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
567         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0);
568         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
569         RNA_boolean_set(kmi->ptr, "extend", true);
570         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
571         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
572         RNA_boolean_set(kmi->ptr, "extend", true);
573         RNA_boolean_set(kmi->ptr, "fill", true);
574
575         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, 0, 0);
576         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
577         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0);
578         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
579         RNA_boolean_set(kmi->ptr, "extend", true);
580         kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
581         RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
582         RNA_boolean_set(kmi->ptr, "extend", true);
583         RNA_boolean_set(kmi->ptr, "fill", true);
584
585
586         /* front and back mouse folder navigation */
587         WM_keymap_add_item(keymap, "FILE_OT_previous", BUTTON4MOUSE, KM_CLICK, 0, 0);
588         WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0);
589
590         WM_keymap_add_item(keymap, "FILE_OT_select_all", AKEY, KM_PRESS, 0, 0);
591         WM_keymap_add_item(keymap, "FILE_OT_select_border", BKEY, KM_PRESS, 0, 0);
592         WM_keymap_add_item(keymap, "FILE_OT_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
593         WM_keymap_add_item(keymap, "FILE_OT_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
594         WM_keymap_add_item(keymap, "FILE_OT_highlight", MOUSEMOVE, KM_ANY, KM_ANY, 0);
595         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0);
596         RNA_int_set(kmi->ptr, "increment", 1);
597         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_SHIFT, 0);
598         RNA_int_set(kmi->ptr, "increment", 10);
599         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
600         RNA_int_set(kmi->ptr, "increment", 100);
601         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, 0, 0);
602         RNA_int_set(kmi->ptr, "increment", -1);
603         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_SHIFT, 0);
604         RNA_int_set(kmi->ptr, "increment", -10);
605         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_CTRL, 0);
606         RNA_int_set(kmi->ptr, "increment", -100);
607
608
609         /* keys for button region (top) */
610         keymap = WM_keymap_find(keyconf, "File Browser Buttons", SPACE_FILE, 0);
611         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0);
612         RNA_int_set(kmi->ptr, "increment", 1);
613         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_SHIFT, 0);
614         RNA_int_set(kmi->ptr, "increment", 10);
615         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
616         RNA_int_set(kmi->ptr, "increment", 100);
617         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, 0, 0);
618         RNA_int_set(kmi->ptr, "increment", -1);
619         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_SHIFT, 0);
620         RNA_int_set(kmi->ptr, "increment", -10);
621         kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_CTRL, 0);
622         RNA_int_set(kmi->ptr, "increment", -100);
623 }
624
625
626 static void file_tools_region_init(wmWindowManager *wm, ARegion *ar)
627 {
628         wmKeyMap *keymap;
629
630         ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
631         ED_region_panels_init(wm, ar);
632
633         /* own keymaps */
634         keymap = WM_keymap_find(wm->defaultconf, "File Browser", SPACE_FILE, 0);
635         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
636 }
637
638 static void file_tools_region_draw(const bContext *C, ARegion *ar)
639 {
640         ED_region_panels(C, ar);
641 }
642
643 static void file_tools_region_listener(
644         wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
645         wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
646 {
647 #if 0
648         /* context changes */
649         switch (wmn->category) {
650                 /* pass */
651         }
652 #endif
653 }
654
655 /* add handlers, stuff you only do once or on area/region changes */
656 static void file_header_region_init(wmWindowManager *wm, ARegion *ar)
657 {
658         wmKeyMap *keymap;
659
660         ED_region_header_init(ar);
661
662         keymap = WM_keymap_find(wm->defaultconf, "File Browser", SPACE_FILE, 0);
663         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
664 }
665
666 static void file_header_region_draw(const bContext *C, ARegion *ar)
667 {
668         ED_region_header(C, ar);
669 }
670
671 /* add handlers, stuff you only do once or on area/region changes */
672 static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
673 {
674         wmKeyMap *keymap;
675
676         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
677
678         /* own keymap */
679         keymap = WM_keymap_find(wm->defaultconf, "File Browser", SPACE_FILE, 0);
680         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
681
682         keymap = WM_keymap_find(wm->defaultconf, "File Browser Buttons", SPACE_FILE, 0);
683         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
684 }
685
686 static void file_ui_region_draw(const bContext *C, ARegion *ar)
687 {
688         float col[3];
689         /* clear */
690         UI_GetThemeColor3fv(TH_BACK, col);
691         GPU_clear_color(col[0], col[1], col[2], 0.0);
692         GPU_clear(GPU_COLOR_BIT);
693
694         /* scrolling here is just annoying, disable it */
695         ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur);
696         ar->v2d.cur.ymin = 0;
697
698         /* set view2d view matrix for scrolling (without scrollers) */
699         UI_view2d_view_ortho(&ar->v2d);
700
701
702         file_draw_buttons(C, ar);
703
704         UI_view2d_view_restore(C);
705 }
706
707 static void file_ui_region_listener(
708         wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
709         wmNotifier *wmn, const Scene *UNUSED(scene))
710 {
711         /* context changes */
712         switch (wmn->category) {
713                 case NC_SPACE:
714                         switch (wmn->data) {
715                                 case ND_SPACE_FILE_LIST:
716                                         ED_region_tag_redraw(ar);
717                                         break;
718                         }
719                         break;
720         }
721 }
722
723 static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
724 {
725         if (drag->type == WM_DRAG_PATH) {
726                 SpaceFile *sfile = CTX_wm_space_file(C);
727                 if (sfile) {
728                         return 1;
729                 }
730         }
731         return 0;
732 }
733
734 static void filepath_drop_copy(wmDrag *drag, wmDropBox *drop)
735 {
736         RNA_string_set(drop->ptr, "filepath", drag->path);
737 }
738
739 /* region dropbox definition */
740 static void file_dropboxes(void)
741 {
742         ListBase *lb = WM_dropboxmap_find("Window", SPACE_EMPTY, RGN_TYPE_WINDOW);
743
744         WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy);
745 }
746
747 /* only called once, from space/spacetypes.c */
748 void ED_spacetype_file(void)
749 {
750         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file");
751         ARegionType *art;
752
753         st->spaceid = SPACE_FILE;
754         strncpy(st->name, "File", BKE_ST_MAXNAME);
755
756         st->new = file_new;
757         st->free = file_free;
758         st->init = file_init;
759         st->exit = file_exit;
760         st->duplicate = file_duplicate;
761         st->refresh = file_refresh;
762         st->listener = file_listener;
763         st->operatortypes = file_operatortypes;
764         st->keymap = file_keymap;
765         st->dropboxes = file_dropboxes;
766
767         /* regions: main window */
768         art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
769         art->regionid = RGN_TYPE_WINDOW;
770         art->init = file_main_region_init;
771         art->draw = file_main_region_draw;
772         art->listener = file_main_region_listener;
773         art->message_subscribe = file_main_region_message_subscribe;
774         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
775         BLI_addhead(&st->regiontypes, art);
776
777         /* regions: header */
778         art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
779         art->regionid = RGN_TYPE_HEADER;
780         art->prefsizey = HEADERY;
781         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
782         art->init = file_header_region_init;
783         art->draw = file_header_region_draw;
784         // art->listener = file_header_region_listener;
785         BLI_addhead(&st->regiontypes, art);
786
787         /* regions: ui */
788         art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
789         art->regionid = RGN_TYPE_UI;
790         art->prefsizey = 60;
791         art->keymapflag = ED_KEYMAP_UI;
792         art->listener = file_ui_region_listener;
793         art->init = file_ui_region_init;
794         art->draw = file_ui_region_draw;
795         BLI_addhead(&st->regiontypes, art);
796
797         /* regions: channels (directories) */
798         art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
799         art->regionid = RGN_TYPE_TOOLS;
800         art->prefsizex = 240;
801         art->prefsizey = 60;
802         art->keymapflag = ED_KEYMAP_UI;
803         art->listener = file_tools_region_listener;
804         art->init = file_tools_region_init;
805         art->draw = file_tools_region_draw;
806         BLI_addhead(&st->regiontypes, art);
807
808         /* regions: tool properties */
809         art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
810         art->regionid = RGN_TYPE_TOOL_PROPS;
811         art->prefsizex = 0;
812         art->prefsizey = 360;
813         art->keymapflag = ED_KEYMAP_UI;
814         art->listener = file_tools_region_listener;
815         art->init = file_tools_region_init;
816         art->draw = file_tools_region_draw;
817         BLI_addhead(&st->regiontypes, art);
818         file_panels_register(art);
819
820         BKE_spacetype_register(st);
821
822 }
823
824 void ED_file_init(void)
825 {
826         ED_file_read_bookmarks();
827
828         if (G.background == false) {
829                 filelist_init_icons();
830         }
831
832         IMB_thumb_makedirs();
833 }
834
835 void ED_file_exit(void)
836 {
837         fsmenu_free();
838
839         if (G.background == false) {
840                 filelist_free_icons();
841         }
842 }
843
844 void ED_file_read_bookmarks(void)
845 {
846         const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
847
848         fsmenu_free();
849
850         fsmenu_read_system(ED_fsmenu_get(), true);
851
852         if (cfgdir) {
853                 char name[FILE_MAX];
854                 BLI_make_file_string("/", name, cfgdir, BLENDER_BOOKMARK_FILE);
855                 fsmenu_read_bookmarks(ED_fsmenu_get(), name);
856         }
857 }