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