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