diff options
Diffstat (limited to 'source/blender/editors/space_file')
-rw-r--r-- | source/blender/editors/space_file/CMakeLists.txt | 76 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_draw.c | 1400 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_intern.h | 15 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_ops.c | 3601 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_panels.c | 83 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_utils.c | 16 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 4156 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.h | 154 | ||||
-rw-r--r-- | source/blender/editors/space_file/filesel.c | 1214 | ||||
-rw-r--r-- | source/blender/editors/space_file/fsmenu.c | 1156 | ||||
-rw-r--r-- | source/blender/editors/space_file/fsmenu.h | 27 | ||||
-rw-r--r-- | source/blender/editors/space_file/space_file.c | 1024 |
12 files changed, 6639 insertions, 6283 deletions
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index a92ed62cae2..6bf975b98e0 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -16,85 +16,85 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../../blenfont - ../../blenkernel - ../../blenlib - ../../blenloader - ../../blentranslation - ../../imbuf - ../../gpu - ../../makesdna - ../../makesrna - ../../render/extern/include - ../../windowmanager - ../../../../intern/atomic - ../../../../intern/guardedalloc - ../../../../intern/glew-mx + ../include + ../../blenfont + ../../blenkernel + ../../blenlib + ../../blenloader + ../../blentranslation + ../../imbuf + ../../gpu + ../../makesdna + ../../makesrna + ../../render/extern/include + ../../windowmanager + ../../../../intern/atomic + ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - file_draw.c - file_ops.c - file_panels.c - file_utils.c - filelist.c - filesel.c - fsmenu.c - space_file.c - - file_intern.h - filelist.h - fsmenu.h + file_draw.c + file_ops.c + file_panels.c + file_utils.c + filelist.c + filesel.c + fsmenu.c + space_file.c + + file_intern.h + filelist.h + fsmenu.h ) set(LIB ) if(WITH_HEADLESS) - add_definitions(-DWITH_HEADLESS) + add_definitions(-DWITH_HEADLESS) endif() if(WITH_IMAGE_OPENEXR) - add_definitions(-DWITH_OPENEXR) + add_definitions(-DWITH_OPENEXR) endif() if(WITH_OPENIMAGEIO) - add_definitions(-DWITH_OPENIMAGEIO) + add_definitions(-DWITH_OPENIMAGEIO) endif() if(WITH_IMAGE_TIFF) - add_definitions(-DWITH_TIFF) + add_definitions(-DWITH_TIFF) endif() if(WITH_IMAGE_OPENJPEG) - add_definitions(-DWITH_OPENJPEG) + add_definitions(-DWITH_OPENJPEG) endif() if(WITH_IMAGE_DDS) - add_definitions(-DWITH_DDS) + add_definitions(-DWITH_DDS) endif() if(WITH_IMAGE_CINEON) - add_definitions(-DWITH_CINEON) + add_definitions(-DWITH_CINEON) endif() if(WITH_IMAGE_HDR) - add_definitions(-DWITH_HDR) + add_definitions(-DWITH_HDR) endif() if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) endif() add_definitions(${GL_DEFINITIONS}) if(WITH_FREESTYLE) - add_definitions(-DWITH_FREESTYLE) + add_definitions(-DWITH_FREESTYLE) endif() blender_add_lib(bf_editor_space_file "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index c0aa03abece..87560436d52 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -21,7 +21,6 @@ * \ingroup spfile */ - #include <math.h> #include <string.h> #include <errno.h> @@ -69,13 +68,13 @@ #include "filelist.h" -#include "file_intern.h" // own include +#include "file_intern.h" // own include /* Dummy helper - we need dynamic tooltips here. */ static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) { - char *dyn_tooltip = argN; - return BLI_strdup(dyn_tooltip); + char *dyn_tooltip = argN; + return BLI_strdup(dyn_tooltip); } /* Note: This function uses pixelspace (0, 0, winx, winy), not view2d. @@ -93,673 +92,804 @@ static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char */ void file_draw_buttons(const bContext *C, ARegion *ar) { - /* Button layout. */ - const int max_x = ar->winx - 10; - const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); - const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); - const int input_minw = 20; - const int btn_h = UI_UNIT_Y; - const int btn_fn_w = UI_UNIT_X; - const int btn_minw = 80; - const int btn_margin = 20; - const int separator = 4; - - /* Additional locals. */ - char uiblockstr[32]; - int loadbutton; - int fnumbuttons; - int min_x = 10; - int chan_offs = 0; - int available_w = max_x - min_x; - int line1_w = available_w; - int line2_w = available_w; - - uiBut *but; - uiBlock *block; - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - ARegion *artmp; - const bool is_browse_only = (sfile->op == NULL); - - /* Initialize UI block. */ - BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar); - block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS); - - /* exception to make space for collapsed region icon */ - for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) { - if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) { - chan_offs = 16; - min_x += chan_offs; - available_w -= chan_offs; - } - } - - /* Is there enough space for the execute / cancel buttons? */ - - - if (is_browse_only) { - loadbutton = 0; - } - else { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin; - CLAMP_MIN(loadbutton, btn_minw); - if (available_w <= loadbutton + separator + input_minw) { - loadbutton = 0; - } - } - - if (loadbutton) { - line1_w -= (loadbutton + separator); - line2_w = line1_w; - } - - /* Is there enough space for file number increment/decrement buttons? */ - fnumbuttons = 2 * btn_fn_w; - if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) { - fnumbuttons = 0; - } - else { - line2_w -= (fnumbuttons + separator); - } - - /* Text input fields for directory and file. */ - if (available_w > 0) { - const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL; - int overwrite_alert = file_draw_check_exists(sfile); - const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER); - - /* callbacks for operator check functions */ - UI_block_func_set(block, file_draw_check_cb, NULL, NULL); - - but = uiDefBut(block, UI_BTYPE_TEXT, -1, "", - min_x, line1_y, line1_w - chan_offs, btn_h, - params->dir, 0.0, (float)FILE_MAX, 0, 0, - TIP_("File path")); - UI_but_func_complete_set(but, autocomplete_directory, NULL); - UI_but_flag_enable(but, UI_BUT_NO_UTF8); - UI_but_flag_disable(but, UI_BUT_UNDO); - UI_but_funcN_set(but, file_directory_enter_handle, NULL, but); - - /* TODO, directory editing is non-functional while a library is loaded - * until this is properly supported just disable it. */ - if (sfile->files && filelist_lib(sfile->files)) - UI_but_flag_enable(but, UI_BUT_DISABLED); - - if ((params->flag & FILE_DIRSEL_ONLY) == 0) { - but = uiDefBut(block, UI_BTYPE_TEXT, -1, "", - min_x, line2_y, line2_w - chan_offs, btn_h, - is_active_dir ? (char *)"" : params->file, - 0.0, (float)FILE_MAXFILE, 0, 0, - TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name"))); - UI_but_func_complete_set(but, autocomplete_file, NULL); - UI_but_flag_enable(but, UI_BUT_NO_UTF8); - UI_but_flag_disable(but, UI_BUT_UNDO); - /* silly workaround calling NFunc to ensure this does not get called - * immediate ui_apply_but_func but only after button deactivates */ - UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); - - /* check if this overrides a file and if the operator option is used */ - if (overwrite_alert) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - } - - /* clear func */ - UI_block_func_set(block, NULL, NULL, NULL); - } - - /* Filename number increment / decrement buttons. */ - if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) { - UI_block_align_begin(block); - but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_REMOVE, - min_x + line2_w + separator - chan_offs, line2_y, - btn_fn_w, btn_h, - TIP_("Decrement the filename number")); - RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1); - - but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ADD, - min_x + line2_w + separator + btn_fn_w - chan_offs, line2_y, - btn_fn_w, btn_h, - TIP_("Increment the filename number")); - RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1); - UI_block_align_end(block); - } - - /* Execute / cancel buttons. */ - if (loadbutton) { - const struct FileDirEntry *file = sfile->files ? filelist_file(sfile->files, params->active_file) : NULL; - char const *str_exec; - - if (file && FILENAME_IS_PARENT(file->relpath)) { - str_exec = IFACE_("Parent Directory"); - } - else if (file && file->typeflag & FILE_TYPE_DIR) { - str_exec = IFACE_("Open Directory"); - } - else { - str_exec = params->title; /* params->title is already translated! */ - } - - but = uiDefButO( - block, UI_BTYPE_BUT, "FILE_OT_execute", WM_OP_EXEC_REGION_WIN, str_exec, - max_x - loadbutton, line1_y, loadbutton, btn_h, ""); - /* Just a display hint. */ - UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); - - uiDefButO(block, UI_BTYPE_BUT, "FILE_OT_cancel", WM_OP_EXEC_REGION_WIN, IFACE_("Cancel"), - max_x - loadbutton, line2_y, loadbutton, btn_h, ""); - } - - UI_block_end(C, block); - UI_block_draw(C, block); + /* Button layout. */ + const int max_x = ar->winx - 10; + const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); + const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); + const int input_minw = 20; + const int btn_h = UI_UNIT_Y; + const int btn_fn_w = UI_UNIT_X; + const int btn_minw = 80; + const int btn_margin = 20; + const int separator = 4; + + /* Additional locals. */ + char uiblockstr[32]; + int loadbutton; + int fnumbuttons; + int min_x = 10; + int chan_offs = 0; + int available_w = max_x - min_x; + int line1_w = available_w; + int line2_w = available_w; + + uiBut *but; + uiBlock *block; + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_params(sfile); + ARegion *artmp; + const bool is_browse_only = (sfile->op == NULL); + + /* Initialize UI block. */ + BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar); + block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS); + + /* exception to make space for collapsed region icon */ + for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) { + if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) { + chan_offs = 16; + min_x += chan_offs; + available_w -= chan_offs; + } + } + + /* Is there enough space for the execute / cancel buttons? */ + + if (is_browse_only) { + loadbutton = 0; + } + else { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin; + CLAMP_MIN(loadbutton, btn_minw); + if (available_w <= loadbutton + separator + input_minw) { + loadbutton = 0; + } + } + + if (loadbutton) { + line1_w -= (loadbutton + separator); + line2_w = line1_w; + } + + /* Is there enough space for file number increment/decrement buttons? */ + fnumbuttons = 2 * btn_fn_w; + if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) { + fnumbuttons = 0; + } + else { + line2_w -= (fnumbuttons + separator); + } + + /* Text input fields for directory and file. */ + if (available_w > 0) { + const struct FileDirEntry *file = sfile->files ? + filelist_file(sfile->files, params->active_file) : + NULL; + int overwrite_alert = file_draw_check_exists(sfile); + const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER); + + /* callbacks for operator check functions */ + UI_block_func_set(block, file_draw_check_cb, NULL, NULL); + + but = uiDefBut(block, + UI_BTYPE_TEXT, + -1, + "", + min_x, + line1_y, + line1_w - chan_offs, + btn_h, + params->dir, + 0.0, + (float)FILE_MAX, + 0, + 0, + TIP_("File path")); + UI_but_func_complete_set(but, autocomplete_directory, NULL); + UI_but_flag_enable(but, UI_BUT_NO_UTF8); + UI_but_flag_disable(but, UI_BUT_UNDO); + UI_but_funcN_set(but, file_directory_enter_handle, NULL, but); + + /* TODO, directory editing is non-functional while a library is loaded + * until this is properly supported just disable it. */ + if (sfile->files && filelist_lib(sfile->files)) + UI_but_flag_enable(but, UI_BUT_DISABLED); + + if ((params->flag & FILE_DIRSEL_ONLY) == 0) { + but = uiDefBut( + block, + UI_BTYPE_TEXT, + -1, + "", + min_x, + line2_y, + line2_w - chan_offs, + btn_h, + is_active_dir ? (char *)"" : params->file, + 0.0, + (float)FILE_MAXFILE, + 0, + 0, + TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name"))); + UI_but_func_complete_set(but, autocomplete_file, NULL); + UI_but_flag_enable(but, UI_BUT_NO_UTF8); + UI_but_flag_disable(but, UI_BUT_UNDO); + /* silly workaround calling NFunc to ensure this does not get called + * immediate ui_apply_but_func but only after button deactivates */ + UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); + + /* check if this overrides a file and if the operator option is used */ + if (overwrite_alert) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } + } + + /* clear func */ + UI_block_func_set(block, NULL, NULL, NULL); + } + + /* Filename number increment / decrement buttons. */ + if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) { + UI_block_align_begin(block); + but = uiDefIconButO(block, + UI_BTYPE_BUT, + "FILE_OT_filenum", + 0, + ICON_REMOVE, + min_x + line2_w + separator - chan_offs, + line2_y, + btn_fn_w, + btn_h, + TIP_("Decrement the filename number")); + RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1); + + but = uiDefIconButO(block, + UI_BTYPE_BUT, + "FILE_OT_filenum", + 0, + ICON_ADD, + min_x + line2_w + separator + btn_fn_w - chan_offs, + line2_y, + btn_fn_w, + btn_h, + TIP_("Increment the filename number")); + RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1); + UI_block_align_end(block); + } + + /* Execute / cancel buttons. */ + if (loadbutton) { + const struct FileDirEntry *file = sfile->files ? + filelist_file(sfile->files, params->active_file) : + NULL; + char const *str_exec; + + if (file && FILENAME_IS_PARENT(file->relpath)) { + str_exec = IFACE_("Parent Directory"); + } + else if (file && file->typeflag & FILE_TYPE_DIR) { + str_exec = IFACE_("Open Directory"); + } + else { + str_exec = params->title; /* params->title is already translated! */ + } + + but = uiDefButO(block, + UI_BTYPE_BUT, + "FILE_OT_execute", + WM_OP_EXEC_REGION_WIN, + str_exec, + max_x - loadbutton, + line1_y, + loadbutton, + btn_h, + ""); + /* Just a display hint. */ + UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); + + uiDefButO(block, + UI_BTYPE_BUT, + "FILE_OT_cancel", + WM_OP_EXEC_REGION_WIN, + IFACE_("Cancel"), + max_x - loadbutton, + line2_y, + loadbutton, + btn_h, + ""); + } + + UI_block_end(C, block); + UI_block_draw(C, block); } - static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade) { - float color[4]; - UI_GetThemeColorShade4fv(colorid, shade, color); - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(true, (float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color); + float color[4]; + UI_GetThemeColorShade4fv(colorid, shade, color); + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa( + true, (float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color); } - -static void file_draw_icon(uiBlock *block, const char *path, int sx, int sy, int icon, int width, int height, bool drag) +static void file_draw_icon( + uiBlock *block, const char *path, int sx, int sy, int icon, int width, int height, bool drag) { - uiBut *but; - int x, y; - // float alpha = 1.0f; + uiBut *but; + int x, y; + // float alpha = 1.0f; - x = sx; - y = sy - height; + x = sx; + y = sy - height; - /*if (icon == ICON_FILE_BLANK) alpha = 0.375f;*/ + /*if (icon == ICON_FILE_BLANK) alpha = 0.375f;*/ - but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL); - UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); + but = uiDefIconBut( + block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL); + UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); - if (drag) { - /* path is no more static, cannot give it directly to but... */ - UI_but_drag_set_path(but, BLI_strdup(path), true); - } + if (drag) { + /* path is no more static, cannot give it directly to but... */ + UI_but_drag_set_path(but, BLI_strdup(path), true); + } } - -static void file_draw_string( - int sx, int sy, const char *string, float width, int height, eFontStyle_Align align, - const uchar col[4]) +static void file_draw_string(int sx, + int sy, + const char *string, + float width, + int height, + eFontStyle_Align align, + const uchar col[4]) { - uiStyle *style; - uiFontStyle fs; - rcti rect; - char fname[FILE_MAXFILE]; - - if (string[0] == '\0') { - return; - } - - style = UI_style_get(); - fs = style->widgetlabel; - - BLI_strncpy(fname, string, FILE_MAXFILE); - UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0'); - - /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict - * (for buttons it works) */ - rect.xmin = sx; - rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC)); - rect.ymin = sy - height; - rect.ymax = sy; - - UI_fontstyle_draw( - &fs, &rect, fname, col, - &(struct uiFontStyleDraw_Params) { .align = align, }); + uiStyle *style; + uiFontStyle fs; + rcti rect; + char fname[FILE_MAXFILE]; + + if (string[0] == '\0') { + return; + } + + style = UI_style_get(); + fs = style->widgetlabel; + + BLI_strncpy(fname, string, FILE_MAXFILE); + UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0'); + + /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict + * (for buttons it works) */ + rect.xmin = sx; + rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC)); + rect.ymin = sy - height; + rect.ymax = sy; + + UI_fontstyle_draw(&fs, + &rect, + fname, + col, + &(struct uiFontStyleDraw_Params){ + .align = align, + }); } void file_calc_previews(const bContext *C, ARegion *ar) { - SpaceFile *sfile = CTX_wm_space_file(C); - View2D *v2d = &ar->v2d; + SpaceFile *sfile = CTX_wm_space_file(C); + View2D *v2d = &ar->v2d; - ED_fileselect_init_layout(sfile, ar); - UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height); + ED_fileselect_init_layout(sfile, ar); + UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height); } -static void file_draw_preview( - uiBlock *block, const char *path, int sx, int sy, const float icon_aspect, - ImBuf *imb, const int icon, FileLayout *layout, const bool is_icon, const int typeflags, const bool drag) +static void file_draw_preview(uiBlock *block, + const char *path, + int sx, + int sy, + const float icon_aspect, + ImBuf *imb, + const int icon, + FileLayout *layout, + const bool is_icon, + const int typeflags, + const bool drag) { - uiBut *but; - float fx, fy; - float dx, dy; - int xco, yco; - float ui_imbx, ui_imby; - float scaledx, scaledy; - float scale; - int ex, ey; - bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE); - float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - - BLI_assert(imb != NULL); - - ui_imbx = imb->x * UI_DPI_FAC; - ui_imby = imb->y * UI_DPI_FAC; - /* Unlike thumbnails, icons are not scaled up. */ - if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) || - (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h)))) - { - if (imb->x > imb->y) { - scaledx = (float)layout->prv_w; - scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w; - scale = scaledx / imb->x; - } - else { - scaledy = (float)layout->prv_h; - scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h; - scale = scaledy / imb->y; - } - } - else { - scaledx = ui_imbx; - scaledy = ui_imby; - scale = UI_DPI_FAC; - } - - ex = (int)scaledx; - ey = (int)scaledy; - fx = ((float)layout->prv_w - (float)ex) / 2.0f; - fy = ((float)layout->prv_h - (float)ey) / 2.0f; - dx = (fx + 0.5f + layout->prv_border_x); - dy = (fy + 0.5f - layout->prv_border_y); - xco = sx + (int)dx; - yco = sy - layout->prv_h + (int)dy; - - /* shadow */ - if (use_dropshadow) { - UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); - } - - GPU_blend(true); - - /* the image */ - if (!is_icon && typeflags & FILE_TYPE_FTFONT) { - UI_GetThemeColor4fv(TH_TEXT, col); - } - - if (!is_icon && typeflags & FILE_TYPE_BLENDERLIB) { - /* Datablock preview images use premultiplied alpha. */ - GPU_blend_set_func_separate(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - } - - IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTexScaled(&state, (float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, - scale, scale, 1.0f, 1.0f, col); - - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - if (icon) { - UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f, NULL); - } - - /* border */ - if (use_dropshadow) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); - immUnbindProgram(); - } - - but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL); - UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); - - /* dragregion */ - if (drag) { - /* path is no more static, cannot give it directly to but... */ - UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true); - } - - GPU_blend(false); + uiBut *but; + float fx, fy; + float dx, dy; + int xco, yco; + float ui_imbx, ui_imby; + float scaledx, scaledy; + float scale; + int ex, ey; + bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE); + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + BLI_assert(imb != NULL); + + ui_imbx = imb->x * UI_DPI_FAC; + ui_imby = imb->y * UI_DPI_FAC; + /* Unlike thumbnails, icons are not scaled up. */ + if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) || + (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h)))) { + if (imb->x > imb->y) { + scaledx = (float)layout->prv_w; + scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w; + scale = scaledx / imb->x; + } + else { + scaledy = (float)layout->prv_h; + scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h; + scale = scaledy / imb->y; + } + } + else { + scaledx = ui_imbx; + scaledy = ui_imby; + scale = UI_DPI_FAC; + } + + ex = (int)scaledx; + ey = (int)scaledy; + fx = ((float)layout->prv_w - (float)ex) / 2.0f; + fy = ((float)layout->prv_h - (float)ey) / 2.0f; + dx = (fx + 0.5f + layout->prv_border_x); + dy = (fy + 0.5f - layout->prv_border_y); + xco = sx + (int)dx; + yco = sy - layout->prv_h + (int)dy; + + /* shadow */ + if (use_dropshadow) { + UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + } + + GPU_blend(true); + + /* the image */ + if (!is_icon && typeflags & FILE_TYPE_FTFONT) { + UI_GetThemeColor4fv(TH_TEXT, col); + } + + if (!is_icon && typeflags & FILE_TYPE_BLENDERLIB) { + /* Datablock preview images use premultiplied alpha. */ + GPU_blend_set_func_separate( + GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + } + + IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); + immDrawPixelsTexScaled(&state, + (float)xco, + (float)yco, + imb->x, + imb->y, + GL_RGBA, + GL_UNSIGNED_BYTE, + GL_NEAREST, + imb->rect, + scale, + scale, + 1.0f, + 1.0f, + col); + + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + if (icon) { + UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f, NULL); + } + + /* border */ + if (use_dropshadow) { + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); + imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + immUnbindProgram(); + } + + but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL); + UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); + + /* dragregion */ + if (drag) { + /* path is no more static, cannot give it directly to but... */ + UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true); + } + + GPU_blend(false); } static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) { - Main *bmain = CTX_data_main(C); - char newname[FILE_MAX + 12]; - char orgname[FILE_MAX + 12]; - char filename[FILE_MAX + 12]; - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - - const char *blendfile_path = BKE_main_blendfile_path(bmain); - BLI_make_file_string(blendfile_path, orgname, sfile->params->dir, oldname); - BLI_strncpy(filename, sfile->params->renamefile, sizeof(filename)); - BLI_filename_make_safe(filename); - BLI_make_file_string(blendfile_path, newname, sfile->params->dir, filename); - - if (!STREQ(orgname, newname)) { - if (!BLI_exists(newname)) { - errno = 0; - if ((BLI_rename(orgname, newname) != 0) || - !BLI_exists(newname)) - { - WM_reportf(RPT_ERROR, - "Could not rename: %s", - errno ? strerror(errno) : "unknown error"); - WM_report_banner_show(); - } - else { - /* If rename is sucessfull, scroll to newly renamed entry. */ - BLI_strncpy(sfile->params->renamefile, filename, sizeof(sfile->params->renamefile)); - sfile->params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_PENDING; - - if (sfile->smoothscroll_timer != NULL) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); - } - sfile->smoothscroll_timer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER1, 1.0 / 1000.0); - sfile->scroll_offset = 0; - } - - /* to make sure we show what is on disk */ - ED_fileselect_clear(wm, sa, sfile); - } - - ED_region_tag_redraw(ar); - } + Main *bmain = CTX_data_main(C); + char newname[FILE_MAX + 12]; + char orgname[FILE_MAX + 12]; + char filename[FILE_MAX + 12]; + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + + const char *blendfile_path = BKE_main_blendfile_path(bmain); + BLI_make_file_string(blendfile_path, orgname, sfile->params->dir, oldname); + BLI_strncpy(filename, sfile->params->renamefile, sizeof(filename)); + BLI_filename_make_safe(filename); + BLI_make_file_string(blendfile_path, newname, sfile->params->dir, filename); + + if (!STREQ(orgname, newname)) { + if (!BLI_exists(newname)) { + errno = 0; + if ((BLI_rename(orgname, newname) != 0) || !BLI_exists(newname)) { + WM_reportf(RPT_ERROR, "Could not rename: %s", errno ? strerror(errno) : "unknown error"); + WM_report_banner_show(); + } + else { + /* If rename is sucessfull, scroll to newly renamed entry. */ + BLI_strncpy(sfile->params->renamefile, filename, sizeof(sfile->params->renamefile)); + sfile->params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_PENDING; + + if (sfile->smoothscroll_timer != NULL) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); + } + sfile->smoothscroll_timer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER1, 1.0 / 1000.0); + sfile->scroll_offset = 0; + } + + /* to make sure we show what is on disk */ + ED_fileselect_clear(wm, sa, sfile); + } + + ED_region_tag_redraw(ar); + } } - static void draw_background(FileLayout *layout, View2D *v2d) { - int i; - int sy; - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShade(TH_BACK, -7); - - /* alternating flat shade background */ - for (i = 0; (i <= layout->rows); i += 2) { - sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) - layout->tile_border_y; - - immRectf(pos, v2d->cur.xmin, (float)sy, v2d->cur.xmax, (float)(sy + layout->tile_h + 2 * layout->tile_border_y)); - } - - immUnbindProgram(); + int i; + int sy; + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, -7); + + /* alternating flat shade background */ + for (i = 0; (i <= layout->rows); i += 2) { + sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) - + layout->tile_border_y; + + immRectf(pos, + v2d->cur.xmin, + (float)sy, + v2d->cur.xmax, + (float)(sy + layout->tile_h + 2 * layout->tile_border_y)); + } + + immUnbindProgram(); } static void draw_dividers(FileLayout *layout, View2D *v2d) { - /* vertical column dividers */ - - const int step = (layout->tile_w + 2 * layout->tile_border_x); - - unsigned int vertex_len = 0; - int sx = (int)v2d->tot.xmin; - while (sx < v2d->cur.xmax) { - sx += step; - vertex_len += 4; /* vertex_count = 2 points per line * 2 lines per divider */ - } - - if (vertex_len > 0) { - int v1[2], v2[2]; - unsigned char col_hi[3], col_lo[3]; - - UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi); - UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo); - - v1[1] = v2d->cur.ymax - layout->tile_border_y; - v2[1] = v2d->cur.ymin; - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - immBegin(GPU_PRIM_LINES, vertex_len); - - sx = (int)v2d->tot.xmin; - while (sx < v2d->cur.xmax) { - sx += step; - - v1[0] = v2[0] = sx; - immAttrSkip(color); - immVertex2iv(pos, v1); - immAttr3ubv(color, col_lo); - immVertex2iv(pos, v2); - - v1[0] = v2[0] = sx + 1; - immAttrSkip(color); - immVertex2iv(pos, v1); - immAttr3ubv(color, col_hi); - immVertex2iv(pos, v2); - } - - immEnd(); - immUnbindProgram(); - } + /* vertical column dividers */ + + const int step = (layout->tile_w + 2 * layout->tile_border_x); + + unsigned int vertex_len = 0; + int sx = (int)v2d->tot.xmin; + while (sx < v2d->cur.xmax) { + sx += step; + vertex_len += 4; /* vertex_count = 2 points per line * 2 lines per divider */ + } + + if (vertex_len > 0) { + int v1[2], v2[2]; + unsigned char col_hi[3], col_lo[3]; + + UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi); + UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo); + + v1[1] = v2d->cur.ymax - layout->tile_border_y; + v2[1] = v2d->cur.ymin; + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + uint color = GPU_vertformat_attr_add( + format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GPU_PRIM_LINES, vertex_len); + + sx = (int)v2d->tot.xmin; + while (sx < v2d->cur.xmax) { + sx += step; + + v1[0] = v2[0] = sx; + immAttrSkip(color); + immVertex2iv(pos, v1); + immAttr3ubv(color, col_lo); + immVertex2iv(pos, v2); + + v1[0] = v2[0] = sx + 1; + immAttrSkip(color); + immVertex2iv(pos, v1); + immAttr3ubv(color, col_hi); + immVertex2iv(pos, v2); + } + + immEnd(); + immUnbindProgram(); + } } void file_draw_list(const bContext *C, ARegion *ar) { - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - FileLayout *layout = ED_fileselect_get_layout(sfile, ar); - View2D *v2d = &ar->v2d; - struct FileList *files = sfile->files; - struct FileDirEntry *file; - const char *root = filelist_dir(files); - ImBuf *imb; - uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); - int numfiles; - int numfiles_layout; - int sx, sy; - int offset; - int textwidth, textheight; - int i; - bool is_icon; - eFontStyle_Align align; - bool do_drag; - int column_space = 0.6f * UI_UNIT_X; - unsigned char text_col[4]; - const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); - const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size); - const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size)); - - numfiles = filelist_files_ensure(files); - - if (params->display != FILE_IMGDISPLAY) { - - draw_background(layout, v2d); - - draw_dividers(layout, v2d); - } - - offset = ED_fileselect_layout_offset(layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax); - if (offset < 0) offset = 0; - - numfiles_layout = ED_fileselect_layout_numfiles(layout, ar); - - /* adjust, so the next row is already drawn when scrolling */ - if (layout->flag & FILE_LAYOUT_HOR) { - numfiles_layout += layout->rows; - } - else { - numfiles_layout += layout->columns; - } - - filelist_file_cache_slidingwindow_set(files, numfiles_layout); - - textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w : (int)layout->column_widths[COLUMN_NAME]; - textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5); - - align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT; - - if (numfiles > 0) { - const bool success = filelist_file_cache_block(files, min_ii(offset + (numfiles_layout / 2), numfiles - 1)); - BLI_assert(success); - UNUSED_VARS_NDEBUG(success); - - filelist_cache_previews_update(files); - - /* Handle preview timer here, since it's filelist_file_cache_block() and filelist_cache_previews_update() - * which controls previews task. */ - { - const bool previews_running = filelist_cache_previews_running(files); -// printf("%s: preview task: %d\n", __func__, previews_running); - if (previews_running && !sfile->previews_timer) { - sfile->previews_timer = WM_event_add_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), - NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01); - } - if (!previews_running && sfile->previews_timer) { - /* Preview is not running, no need to keep generating update events! */ -// printf("%s: Inactive preview task, sleeping!\n", __func__); - WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer); - sfile->previews_timer = NULL; - } - } - } - - BLF_batch_draw_begin(); - - for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) { - unsigned int file_selflag; - char path[FILE_MAX_LIBEXTRA]; - ED_fileselect_layout_tilepos(layout, i, &sx, &sy); - sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X); - sy = (int)(v2d->tot.ymax - sy); - - file = filelist_file(files, i); - file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL); - - BLI_join_dirfile(path, sizeof(path), root, file->relpath); - - if (!(file_selflag & FILE_SEL_EDITING)) { - if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) || - (file_selflag & FILE_SEL_SELECTED)) - { - int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; - int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0; - - BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath)); - - draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade); - } - } - UI_draw_roundbox_corner_set(UI_CNR_NONE); - - /* don't drag parent or refresh items */ - do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); - - if (FILE_IMGDISPLAY == params->display) { - const int icon = filelist_geticon(files, i, false); - is_icon = 0; - imb = filelist_getimage(files, i); - if (!imb) { - imb = filelist_geticon_image(files, i); - is_icon = 1; - } - - file_draw_preview(block, path, sx, sy, thumb_icon_aspect, - imb, icon, layout, is_icon, file->typeflag, do_drag); - } - else { - file_draw_icon(block, path, sx, sy - (UI_UNIT_Y / 6), filelist_geticon(files, i, true), - ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag); - sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; - } - - UI_GetThemeColor4ubv(TH_TEXT, text_col); - - if (file_selflag & FILE_SEL_EDITING) { - uiBut *but; - short width; - - if (params->display == FILE_SHORTDISPLAY) { - width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X); - } - else if (params->display == FILE_LONGDISPLAY) { - width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f); - } - else { - BLI_assert(params->display == FILE_IMGDISPLAY); - width = textwidth; - } - - but = uiDefBut(block, UI_BTYPE_TEXT, 1, "", sx, sy - layout->tile_h - 0.15f * UI_UNIT_X, - width, textheight, sfile->params->renamefile, 1.0f, - (float)sizeof(sfile->params->renamefile), 0, 0, ""); - UI_but_func_rename_set(but, renamebutton_cb, file); - UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */ - UI_but_flag_disable(but, UI_BUT_UNDO); - if (false == UI_but_active_only(C, ar, block, but)) { - file_selflag = filelist_entry_select_set( - sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL); - } - } - - if (!(file_selflag& FILE_SEL_EDITING)) { - int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy; - file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col); - } - - sx += (int)layout->column_widths[COLUMN_NAME] + column_space; - if (params->display == FILE_SHORTDISPLAY) { - if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || - !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) - { - if ((file->entry->size_str[0] == '\0') || update_stat_strings) { - BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str); - } - file_draw_string( - sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, - align, text_col); - } - sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; - } - else if (params->display == FILE_LONGDISPLAY) { - if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) { - if ((file->entry->date_str[0] == '\0') || update_stat_strings) { - BLI_filelist_entry_datetime_to_string( - NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str); - } - file_draw_string( - sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h, - align, text_col); - sx += (int)layout->column_widths[COLUMN_DATE] + column_space; - file_draw_string( - sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h, - align, text_col); - sx += (int)layout->column_widths[COLUMN_TIME] + column_space; - } - else { - sx += (int)layout->column_widths[COLUMN_DATE] + column_space; - sx += (int)layout->column_widths[COLUMN_TIME] + column_space; - } - - if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || - !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) - { - if ((file->entry->size_str[0] == '\0') || update_stat_strings) { - BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str); - } - file_draw_string( - sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, - align, text_col); - } - sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; - } - } - - BLF_batch_draw_end(); - - UI_block_end(C, block); - UI_block_draw(C, block); - - layout->curr_size = params->thumbnail_size; + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_params(sfile); + FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + View2D *v2d = &ar->v2d; + struct FileList *files = sfile->files; + struct FileDirEntry *file; + const char *root = filelist_dir(files); + ImBuf *imb; + uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + int numfiles; + int numfiles_layout; + int sx, sy; + int offset; + int textwidth, textheight; + int i; + bool is_icon; + eFontStyle_Align align; + bool do_drag; + int column_space = 0.6f * UI_UNIT_X; + unsigned char text_col[4]; + const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); + const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size); + const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size)); + + numfiles = filelist_files_ensure(files); + + if (params->display != FILE_IMGDISPLAY) { + + draw_background(layout, v2d); + + draw_dividers(layout, v2d); + } + + offset = ED_fileselect_layout_offset(layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax); + if (offset < 0) + offset = 0; + + numfiles_layout = ED_fileselect_layout_numfiles(layout, ar); + + /* adjust, so the next row is already drawn when scrolling */ + if (layout->flag & FILE_LAYOUT_HOR) { + numfiles_layout += layout->rows; + } + else { + numfiles_layout += layout->columns; + } + + filelist_file_cache_slidingwindow_set(files, numfiles_layout); + + textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w : + (int)layout->column_widths[COLUMN_NAME]; + textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5); + + align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT; + + if (numfiles > 0) { + const bool success = filelist_file_cache_block( + files, min_ii(offset + (numfiles_layout / 2), numfiles - 1)); + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); + + filelist_cache_previews_update(files); + + /* Handle preview timer here, since it's filelist_file_cache_block() and filelist_cache_previews_update() + * which controls previews task. */ + { + const bool previews_running = filelist_cache_previews_running(files); + // printf("%s: preview task: %d\n", __func__, previews_running); + if (previews_running && !sfile->previews_timer) { + sfile->previews_timer = WM_event_add_timer_notifier( + CTX_wm_manager(C), CTX_wm_window(C), NC_SPACE | ND_SPACE_FILE_PREVIEW, 0.01); + } + if (!previews_running && sfile->previews_timer) { + /* Preview is not running, no need to keep generating update events! */ + // printf("%s: Inactive preview task, sleeping!\n", __func__); + WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), sfile->previews_timer); + sfile->previews_timer = NULL; + } + } + } + + BLF_batch_draw_begin(); + + for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) { + unsigned int file_selflag; + char path[FILE_MAX_LIBEXTRA]; + ED_fileselect_layout_tilepos(layout, i, &sx, &sy); + sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X); + sy = (int)(v2d->tot.ymax - sy); + + file = filelist_file(files, i); + file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL); + + BLI_join_dirfile(path, sizeof(path), root, file->relpath); + + if (!(file_selflag & FILE_SEL_EDITING)) { + if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) || + (file_selflag & FILE_SEL_SELECTED)) { + int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; + int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : + 0; + + BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath)); + + draw_tile(sx, + sy - 1, + layout->tile_w + 4, + sfile->layout->tile_h + layout->tile_border_y, + colorid, + shade); + } + } + UI_draw_roundbox_corner_set(UI_CNR_NONE); + + /* don't drag parent or refresh items */ + do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); + + if (FILE_IMGDISPLAY == params->display) { + const int icon = filelist_geticon(files, i, false); + is_icon = 0; + imb = filelist_getimage(files, i); + if (!imb) { + imb = filelist_geticon_image(files, i); + is_icon = 1; + } + + file_draw_preview(block, + path, + sx, + sy, + thumb_icon_aspect, + imb, + icon, + layout, + is_icon, + file->typeflag, + do_drag); + } + else { + file_draw_icon(block, + path, + sx, + sy - (UI_UNIT_Y / 6), + filelist_geticon(files, i, true), + ICON_DEFAULT_WIDTH_SCALE, + ICON_DEFAULT_HEIGHT_SCALE, + do_drag); + sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; + } + + UI_GetThemeColor4ubv(TH_TEXT, text_col); + + if (file_selflag & FILE_SEL_EDITING) { + uiBut *but; + short width; + + if (params->display == FILE_SHORTDISPLAY) { + width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X); + } + else if (params->display == FILE_LONGDISPLAY) { + width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f); + } + else { + BLI_assert(params->display == FILE_IMGDISPLAY); + width = textwidth; + } + + but = uiDefBut(block, + UI_BTYPE_TEXT, + 1, + "", + sx, + sy - layout->tile_h - 0.15f * UI_UNIT_X, + width, + textheight, + sfile->params->renamefile, + 1.0f, + (float)sizeof(sfile->params->renamefile), + 0, + 0, + ""); + UI_but_func_rename_set(but, renamebutton_cb, file); + UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */ + UI_but_flag_disable(but, UI_BUT_UNDO); + if (false == UI_but_active_only(C, ar, block, but)) { + file_selflag = filelist_entry_select_set( + sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL); + } + } + + if (!(file_selflag & FILE_SEL_EDITING)) { + int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : + sy; + file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col); + } + + sx += (int)layout->column_widths[COLUMN_NAME] + column_space; + if (params->display == FILE_SHORTDISPLAY) { + if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || + !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { + if ((file->entry->size_str[0] == '\0') || update_stat_strings) { + BLI_filelist_entry_size_to_string( + NULL, file->entry->size, small_size, file->entry->size_str); + } + file_draw_string(sx, + sy, + file->entry->size_str, + layout->column_widths[COLUMN_SIZE], + layout->tile_h, + align, + text_col); + } + sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; + } + else if (params->display == FILE_LONGDISPLAY) { + if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) { + if ((file->entry->date_str[0] == '\0') || update_stat_strings) { + BLI_filelist_entry_datetime_to_string( + NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str); + } + file_draw_string(sx, + sy, + file->entry->date_str, + layout->column_widths[COLUMN_DATE], + layout->tile_h, + align, + text_col); + sx += (int)layout->column_widths[COLUMN_DATE] + column_space; + file_draw_string(sx, + sy, + file->entry->time_str, + layout->column_widths[COLUMN_TIME], + layout->tile_h, + align, + text_col); + sx += (int)layout->column_widths[COLUMN_TIME] + column_space; + } + else { + sx += (int)layout->column_widths[COLUMN_DATE] + column_space; + sx += (int)layout->column_widths[COLUMN_TIME] + column_space; + } + + if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || + !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { + if ((file->entry->size_str[0] == '\0') || update_stat_strings) { + BLI_filelist_entry_size_to_string( + NULL, file->entry->size, small_size, file->entry->size_str); + } + file_draw_string(sx, + sy, + file->entry->size_str, + layout->column_widths[COLUMN_SIZE], + layout->tile_h, + align, + text_col); + } + sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; + } + } + + BLF_batch_draw_end(); + + UI_block_end(C, block); + UI_block_draw(C, block); + + layout->curr_size = params->thumbnail_size; } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 46e30e556d1..bad25511dd5 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -42,7 +42,7 @@ struct ARegion *file_tools_region(struct ScrArea *sa); #define IMASEL_BUTTONS_HEIGHT (UI_UNIT_Y * 2) #define IMASEL_BUTTONS_MARGIN (UI_UNIT_Y / 6) -#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */ +#define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */ void file_draw_buttons(const bContext *C, ARegion *ar); void file_calc_previews(const bContext *C, ARegion *ar); @@ -57,10 +57,10 @@ struct wmOperator; struct wmOperatorType; typedef enum WalkSelectDirection { - FILE_SELECT_WALK_UP, - FILE_SELECT_WALK_DOWN, - FILE_SELECT_WALK_LEFT, - FILE_SELECT_WALK_RIGHT, + FILE_SELECT_WALK_UP, + FILE_SELECT_WALK_DOWN, + FILE_SELECT_WALK_LEFT, + FILE_SELECT_WALK_RIGHT, } WalkSelectDirections; void FILE_OT_highlight(struct wmOperatorType *ot); @@ -103,7 +103,10 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but); int file_highlight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my); void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath); -void file_sfile_to_operator_ex(bContext *C, struct wmOperator *op, struct SpaceFile *sfile, char *filepath); +void file_sfile_to_operator_ex(bContext *C, + struct wmOperator *op, + struct SpaceFile *sfile, + char *filepath); void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile); void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 482774c8131..073b6d0f487 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -69,161 +69,158 @@ /* ---------- FILE SELECTION ------------ */ static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *ar, const rcti *rect_region) { - FileSelection sel; + FileSelection sel; - View2D *v2d = &ar->v2d; - rcti rect_view; - rctf rect_view_fl; - rctf rect_region_fl; + View2D *v2d = &ar->v2d; + rcti rect_view; + rctf rect_view_fl; + rctf rect_region_fl; - BLI_rctf_rcti_copy(&rect_region_fl, rect_region); + BLI_rctf_rcti_copy(&rect_region_fl, rect_region); - UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl); + UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl); - BLI_rcti_init(&rect_view, - (int)(v2d->tot.xmin + rect_view_fl.xmin), - (int)(v2d->tot.xmin + rect_view_fl.xmax), - (int)(v2d->tot.ymax - rect_view_fl.ymin), - (int)(v2d->tot.ymax - rect_view_fl.ymax)); + BLI_rcti_init(&rect_view, + (int)(v2d->tot.xmin + rect_view_fl.xmin), + (int)(v2d->tot.xmin + rect_view_fl.xmax), + (int)(v2d->tot.ymax - rect_view_fl.ymin), + (int)(v2d->tot.ymax - rect_view_fl.ymax)); - sel = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view); + sel = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view); - return sel; + return sel; } static void file_deselect_all(SpaceFile *sfile, unsigned int flag) { - FileSelection sel; - sel.first = 0; - sel.last = filelist_files_ensure(sfile->files) - 1; + FileSelection sel; + sel.first = 0; + sel.last = filelist_files_ensure(sfile->files) - 1; - filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL); + filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL); } typedef enum FileSelect { - FILE_SELECT_NOTHING = 0, - FILE_SELECT_DIR = 1, - FILE_SELECT_FILE = 2, + FILE_SELECT_NOTHING = 0, + FILE_SELECT_DIR = 1, + FILE_SELECT_FILE = 2, } FileSelect; static void clamp_to_filelist(int numfiles, FileSelection *sel) { - /* box select before the first file */ - if ( (sel->first < 0) && (sel->last >= 0) ) { - sel->first = 0; - } - /* don't select if everything is outside filelist */ - if ( (sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles)) ) { - sel->first = -1; - sel->last = -1; - } - - /* fix if last file invalid */ - if ( (sel->first > 0) && (sel->last < 0) ) - sel->last = numfiles - 1; - - /* clamp */ - if ( (sel->first >= numfiles) ) { - sel->first = numfiles - 1; - } - if ( (sel->last >= numfiles) ) { - sel->last = numfiles - 1; - } + /* box select before the first file */ + if ((sel->first < 0) && (sel->last >= 0)) { + sel->first = 0; + } + /* don't select if everything is outside filelist */ + if ((sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles))) { + sel->first = -1; + sel->last = -1; + } + + /* fix if last file invalid */ + if ((sel->first > 0) && (sel->last < 0)) + sel->last = numfiles - 1; + + /* clamp */ + if ((sel->first >= numfiles)) { + sel->first = numfiles - 1; + } + if ((sel->last >= numfiles)) { + sel->last = numfiles - 1; + } } static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill) { - ARegion *ar = CTX_wm_region(C); - SpaceFile *sfile = CTX_wm_space_file(C); - int numfiles = filelist_files_ensure(sfile->files); - FileSelection sel; - - sel = find_file_mouse_rect(sfile, ar, rect); - if (!((sel.first == -1) && (sel.last == -1)) ) { - clamp_to_filelist(numfiles, &sel); - } - - - /* if desired, fill the selection up from the last selected file to the current one */ - if (fill && (sel.last >= 0) && (sel.last < numfiles) ) { - int f; - /* Try to find a smaller-index selected item. */ - for (f = sel.last; f >= 0; f--) { - if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) ) - break; - } - if (f >= 0) { - sel.first = f + 1; - } - /* If none found, try to find a higher-index selected item. */ - else { - for (f = sel.first; f < numfiles; f++) { - if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) ) - break; - } - if (f < numfiles) { - sel.last = f - 1; - } - } - } - return sel; + ARegion *ar = CTX_wm_region(C); + SpaceFile *sfile = CTX_wm_space_file(C); + int numfiles = filelist_files_ensure(sfile->files); + FileSelection sel; + + sel = find_file_mouse_rect(sfile, ar, rect); + if (!((sel.first == -1) && (sel.last == -1))) { + clamp_to_filelist(numfiles, &sel); + } + + /* if desired, fill the selection up from the last selected file to the current one */ + if (fill && (sel.last >= 0) && (sel.last < numfiles)) { + int f; + /* Try to find a smaller-index selected item. */ + for (f = sel.last; f >= 0; f--) { + if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL)) + break; + } + if (f >= 0) { + sel.first = f + 1; + } + /* If none found, try to find a higher-index selected item. */ + else { + for (f = sel.first; f < numfiles; f++) { + if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL)) + break; + } + if (f < numfiles) { + sel.last = f - 1; + } + } + } + return sel; } static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) { - Main *bmain = CTX_data_main(C); - FileSelect retval = FILE_SELECT_NOTHING; - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - int numfiles = filelist_files_ensure(sfile->files); - const FileDirEntry *file; - - /* make the selected file active */ - if ((selected_idx >= 0) && - (selected_idx < numfiles) && - (file = filelist_file(sfile->files, selected_idx))) - { - params->highlight_file = selected_idx; - params->active_file = selected_idx; - - if (file->typeflag & FILE_TYPE_DIR) { - const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath); - - if (do_diropen == false) { - params->file[0] = '\0'; - retval = FILE_SELECT_DIR; - } - /* the path is too long and we are not going up! */ - else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) { - // XXX error("Path too long, cannot enter this directory"); - } - else { - if (is_parent_dir) { - /* avoids /../../ */ - BLI_parent_dir(params->dir); - - if (params->recursion_level > 1) { - /* Disable 'dirtree' recursion when going up in tree. */ - params->recursion_level = 0; - filelist_setrecursion(sfile->files, params->recursion_level); - } - } - else { - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); - strcat(params->dir, file->relpath); - BLI_add_slash(params->dir); - } - - ED_file_change_dir(C); - retval = FILE_SELECT_DIR; - } - } - else { - retval = FILE_SELECT_FILE; - } - fileselect_file_set(sfile, selected_idx); - } - return retval; + Main *bmain = CTX_data_main(C); + FileSelect retval = FILE_SELECT_NOTHING; + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_params(sfile); + int numfiles = filelist_files_ensure(sfile->files); + const FileDirEntry *file; + + /* make the selected file active */ + if ((selected_idx >= 0) && (selected_idx < numfiles) && + (file = filelist_file(sfile->files, selected_idx))) { + params->highlight_file = selected_idx; + params->active_file = selected_idx; + + if (file->typeflag & FILE_TYPE_DIR) { + const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath); + + if (do_diropen == false) { + params->file[0] = '\0'; + retval = FILE_SELECT_DIR; + } + /* the path is too long and we are not going up! */ + else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) { + // XXX error("Path too long, cannot enter this directory"); + } + else { + if (is_parent_dir) { + /* avoids /../../ */ + BLI_parent_dir(params->dir); + + if (params->recursion_level > 1) { + /* Disable 'dirtree' recursion when going up in tree. */ + params->recursion_level = 0; + filelist_setrecursion(sfile->files, params->recursion_level); + } + } + else { + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); + strcat(params->dir, file->relpath); + BLI_add_slash(params->dir); + } + + ED_file_change_dir(C); + retval = FILE_SELECT_DIR; + } + } + else { + retval = FILE_SELECT_FILE; + } + fileselect_file_set(sfile, selected_idx); + } + return retval; } /** @@ -231,17 +228,17 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) */ static bool file_is_any_selected(struct FileList *files) { - const int numfiles = filelist_files_ensure(files); - int i; + const int numfiles = filelist_files_ensure(files); + int i; - /* Is any file selected ? */ - for (i = 0; i < numfiles; ++i) { - if (filelist_entry_select_index_get(files, i, CHECK_ALL)) { - return true; - } - } + /* Is any file selected ? */ + for (i = 0; i < numfiles; ++i) { + if (filelist_entry_select_index_get(files, i, CHECK_ALL)) { + return true; + } + } - return false; + return false; } /** @@ -249,577 +246,607 @@ static bool file_is_any_selected(struct FileList *files) */ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const int file) { - FileLayout *layout = ED_fileselect_get_layout(sfile, ar); - rctf *cur = &ar->v2d.cur; - rcti rect; - bool changed = true; - - file_tile_boundbox(ar, layout, file, &rect); - - /* down - also use if tile is higher than viewbounds so view is aligned to file name */ - if (cur->ymin > rect.ymin || layout->tile_h > ar->winy) { - cur->ymin = rect.ymin - (2 * layout->tile_border_y); - cur->ymax = cur->ymin + ar->winy; - } - /* up */ - else if (cur->ymax < rect.ymax) { - cur->ymax = rect.ymax + layout->tile_border_y; - cur->ymin = cur->ymax - ar->winy; - } - /* left - also use if tile is wider than viewbounds so view is aligned to file name */ - else if (cur->xmin > rect.xmin || layout->tile_w > ar->winx) { - cur->xmin = rect.xmin - layout->tile_border_x; - cur->xmax = cur->xmin + ar->winx; - } - /* right */ - else if (cur->xmax < rect.xmax) { - cur->xmax = rect.xmax + (2 * layout->tile_border_x); - cur->xmin = cur->xmax - ar->winx; - } - else { - BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && - cur->ymin <= rect.ymin && cur->ymax >= rect.ymax); - changed = false; - } - - if (changed) { - UI_view2d_curRect_validate(&ar->v2d); - } -} - - -static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) -{ - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelect retval = FILE_SELECT_NOTHING; - FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */ - const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL; - - /* flag the files as selected in the filelist */ - filelist_entries_select_index_range_set(sfile->files, &sel, select, FILE_SEL_SELECTED, check_type); - - /* Don't act on multiple selected files */ - if (sel.first != sel.last) select = 0; - - /* Do we have a valid selection and are we actually selecting */ - if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) { - /* Check last selection, if selected, act on the file or dir */ - if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) { - retval = file_select_do(C, sel.last, do_diropen); - } - } - - if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) { - sfile->params->active_file = -1; - } - else { - ARegion *ar = CTX_wm_region(C); - const FileLayout *layout = ED_fileselect_get_layout(sfile, ar); - - /* Adjust view to display selection. Doing iterations for first and last - * selected item makes view showing as much of the selection possible. - * Not really useful if tiles are (almost) bigger than viewbounds though. */ - if (((layout->flag & FILE_LAYOUT_HOR) && ar->winx > (1.2f * layout->tile_w)) || - ((layout->flag & FILE_LAYOUT_VER) && ar->winy > (2.0f * layout->tile_h))) - { - file_ensure_inside_viewbounds(ar, sfile, sel.last); - file_ensure_inside_viewbounds(ar, sfile, sel.first); - } - } - - /* update operator for name change event */ - file_draw_check(C); - - return retval; -} - -static int file_box_select_find_last_selected( - SpaceFile *sfile, ARegion *ar, const FileSelection *sel, - const int mouse_xy[2]) -{ - FileLayout *layout = ED_fileselect_get_layout(sfile, ar); - rcti bounds_first, bounds_last; - int dist_first, dist_last; - float mouseco_view[2]; - - UI_view2d_region_to_view(&ar->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]); - - file_tile_boundbox(ar, layout, sel->first, &bounds_first); - file_tile_boundbox(ar, layout, sel->last, &bounds_last); - - /* are first and last in the same column (horizontal layout)/row (vertical layout)? */ - if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) || - (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin)) - { - /* use vertical distance */ - const int my_loc = (int)mouseco_view[1]; - dist_first = BLI_rcti_length_y(&bounds_first, my_loc); - dist_last = BLI_rcti_length_y(&bounds_last, my_loc); - } - else { - /* use horizontal distance */ - const int mx_loc = (int)mouseco_view[0]; - dist_first = BLI_rcti_length_x(&bounds_first, mx_loc); - dist_last = BLI_rcti_length_x(&bounds_last, mx_loc); - } - - return (dist_first < dist_last) ? sel->first : sel->last; + FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + rctf *cur = &ar->v2d.cur; + rcti rect; + bool changed = true; + + file_tile_boundbox(ar, layout, file, &rect); + + /* down - also use if tile is higher than viewbounds so view is aligned to file name */ + if (cur->ymin > rect.ymin || layout->tile_h > ar->winy) { + cur->ymin = rect.ymin - (2 * layout->tile_border_y); + cur->ymax = cur->ymin + ar->winy; + } + /* up */ + else if (cur->ymax < rect.ymax) { + cur->ymax = rect.ymax + layout->tile_border_y; + cur->ymin = cur->ymax - ar->winy; + } + /* left - also use if tile is wider than viewbounds so view is aligned to file name */ + else if (cur->xmin > rect.xmin || layout->tile_w > ar->winx) { + cur->xmin = rect.xmin - layout->tile_border_x; + cur->xmax = cur->xmin + ar->winx; + } + /* right */ + else if (cur->xmax < rect.xmax) { + cur->xmax = rect.xmax + (2 * layout->tile_border_x); + cur->xmin = cur->xmax - ar->winx; + } + else { + BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin && + cur->ymax >= rect.ymax); + changed = false; + } + + if (changed) { + UI_view2d_curRect_validate(&ar->v2d); + } +} + +static FileSelect file_select( + bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) +{ + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelect retval = FILE_SELECT_NOTHING; + FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */ + const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : + CHECK_ALL; + + /* flag the files as selected in the filelist */ + filelist_entries_select_index_range_set( + sfile->files, &sel, select, FILE_SEL_SELECTED, check_type); + + /* Don't act on multiple selected files */ + if (sel.first != sel.last) + select = 0; + + /* Do we have a valid selection and are we actually selecting */ + if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) { + /* Check last selection, if selected, act on the file or dir */ + if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) { + retval = file_select_do(C, sel.last, do_diropen); + } + } + + if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) { + sfile->params->active_file = -1; + } + else { + ARegion *ar = CTX_wm_region(C); + const FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + + /* Adjust view to display selection. Doing iterations for first and last + * selected item makes view showing as much of the selection possible. + * Not really useful if tiles are (almost) bigger than viewbounds though. */ + if (((layout->flag & FILE_LAYOUT_HOR) && ar->winx > (1.2f * layout->tile_w)) || + ((layout->flag & FILE_LAYOUT_VER) && ar->winy > (2.0f * layout->tile_h))) { + file_ensure_inside_viewbounds(ar, sfile, sel.last); + file_ensure_inside_viewbounds(ar, sfile, sel.first); + } + } + + /* update operator for name change event */ + file_draw_check(C); + + return retval; +} + +static int file_box_select_find_last_selected(SpaceFile *sfile, + ARegion *ar, + const FileSelection *sel, + const int mouse_xy[2]) +{ + FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + rcti bounds_first, bounds_last; + int dist_first, dist_last; + float mouseco_view[2]; + + UI_view2d_region_to_view(&ar->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]); + + file_tile_boundbox(ar, layout, sel->first, &bounds_first); + file_tile_boundbox(ar, layout, sel->last, &bounds_last); + + /* are first and last in the same column (horizontal layout)/row (vertical layout)? */ + if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) || + (layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin)) { + /* use vertical distance */ + const int my_loc = (int)mouseco_view[1]; + dist_first = BLI_rcti_length_y(&bounds_first, my_loc); + dist_last = BLI_rcti_length_y(&bounds_last, my_loc); + } + else { + /* use horizontal distance */ + const int mx_loc = (int)mouseco_view[0]; + dist_first = BLI_rcti_length_x(&bounds_first, mx_loc); + dist_last = BLI_rcti_length_x(&bounds_last, mx_loc); + } + + return (dist_first < dist_last) ? sel->first : sel->last; } static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - FileSelection sel; - rcti rect; + ARegion *ar = CTX_wm_region(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelection sel; + rcti rect; - int result; + int result; - result = WM_gesture_box_modal(C, op, event); + result = WM_gesture_box_modal(C, op, event); - if (result == OPERATOR_RUNNING_MODAL) { - WM_operator_properties_border_to_rcti(op, &rect); + if (result == OPERATOR_RUNNING_MODAL) { + WM_operator_properties_border_to_rcti(op, &rect); - BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); + BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); - sel = file_selection_get(C, &rect, 0); - if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) { - int idx; + sel = file_selection_get(C, &rect, 0); + if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) { + int idx; - file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); - filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); + filelist_entries_select_index_range_set( + sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - for (idx = sel.last; idx >= 0; idx--) { - const FileDirEntry *file = filelist_file(sfile->files, idx); + for (idx = sel.last; idx >= 0; idx--) { + const FileDirEntry *file = filelist_file(sfile->files, idx); - /* dont highlight readonly file (".." or ".") on box select */ - if (FILENAME_IS_CURRPAR(file->relpath)) { - filelist_entry_select_set(sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL); - } + /* dont highlight readonly file (".." or ".") on box select */ + if (FILENAME_IS_CURRPAR(file->relpath)) { + filelist_entry_select_set( + sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL); + } - /* make sure highlight_file is no readonly file */ - if (sel.last == idx) { - params->highlight_file = idx; - } - } - } - params->sel_first = sel.first; params->sel_last = sel.last; - params->active_file = file_box_select_find_last_selected(sfile, ar, &sel, event->mval); - } - else { - params->highlight_file = -1; - params->sel_first = params->sel_last = -1; - fileselect_file_set(sfile, params->active_file); - file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - } + /* make sure highlight_file is no readonly file */ + if (sel.last == idx) { + params->highlight_file = idx; + } + } + } + params->sel_first = sel.first; + params->sel_last = sel.last; + params->active_file = file_box_select_find_last_selected(sfile, ar, &sel, event->mval); + } + else { + params->highlight_file = -1; + params->sel_first = params->sel_last = -1; + fileselect_file_set(sfile, params->active_file); + file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + } - return result; + return result; } static int file_box_select_exec(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); - SpaceFile *sfile = CTX_wm_space_file(C); - rcti rect; - FileSelect ret; + ARegion *ar = CTX_wm_region(C); + SpaceFile *sfile = CTX_wm_space_file(C); + rcti rect; + FileSelect ret; - WM_operator_properties_border_to_rcti(op, &rect); + WM_operator_properties_border_to_rcti(op, &rect); - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const bool select = (sel_op != SEL_OP_SUB); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - file_deselect_all(sfile, FILE_SEL_SELECTED); - } + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const bool select = (sel_op != SEL_OP_SUB); + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + file_deselect_all(sfile, FILE_SEL_SELECTED); + } - BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); + BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); - ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false); + ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false); - /* unselect '..' parent entry - it's not supposed to be selected if more than - * one file is selected */ - filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + /* unselect '..' parent entry - it's not supposed to be selected if more than + * one file is selected */ + filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); - if (FILE_SELECT_DIR == ret) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } - else if (FILE_SELECT_FILE == ret) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - } - return OPERATOR_FINISHED; + if (FILE_SELECT_DIR == ret) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + } + else if (FILE_SELECT_FILE == ret) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + } + return OPERATOR_FINISHED; } void FILE_OT_select_box(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Box Select"; - ot->description = "Activate/select the file(s) contained in the border"; - ot->idname = "FILE_OT_select_box"; + /* identifiers */ + ot->name = "Box Select"; + ot->description = "Activate/select the file(s) contained in the border"; + ot->idname = "FILE_OT_select_box"; - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = file_box_select_exec; - ot->modal = file_box_select_modal; - ot->poll = ED_operator_file_active; - ot->cancel = WM_gesture_box_cancel; + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = file_box_select_exec; + ot->modal = file_box_select_modal; + ot->poll = ED_operator_file_active; + ot->cancel = WM_gesture_box_cancel; - /* properties */ - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); + /* properties */ + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); } static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelect ret; - rcti rect; - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool fill = RNA_boolean_get(op->ptr, "fill"); - const bool do_diropen = RNA_boolean_get(op->ptr, "open"); + ARegion *ar = CTX_wm_region(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelect ret; + rcti rect; + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool fill = RNA_boolean_get(op->ptr, "fill"); + const bool do_diropen = RNA_boolean_get(op->ptr, "open"); - if (ar->regiontype != RGN_TYPE_WINDOW) - return OPERATOR_CANCELLED; + if (ar->regiontype != RGN_TYPE_WINDOW) + return OPERATOR_CANCELLED; - rect.xmin = rect.xmax = event->mval[0]; - rect.ymin = rect.ymax = event->mval[1]; + rect.xmin = rect.xmax = event->mval[0]; + rect.ymin = rect.ymax = event->mval[1]; - if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) - return OPERATOR_CANCELLED; + if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) + return OPERATOR_CANCELLED; - if (sfile && sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); + if (sfile && sfile->params) { + int idx = sfile->params->highlight_file; + int numfiles = filelist_files_ensure(sfile->files); - if ((idx >= 0) && (idx < numfiles)) { - /* single select, deselect all selected first */ - if (!extend) { - file_deselect_all(sfile, FILE_SEL_SELECTED); - } - } - } + if ((idx >= 0) && (idx < numfiles)) { + /* single select, deselect all selected first */ + if (!extend) { + file_deselect_all(sfile, FILE_SEL_SELECTED); + } + } + } - ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen); + ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen); - if (extend) { - /* unselect '..' parent entry - it's not supposed to be selected if more - * than one file is selected */ - filelist_entry_select_index_set(sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); - } + if (extend) { + /* unselect '..' parent entry - it's not supposed to be selected if more + * than one file is selected */ + filelist_entry_select_index_set( + sfile->files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + } - if (FILE_SELECT_DIR == ret) - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - else if (FILE_SELECT_FILE == ret) - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + if (FILE_SELECT_DIR == ret) + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + else if (FILE_SELECT_FILE == ret) + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - WM_event_add_mousemove(C); /* for directory changes */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + WM_event_add_mousemove(C); /* for directory changes */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FILE_OT_select(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select"; - ot->description = "Activate/select file"; - ot->idname = "FILE_OT_select"; + /* identifiers */ + ot->name = "Select"; + ot->description = "Activate/select file"; + ot->idname = "FILE_OT_select"; - /* api callbacks */ - ot->invoke = file_select_invoke; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->invoke = file_select_invoke; + ot->poll = ED_operator_file_active; - /* properties */ - prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + prop = RNA_def_boolean(ot->srna, + "extend", + false, + "Extend", + "Extend selection instead of deselecting everything first"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** * \returns true if selection has changed */ -static bool file_walk_select_selection_set( - bContext *C, SpaceFile *sfile, - const int direction, const int numfiles, - const int active_old, const int active_new, const int other_site, - const bool has_selection, const bool extend, const bool fill) -{ - FileSelectParams *params = sfile->params; - struct FileList *files = sfile->files; - const int last_sel = params->active_file; /* store old value */ - int active = active_old; /* could use active_old instead, just for readability */ - bool deselect = false; - - BLI_assert(params); - - if (has_selection) { - if (extend && - filelist_entry_select_index_get(files, active_old, CHECK_ALL) && - filelist_entry_select_index_get(files, active_new, CHECK_ALL)) - { - /* conditions for deselecting: initial file is selected, new file is - * selected and either other_side isn't selected/found or we use fill */ - deselect = (fill || other_site == -1 || - !filelist_entry_select_index_get(files, other_site, CHECK_ALL)); - - /* don't change highlight_file here since we either want to deselect active or we want - * to walk through a block of selected files without selecting/deselecting anything */ - params->active_file = active_new; - /* but we want to change active if we use fill - * (needed to get correct selection bounds) */ - if (deselect && fill) { - active = active_new; - } - } - else { - /* regular selection change */ - params->active_file = active = active_new; - } - } - else { - /* select last file */ - if (ELEM(direction, FILE_SELECT_WALK_UP, FILE_SELECT_WALK_LEFT)) { - params->active_file = active = numfiles - 1; - } - /* select first file */ - else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) { - params->active_file = active = extend ? 1 : 0; - } - else { - BLI_assert(0); - } - } - - if (active < 0) { - return false; - } - - if (extend) { - /* highlight the active walker file for extended selection for better visual feedback */ - params->highlight_file = params->active_file; - - /* unselect '..' parent entry - it's not supposed to be selected if more - * than one file is selected */ - filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); - } - else { - /* deselect all first */ - file_deselect_all(sfile, FILE_SEL_SELECTED); - - /* highlight file under mouse pos */ - params->highlight_file = -1; - WM_event_add_mousemove(C); - } - - /* do the actual selection */ - if (fill) { - FileSelection sel = { MIN2(active, last_sel), MAX2(active, last_sel) }; - - /* clamping selection to not include '..' parent entry */ - if (sel.first == 0) { - sel.first = 1; - } - - /* fill selection between last and first selected file */ - filelist_entries_select_index_range_set( - files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); - /* entire sel is cleared here, so select active again */ - if (deselect) { - filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); - } - } - else { - filelist_entry_select_index_set( - files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); - } - - BLI_assert(IN_RANGE(active, -1, numfiles)); - fileselect_file_set(sfile, params->active_file); - - /* ensure newly selected file is inside viewbounds */ - file_ensure_inside_viewbounds(CTX_wm_region(C), sfile, params->active_file); - - /* selection changed */ - return true; +static bool file_walk_select_selection_set(bContext *C, + SpaceFile *sfile, + const int direction, + const int numfiles, + const int active_old, + const int active_new, + const int other_site, + const bool has_selection, + const bool extend, + const bool fill) +{ + FileSelectParams *params = sfile->params; + struct FileList *files = sfile->files; + const int last_sel = params->active_file; /* store old value */ + int active = active_old; /* could use active_old instead, just for readability */ + bool deselect = false; + + BLI_assert(params); + + if (has_selection) { + if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) && + filelist_entry_select_index_get(files, active_new, CHECK_ALL)) { + /* conditions for deselecting: initial file is selected, new file is + * selected and either other_side isn't selected/found or we use fill */ + deselect = (fill || other_site == -1 || + !filelist_entry_select_index_get(files, other_site, CHECK_ALL)); + + /* don't change highlight_file here since we either want to deselect active or we want + * to walk through a block of selected files without selecting/deselecting anything */ + params->active_file = active_new; + /* but we want to change active if we use fill + * (needed to get correct selection bounds) */ + if (deselect && fill) { + active = active_new; + } + } + else { + /* regular selection change */ + params->active_file = active = active_new; + } + } + else { + /* select last file */ + if (ELEM(direction, FILE_SELECT_WALK_UP, FILE_SELECT_WALK_LEFT)) { + params->active_file = active = numfiles - 1; + } + /* select first file */ + else if (ELEM(direction, FILE_SELECT_WALK_DOWN, FILE_SELECT_WALK_RIGHT)) { + params->active_file = active = extend ? 1 : 0; + } + else { + BLI_assert(0); + } + } + + if (active < 0) { + return false; + } + + if (extend) { + /* highlight the active walker file for extended selection for better visual feedback */ + params->highlight_file = params->active_file; + + /* unselect '..' parent entry - it's not supposed to be selected if more + * than one file is selected */ + filelist_entry_select_index_set(files, 0, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + } + else { + /* deselect all first */ + file_deselect_all(sfile, FILE_SEL_SELECTED); + + /* highlight file under mouse pos */ + params->highlight_file = -1; + WM_event_add_mousemove(C); + } + + /* do the actual selection */ + if (fill) { + FileSelection sel = {MIN2(active, last_sel), MAX2(active, last_sel)}; + + /* clamping selection to not include '..' parent entry */ + if (sel.first == 0) { + sel.first = 1; + } + + /* fill selection between last and first selected file */ + filelist_entries_select_index_range_set( + files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + /* entire sel is cleared here, so select active again */ + if (deselect) { + filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + } + } + else { + filelist_entry_select_index_set( + files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + } + + BLI_assert(IN_RANGE(active, -1, numfiles)); + fileselect_file_set(sfile, params->active_file); + + /* ensure newly selected file is inside viewbounds */ + file_ensure_inside_viewbounds(CTX_wm_region(C), sfile, params->active_file); + + /* selection changed */ + return true; } /** * \returns true if selection has changed */ -static bool file_walk_select_do( - bContext *C, SpaceFile *sfile, - FileSelectParams *params, const int direction, - const bool extend, const bool fill) -{ - struct FileList *files = sfile->files; - const int numfiles = filelist_files_ensure(files); - const bool has_selection = file_is_any_selected(files); - const int active_old = params->active_file; - int active_new = -1; - int other_site = -1; /* file on the other site of active_old */ - - - /* *** get all needed files for handling selection *** */ - - if (has_selection) { - ARegion *ar = CTX_wm_region(C); - FileLayout *layout = ED_fileselect_get_layout(sfile, ar); - const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns; - - if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) || - (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) - { - active_new = active_old - 1; - other_site = active_old + 1; - } - else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_DOWN) || - (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_RIGHT)) - { - active_new = active_old + 1; - other_site = active_old - 1; - } - else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_LEFT) || - (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_UP)) - { - active_new = active_old - idx_shift; - other_site = active_old + idx_shift; - } - else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_RIGHT) || - (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_DOWN)) - { - - active_new = active_old + idx_shift; - other_site = active_old - idx_shift; - } - else { - BLI_assert(0); - } - - if (!IN_RANGE(active_new, 0, numfiles)) { - if (extend) { - /* extend to invalid file -> abort */ - return false; - } - /* if we don't extend, selecting '..' (index == 0) is allowed so - * using key selection to go to parent directory is possible */ - else if (active_new != 0) { - /* select initial file */ - active_new = active_old; - } - } - if (!IN_RANGE(other_site, 0, numfiles)) { - other_site = -1; - } - } - - return file_walk_select_selection_set( - C, sfile, direction, numfiles, active_old, active_new, other_site, has_selection, extend, fill); +static bool file_walk_select_do(bContext *C, + SpaceFile *sfile, + FileSelectParams *params, + const int direction, + const bool extend, + const bool fill) +{ + struct FileList *files = sfile->files; + const int numfiles = filelist_files_ensure(files); + const bool has_selection = file_is_any_selected(files); + const int active_old = params->active_file; + int active_new = -1; + int other_site = -1; /* file on the other site of active_old */ + + /* *** get all needed files for handling selection *** */ + + if (has_selection) { + ARegion *ar = CTX_wm_region(C); + FileLayout *layout = ED_fileselect_get_layout(sfile, ar); + const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns; + + if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) { + active_new = active_old - 1; + other_site = active_old + 1; + } + else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_DOWN) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_RIGHT)) { + active_new = active_old + 1; + other_site = active_old - 1; + } + else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_LEFT) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_UP)) { + active_new = active_old - idx_shift; + other_site = active_old + idx_shift; + } + else if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_RIGHT) || + (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_DOWN)) { + + active_new = active_old + idx_shift; + other_site = active_old - idx_shift; + } + else { + BLI_assert(0); + } + + if (!IN_RANGE(active_new, 0, numfiles)) { + if (extend) { + /* extend to invalid file -> abort */ + return false; + } + /* if we don't extend, selecting '..' (index == 0) is allowed so + * using key selection to go to parent directory is possible */ + else if (active_new != 0) { + /* select initial file */ + active_new = active_old; + } + } + if (!IN_RANGE(other_site, 0, numfiles)) { + other_site = -1; + } + } + + return file_walk_select_selection_set(C, + sfile, + direction, + numfiles, + active_old, + active_new, + other_site, + has_selection, + extend, + fill); } static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - FileSelectParams *params = sfile->params; - const int direction = RNA_enum_get(op->ptr, "direction"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool fill = RNA_boolean_get(op->ptr, "fill"); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + FileSelectParams *params = sfile->params; + const int direction = RNA_enum_get(op->ptr, "direction"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool fill = RNA_boolean_get(op->ptr, "fill"); - if (file_walk_select_do(C, sfile, params, direction, extend, fill)) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - return OPERATOR_FINISHED; - } + if (file_walk_select_do(C, sfile, params, direction, extend, fill)) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + return OPERATOR_FINISHED; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } void FILE_OT_select_walk(wmOperatorType *ot) { - static const EnumPropertyItem direction_items[] = { - {FILE_SELECT_WALK_UP, "UP", 0, "Prev", ""}, - {FILE_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""}, - {FILE_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""}, - {FILE_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""}, - {0, NULL, 0, NULL, NULL}, - }; - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Walk Select/Deselect File"; - ot->description = "Select/Deselect files by walking through them"; - ot->idname = "FILE_OT_select_walk"; - - /* api callbacks */ - ot->invoke = file_walk_select_invoke; - ot->poll = ED_operator_file_active; - - /* properties */ - prop = RNA_def_enum(ot->srna, "direction", direction_items, 0, "Walk Direction", - "Select/Deselect file in this direction"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", - "Extend selection instead of deselecting everything first"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + static const EnumPropertyItem direction_items[] = { + {FILE_SELECT_WALK_UP, "UP", 0, "Prev", ""}, + {FILE_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""}, + {FILE_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""}, + {FILE_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""}, + {0, NULL, 0, NULL, NULL}, + }; + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Walk Select/Deselect File"; + ot->description = "Select/Deselect files by walking through them"; + ot->idname = "FILE_OT_select_walk"; + + /* api callbacks */ + ot->invoke = file_walk_select_invoke; + ot->poll = ED_operator_file_active; + + /* properties */ + prop = RNA_def_enum(ot->srna, + "direction", + direction_items, + 0, + "Walk Direction", + "Select/Deselect file in this direction"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, + "extend", + false, + "Extend", + "Extend selection instead of deselecting everything first"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelection sel; - const int numfiles = filelist_files_ensure(sfile->files); - const bool has_selection = file_is_any_selected(sfile->files); - - sel.first = 0; - sel.last = numfiles - 1; - - /* select all only if previously no file was selected */ - if (has_selection) { - filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); - sfile->params->active_file = -1; - } - else { - const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; - int i; - - filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type); - - /* set active_file to first selected */ - for (i = 0; i < numfiles; i++) { - if (filelist_entry_select_index_get(sfile->files, i, check_type)) { - sfile->params->active_file = i; - break; - } - } - } - - file_draw_check(C); - WM_event_add_mousemove(C); - ED_area_tag_redraw(sa); - - return OPERATOR_FINISHED; + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelection sel; + const int numfiles = filelist_files_ensure(sfile->files); + const bool has_selection = file_is_any_selected(sfile->files); + + sel.first = 0; + sel.last = numfiles - 1; + + /* select all only if previously no file was selected */ + if (has_selection) { + filelist_entries_select_index_range_set( + sfile->files, &sel, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + sfile->params->active_file = -1; + } + else { + const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : + CHECK_FILES; + int i; + + filelist_entries_select_index_range_set( + sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_SELECTED, check_type); + + /* set active_file to first selected */ + for (i = 0; i < numfiles; i++) { + if (filelist_entry_select_index_get(sfile->files, i, check_type)) { + sfile->params->active_file = i; + break; + } + } + } + + file_draw_check(C); + WM_event_add_mousemove(C); + ED_area_tag_redraw(sa); + + return OPERATOR_FINISHED; } void FILE_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "(De)select All Files"; - ot->description = "Select or deselect all files"; - ot->idname = "FILE_OT_select_all"; + /* identifiers */ + ot->name = "(De)select All Files"; + ot->description = "Select or deselect all files"; + ot->idname = "FILE_OT_select_all"; - /* api callbacks */ - ot->exec = file_select_all_exec; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->exec = file_select_all_exec; + ot->poll = ED_operator_file_active; - /* properties */ + /* properties */ } /* ---------- BOOKMARKS ----------- */ @@ -828,487 +855,500 @@ void FILE_OT_select_all(wmOperatorType *ot) * Does not hurt keeping it around for now. */ static int bookmark_select_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceFile *sfile = CTX_wm_space_file(C); - PropertyRNA *prop; + Main *bmain = CTX_data_main(C); + SpaceFile *sfile = CTX_wm_space_file(C); + PropertyRNA *prop; - if ((prop = RNA_struct_find_property(op->ptr, "dir"))) { - char entry[256]; - FileSelectParams *params = sfile->params; + if ((prop = RNA_struct_find_property(op->ptr, "dir"))) { + char entry[256]; + FileSelectParams *params = sfile->params; - RNA_property_string_get(op->ptr, prop, entry); - BLI_strncpy(params->dir, entry, sizeof(params->dir)); - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); - ED_file_change_dir(C); + RNA_property_string_get(op->ptr, prop, entry); + BLI_strncpy(params->dir, entry, sizeof(params->dir)); + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); + ED_file_change_dir(C); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FILE_OT_select_bookmark(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select Directory"; - ot->description = "Select a bookmarked directory"; - ot->idname = "FILE_OT_select_bookmark"; + /* identifiers */ + ot->name = "Select Directory"; + ot->description = "Select a bookmarked directory"; + ot->idname = "FILE_OT_select_bookmark"; - /* api callbacks */ - ot->exec = bookmark_select_exec; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->exec = bookmark_select_exec; + ot->poll = ED_operator_file_active; - /* properties */ - prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Dir", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Dir", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = CTX_wm_space_file(C); - struct FSMenu *fsmenu = ED_fsmenu_get(); - struct FileSelectParams *params = ED_fileselect_get_params(sfile); + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = CTX_wm_space_file(C); + struct FSMenu *fsmenu = ED_fsmenu_get(); + struct FileSelectParams *params = ED_fileselect_get_params(sfile); - if (params->dir[0] != '\0') { - char name[FILE_MAX]; + if (params->dir[0] != '\0') { + char name[FILE_MAX]; - fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, FS_INSERT_SAVE); - BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(fsmenu, name); - } + fsmenu_insert_entry(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, FS_INSERT_SAVE); + BLI_make_file_string( + "/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + fsmenu_write_file(fsmenu, name); + } - ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); - return OPERATOR_FINISHED; + ED_area_tag_refresh(sa); + ED_area_tag_redraw(sa); + return OPERATOR_FINISHED; } void FILE_OT_bookmark_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Bookmark"; - ot->description = "Add a bookmark for the selected/active directory"; - ot->idname = "FILE_OT_bookmark_add"; + /* identifiers */ + ot->name = "Add Bookmark"; + ot->description = "Add a bookmark for the selected/active directory"; + ot->idname = "FILE_OT_bookmark_add"; - /* api callbacks */ - ot->exec = bookmark_add_exec; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->exec = bookmark_add_exec; + ot->poll = ED_operator_file_active; } static int bookmark_delete_exec(bContext *C, wmOperator *op) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = CTX_wm_space_file(C); - struct FSMenu *fsmenu = ED_fsmenu_get(); - int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS); - - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index"); - - if (prop) { - int index; - if (RNA_property_is_set(op->ptr, prop)) { - index = RNA_property_int_get(op->ptr, prop); - } - else { /* if index unset, use active bookmark... */ - index = sfile->bookmarknr; - } - if ((index > -1) && (index < nentries)) { - char name[FILE_MAX]; - - fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index); - BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(fsmenu, name); - ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); - } - } - - return OPERATOR_FINISHED; + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = CTX_wm_space_file(C); + struct FSMenu *fsmenu = ED_fsmenu_get(); + int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS); + + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index"); + + if (prop) { + int index; + if (RNA_property_is_set(op->ptr, prop)) { + index = RNA_property_int_get(op->ptr, prop); + } + else { /* if index unset, use active bookmark... */ + index = sfile->bookmarknr; + } + if ((index > -1) && (index < nentries)) { + char name[FILE_MAX]; + + fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index); + BLI_make_file_string("/", + name, + BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLENDER_BOOKMARK_FILE); + fsmenu_write_file(fsmenu, name); + ED_area_tag_refresh(sa); + ED_area_tag_redraw(sa); + } + } + + return OPERATOR_FINISHED; } void FILE_OT_bookmark_delete(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Delete Bookmark"; - ot->description = "Delete selected bookmark"; - ot->idname = "FILE_OT_bookmark_delete"; + /* identifiers */ + ot->name = "Delete Bookmark"; + ot->description = "Delete selected bookmark"; + ot->idname = "FILE_OT_bookmark_delete"; - /* api callbacks */ - ot->exec = bookmark_delete_exec; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->exec = bookmark_delete_exec; + ot->poll = ED_operator_file_active; - /* properties */ - prop = RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + prop = RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *sa = CTX_wm_area(C); - struct FSMenu *fsmenu = ED_fsmenu_get(); - struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); - int index; - bool changed = false; + ScrArea *sa = CTX_wm_area(C); + struct FSMenu *fsmenu = ED_fsmenu_get(); + struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); + int index; + bool changed = false; - for (index = 0; fsme; fsme = fsme_next) { - fsme_next = fsme->next; + for (index = 0; fsme; fsme = fsme_next) { + fsme_next = fsme->next; - if (!BLI_is_dir(fsme->path)) { - fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index); - changed = true; - } - else { - index++; - } - } + if (!BLI_is_dir(fsme->path)) { + fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index); + changed = true; + } + else { + index++; + } + } - if (changed) { - char name[FILE_MAX]; + if (changed) { + char name[FILE_MAX]; - BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(fsmenu, name); - fsmenu_refresh_bookmarks_status(fsmenu); - ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); - } + BLI_make_file_string( + "/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + fsmenu_write_file(fsmenu, name); + fsmenu_refresh_bookmarks_status(fsmenu); + ED_area_tag_refresh(sa); + ED_area_tag_redraw(sa); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FILE_OT_bookmark_cleanup(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Cleanup Bookmarks"; - ot->description = "Delete all invalid bookmarks"; - ot->idname = "FILE_OT_bookmark_cleanup"; + /* identifiers */ + ot->name = "Cleanup Bookmarks"; + ot->description = "Delete all invalid bookmarks"; + ot->idname = "FILE_OT_bookmark_cleanup"; - /* api callbacks */ - ot->exec = bookmark_cleanup_exec; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->exec = bookmark_cleanup_exec; + ot->poll = ED_operator_file_active; - /* properties */ + /* properties */ } enum { - FILE_BOOKMARK_MOVE_TOP = -2, - FILE_BOOKMARK_MOVE_UP = -1, - FILE_BOOKMARK_MOVE_DOWN = 1, - FILE_BOOKMARK_MOVE_BOTTOM = 2, + FILE_BOOKMARK_MOVE_TOP = -2, + FILE_BOOKMARK_MOVE_UP = -1, + FILE_BOOKMARK_MOVE_DOWN = 1, + FILE_BOOKMARK_MOVE_BOTTOM = 2, }; static int bookmark_move_exec(bContext *C, wmOperator *op) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = CTX_wm_space_file(C); - struct FSMenu *fsmenu = ED_fsmenu_get(); - struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); - const struct FSMenuEntry *fsmentry_org = fsmentry; - - char fname[FILE_MAX]; - - const int direction = RNA_enum_get(op->ptr, "direction"); - const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS); - const int act_index = sfile->bookmarknr; - int new_index; - - if (totitems < 2) { - return OPERATOR_CANCELLED; - } - - switch (direction) { - case FILE_BOOKMARK_MOVE_TOP: - new_index = 0; - break; - case FILE_BOOKMARK_MOVE_BOTTOM: - new_index = totitems - 1; - break; - case FILE_BOOKMARK_MOVE_UP: - case FILE_BOOKMARK_MOVE_DOWN: - default: - new_index = (totitems + act_index + direction) % totitems; - break; - } - - if (new_index == act_index) { - return OPERATOR_CANCELLED; - } - - BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index); - if (fsmentry != fsmentry_org) { - ED_fsmenu_set_category(fsmenu, FS_CATEGORY_BOOKMARKS, fsmentry); - } - - /* Need to update active bookmark number. */ - sfile->bookmarknr = new_index; - - BLI_make_file_string("/", fname, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(fsmenu, fname); - - ED_area_tag_redraw(sa); - return OPERATOR_FINISHED; + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = CTX_wm_space_file(C); + struct FSMenu *fsmenu = ED_fsmenu_get(); + struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); + const struct FSMenuEntry *fsmentry_org = fsmentry; + + char fname[FILE_MAX]; + + const int direction = RNA_enum_get(op->ptr, "direction"); + const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS); + const int act_index = sfile->bookmarknr; + int new_index; + + if (totitems < 2) { + return OPERATOR_CANCELLED; + } + + switch (direction) { + case FILE_BOOKMARK_MOVE_TOP: + new_index = 0; + break; + case FILE_BOOKMARK_MOVE_BOTTOM: + new_index = totitems - 1; + break; + case FILE_BOOKMARK_MOVE_UP: + case FILE_BOOKMARK_MOVE_DOWN: + default: + new_index = (totitems + act_index + direction) % totitems; + break; + } + + if (new_index == act_index) { + return OPERATOR_CANCELLED; + } + + BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index); + if (fsmentry != fsmentry_org) { + ED_fsmenu_set_category(fsmenu, FS_CATEGORY_BOOKMARKS, fsmentry); + } + + /* Need to update active bookmark number. */ + sfile->bookmarknr = new_index; + + BLI_make_file_string( + "/", fname, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + fsmenu_write_file(fsmenu, fname); + + ED_area_tag_redraw(sa); + return OPERATOR_FINISHED; } void FILE_OT_bookmark_move(wmOperatorType *ot) { - static const EnumPropertyItem slot_move[] = { - {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"}, - {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""}, - {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""}, - {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"}, - { 0, NULL, 0, NULL, NULL } - }; + static const EnumPropertyItem slot_move[] = { + {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"}, + {FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""}, + {FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""}, + {FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"}, + {0, NULL, 0, NULL, NULL}}; - /* identifiers */ - ot->name = "Move Bookmark"; - ot->idname = "FILE_OT_bookmark_move"; - ot->description = "Move the active bookmark up/down in the list"; + /* identifiers */ + ot->name = "Move Bookmark"; + ot->idname = "FILE_OT_bookmark_move"; + ot->description = "Move the active bookmark up/down in the list"; - /* api callbacks */ - ot->poll = ED_operator_file_active; - ot->exec = bookmark_move_exec; + /* api callbacks */ + ot->poll = ED_operator_file_active; + ot->exec = bookmark_move_exec; - /* flags */ - ot->flag = OPTYPE_REGISTER; /* No undo! */ + /* flags */ + ot->flag = OPTYPE_REGISTER; /* No undo! */ - RNA_def_enum(ot->srna, "direction", slot_move, 0, "Direction", - "Direction to move the active bookmark towards"); + RNA_def_enum(ot->srna, + "direction", + slot_move, + 0, + "Direction", + "Direction to move the active bookmark towards"); } static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *sa = CTX_wm_area(C); - char name[FILE_MAX]; - struct FSMenu *fsmenu = ED_fsmenu_get(); + ScrArea *sa = CTX_wm_area(C); + char name[FILE_MAX]; + struct FSMenu *fsmenu = ED_fsmenu_get(); - while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) { - fsmenu_remove_entry(fsmenu, FS_CATEGORY_RECENT, 0); - } - BLI_make_file_string("/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(fsmenu, name); - ED_area_tag_redraw(sa); + while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) { + fsmenu_remove_entry(fsmenu, FS_CATEGORY_RECENT, 0); + } + BLI_make_file_string( + "/", name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); + fsmenu_write_file(fsmenu, name); + ED_area_tag_redraw(sa); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FILE_OT_reset_recent(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Reset Recent"; - ot->description = "Reset Recent files"; - ot->idname = "FILE_OT_reset_recent"; - - /* api callbacks */ - ot->exec = reset_recent_exec; - ot->poll = ED_operator_file_active; + /* identifiers */ + ot->name = "Reset Recent"; + ot->description = "Reset Recent files"; + ot->idname = "FILE_OT_reset_recent"; + /* api callbacks */ + ot->exec = reset_recent_exec; + ot->poll = ED_operator_file_active; } int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my) { - View2D *v2d = &ar->v2d; - FileSelectParams *params; - int numfiles, origfile; + View2D *v2d = &ar->v2d; + FileSelectParams *params; + int numfiles, origfile; - if (sfile == NULL || sfile->files == NULL) return 0; + if (sfile == NULL || sfile->files == NULL) + return 0; - numfiles = filelist_files_ensure(sfile->files); - params = ED_fileselect_get_params(sfile); + numfiles = filelist_files_ensure(sfile->files); + params = ED_fileselect_get_params(sfile); - origfile = params->highlight_file; + origfile = params->highlight_file; - mx -= ar->winrct.xmin; - my -= ar->winrct.ymin; + mx -= ar->winrct.xmin; + my -= ar->winrct.ymin; - if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) { - float fx, fy; - int highlight_file; + if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) { + float fx, fy; + int highlight_file; - UI_view2d_region_to_view(v2d, mx, my, &fx, &fy); + UI_view2d_region_to_view(v2d, mx, my, &fx, &fy); - highlight_file = ED_fileselect_layout_offset(sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy)); + highlight_file = ED_fileselect_layout_offset( + sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy)); - if ((highlight_file >= 0) && (highlight_file < numfiles)) - params->highlight_file = highlight_file; - else - params->highlight_file = -1; - } - else - params->highlight_file = -1; + if ((highlight_file >= 0) && (highlight_file < numfiles)) + params->highlight_file = highlight_file; + else + params->highlight_file = -1; + } + else + params->highlight_file = -1; - return (params->highlight_file != origfile); + return (params->highlight_file != origfile); } static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceFile *sfile = CTX_wm_space_file(C); + ARegion *ar = CTX_wm_region(C); + SpaceFile *sfile = CTX_wm_space_file(C); - if (!file_highlight_set(sfile, ar, event->x, event->y)) - return OPERATOR_PASS_THROUGH; + if (!file_highlight_set(sfile, ar, event->x, event->y)) + return OPERATOR_PASS_THROUGH; - ED_area_tag_redraw(CTX_wm_area(C)); + ED_area_tag_redraw(CTX_wm_area(C)); - return OPERATOR_PASS_THROUGH; + return OPERATOR_PASS_THROUGH; } void FILE_OT_highlight(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Highlight File"; - ot->description = "Highlight selected file(s)"; - ot->idname = "FILE_OT_highlight"; + /* identifiers */ + ot->name = "Highlight File"; + ot->description = "Highlight selected file(s)"; + ot->idname = "FILE_OT_highlight"; - /* api callbacks */ - ot->invoke = file_highlight_invoke; - ot->poll = ED_operator_file_active; + /* api callbacks */ + ot->invoke = file_highlight_invoke; + ot->poll = ED_operator_file_active; } int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused)) { - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - wmOperator *op = sfile->op; + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + wmOperator *op = sfile->op; - sfile->op = NULL; + sfile->op = NULL; - WM_event_fileselect_event(wm, op, EVT_FILESELECT_CANCEL); + WM_event_fileselect_event(wm, op, EVT_FILESELECT_CANCEL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static bool file_operator_poll(bContext *C) { - bool poll = ED_operator_file_active(C); - SpaceFile *sfile = CTX_wm_space_file(C); + bool poll = ED_operator_file_active(C); + SpaceFile *sfile = CTX_wm_space_file(C); - if (!sfile || !sfile->op) poll = 0; + if (!sfile || !sfile->op) + poll = 0; - return poll; + return poll; } void FILE_OT_cancel(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Cancel File Load"; - ot->description = "Cancel loading of selected file"; - ot->idname = "FILE_OT_cancel"; + /* identifiers */ + ot->name = "Cancel File Load"; + ot->description = "Cancel loading of selected file"; + ot->idname = "FILE_OT_cancel"; - /* api callbacks */ - ot->exec = file_cancel_exec; - ot->poll = file_operator_poll; + /* api callbacks */ + ot->exec = file_cancel_exec; + ot->poll = file_operator_poll; } - void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, char *filepath) { - Main *bmain = CTX_data_main(C); - PropertyRNA *prop; - - /* XXX, not real length */ - BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); - - if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { - if (RNA_property_boolean_get(op->ptr, prop)) { - BLI_path_rel(filepath, BKE_main_blendfile_path(bmain)); - } - } - - if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { - RNA_property_string_set(op->ptr, prop, sfile->params->file); - } - if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_set(op->ptr, prop, sfile->params->dir); - } - if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { - RNA_property_string_set(op->ptr, prop, filepath); - } - - /* some ops have multiple files to select */ - /* this is called on operators check() so clear collections first since - * they may be already set. */ - { - int i, numfiles = filelist_files_ensure(sfile->files); - - if ((prop = RNA_struct_find_property(op->ptr, "files"))) { - PointerRNA itemptr; - int num_files = 0; - RNA_property_collection_clear(op->ptr, prop); - for (i = 0; i < numfiles; i++) { - if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { - FileDirEntry *file = filelist_file(sfile->files, i); - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", file->relpath); - num_files++; - } - } - /* make sure the file specified in the filename button is added even if no - * files selected */ - if (0 == num_files) { - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", sfile->params->file); - } - } - - if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) { - PointerRNA itemptr; - int num_dirs = 0; - RNA_property_collection_clear(op->ptr, prop); - for (i = 0; i < numfiles; i++) { - if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) { - FileDirEntry *file = filelist_file(sfile->files, i); - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", file->relpath); - num_dirs++; - } - } - - /* make sure the directory specified in the button is added even if no - * directory selected */ - if (0 == num_dirs) { - RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", sfile->params->dir); - } - } - - - } + Main *bmain = CTX_data_main(C); + PropertyRNA *prop; + + /* XXX, not real length */ + BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); + + if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { + if (RNA_property_boolean_get(op->ptr, prop)) { + BLI_path_rel(filepath, BKE_main_blendfile_path(bmain)); + } + } + + if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { + RNA_property_string_set(op->ptr, prop, sfile->params->file); + } + if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { + RNA_property_string_set(op->ptr, prop, sfile->params->dir); + } + if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { + RNA_property_string_set(op->ptr, prop, filepath); + } + + /* some ops have multiple files to select */ + /* this is called on operators check() so clear collections first since + * they may be already set. */ + { + int i, numfiles = filelist_files_ensure(sfile->files); + + if ((prop = RNA_struct_find_property(op->ptr, "files"))) { + PointerRNA itemptr; + int num_files = 0; + RNA_property_collection_clear(op->ptr, prop); + for (i = 0; i < numfiles; i++) { + if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { + FileDirEntry *file = filelist_file(sfile->files, i); + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", file->relpath); + num_files++; + } + } + /* make sure the file specified in the filename button is added even if no + * files selected */ + if (0 == num_files) { + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", sfile->params->file); + } + } + + if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) { + PointerRNA itemptr; + int num_dirs = 0; + RNA_property_collection_clear(op->ptr, prop); + for (i = 0; i < numfiles; i++) { + if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) { + FileDirEntry *file = filelist_file(sfile->files, i); + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", file->relpath); + num_dirs++; + } + } + + /* make sure the directory specified in the button is added even if no + * directory selected */ + if (0 == num_dirs) { + RNA_property_collection_add(op->ptr, prop, &itemptr); + RNA_string_set(&itemptr, "name", sfile->params->dir); + } + } + } } void file_sfile_to_operator(bContext *C, wmOperator *op, SpaceFile *sfile) { - char filepath[FILE_MAX]; + char filepath[FILE_MAX]; - file_sfile_to_operator_ex(C, op, sfile, filepath); + file_sfile_to_operator_ex(C, op, sfile, filepath); } void file_operator_to_sfile(bContext *C, SpaceFile *sfile, wmOperator *op) { - Main *bmain = CTX_data_main(C); - PropertyRNA *prop; - - /* If neither of the above are set, split the filepath back */ - if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { - char filepath[FILE_MAX]; - RNA_property_string_get(op->ptr, prop, filepath); - BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); - } - else { - if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { - RNA_property_string_get(op->ptr, prop, sfile->params->file); - } - if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_get(op->ptr, prop, sfile->params->dir); - } - } - - /* we could check for relative_path property which is used when converting - * in the other direction but doesn't hurt to do this every time */ - BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain)); - - /* XXX, files and dirs updates missing, not really so important though */ + Main *bmain = CTX_data_main(C); + PropertyRNA *prop; + + /* If neither of the above are set, split the filepath back */ + if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { + char filepath[FILE_MAX]; + RNA_property_string_get(op->ptr, prop, filepath); + BLI_split_dirfile(filepath, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + } + else { + if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { + RNA_property_string_get(op->ptr, prop, sfile->params->file); + } + if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { + RNA_property_string_get(op->ptr, prop, sfile->params->dir); + } + } + + /* we could check for relative_path property which is used when converting + * in the other direction but doesn't hurt to do this every time */ + BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain)); + + /* XXX, files and dirs updates missing, not really so important though */ } /** @@ -1316,433 +1356,439 @@ void file_operator_to_sfile(bContext *C, SpaceFile *sfile, wmOperator *op) */ void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath) { - BLI_assert(BLI_exists(filepath)); - - if (BLI_is_dir(filepath)) { - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - } - else { - if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) { - BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file, - sizeof(sfile->params->dir), sizeof(sfile->params->file)); - } - else { - BLI_split_dir_part(filepath, sfile->params->dir, sizeof(sfile->params->dir)); - } - } + BLI_assert(BLI_exists(filepath)); + + if (BLI_is_dir(filepath)) { + BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); + } + else { + if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) { + BLI_split_dirfile(filepath, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + } + else { + BLI_split_dir_part(filepath, sfile->params->dir, sizeof(sfile->params->dir)); + } + } } void file_draw_check(bContext *C) { - SpaceFile *sfile = CTX_wm_space_file(C); - wmOperator *op = sfile->op; - if (op) { /* fail on reload */ - if (op->type->check) { - file_sfile_to_operator(C, op, sfile); + SpaceFile *sfile = CTX_wm_space_file(C); + wmOperator *op = sfile->op; + if (op) { /* fail on reload */ + if (op->type->check) { + file_sfile_to_operator(C, op, sfile); - /* redraw */ - if (op->type->check(C, op)) { - file_operator_to_sfile(C, sfile, op); + /* redraw */ + if (op->type->check(C, op)) { + file_operator_to_sfile(C, sfile, op); - /* redraw, else the changed settings wont get updated */ - ED_area_tag_redraw(CTX_wm_area(C)); - } - } - } + /* redraw, else the changed settings wont get updated */ + ED_area_tag_redraw(CTX_wm_area(C)); + } + } + } } /* for use with; UI_block_func_set */ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) { - file_draw_check(C); + file_draw_check(C); } bool file_draw_check_exists(SpaceFile *sfile) { - if (sfile->op) { /* fails on reload */ - PropertyRNA *prop; - if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) { - if (RNA_property_boolean_get(sfile->op->ptr, prop)) { - char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file); - if (BLI_is_file(filepath)) { - return true; - } - } - } - } + if (sfile->op) { /* fails on reload */ + PropertyRNA *prop; + if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) { + if (RNA_property_boolean_get(sfile->op->ptr, prop)) { + char filepath[FILE_MAX]; + BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file); + if (BLI_is_file(filepath)) { + return true; + } + } + } + } - return false; + return false; } int file_exec(bContext *C, wmOperator *exec_op) { - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); - char filepath[FILE_MAX]; - - /* directory change */ - if (file && (file->typeflag & FILE_TYPE_DIR)) { - if (!file->relpath) { - return OPERATOR_CANCELLED; - } - - if (FILENAME_IS_PARENT(file->relpath)) { - BLI_parent_dir(sfile->params->dir); - } - else { - BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir); - BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); - BLI_add_slash(sfile->params->dir); - } - - ED_file_change_dir(C); - } - /* opening file - sends events now, so things get handled on windowqueue level */ - else if (sfile->op) { - wmOperator *op = sfile->op; - - /* when used as a macro, for doubleclick, - * to prevent closing when doubleclicking on .. item */ - if (RNA_boolean_get(exec_op->ptr, "need_active")) { - const int numfiles = filelist_files_ensure(sfile->files); - int i, active = 0; - - for (i = 0; i < numfiles; i++) { - if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) { - active = 1; - break; - } - } - if (active == 0) - return OPERATOR_CANCELLED; - } - - sfile->op = NULL; - - file_sfile_to_operator_ex(C, op, sfile, filepath); - - if (BLI_exists(sfile->params->dir)) { - fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL, - FS_INSERT_SAVE | FS_INSERT_FIRST); - } - - BLI_make_file_string(BKE_main_blendfile_path(bmain), filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), - BLENDER_BOOKMARK_FILE); - fsmenu_write_file(ED_fsmenu_get(), filepath); - WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC); - - } - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); + char filepath[FILE_MAX]; + + /* directory change */ + if (file && (file->typeflag & FILE_TYPE_DIR)) { + if (!file->relpath) { + return OPERATOR_CANCELLED; + } + + if (FILENAME_IS_PARENT(file->relpath)) { + BLI_parent_dir(sfile->params->dir); + } + else { + BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir); + BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); + BLI_add_slash(sfile->params->dir); + } + + ED_file_change_dir(C); + } + /* opening file - sends events now, so things get handled on windowqueue level */ + else if (sfile->op) { + wmOperator *op = sfile->op; + + /* when used as a macro, for doubleclick, + * to prevent closing when doubleclicking on .. item */ + if (RNA_boolean_get(exec_op->ptr, "need_active")) { + const int numfiles = filelist_files_ensure(sfile->files); + int i, active = 0; + + for (i = 0; i < numfiles; i++) { + if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) { + active = 1; + break; + } + } + if (active == 0) + return OPERATOR_CANCELLED; + } + + sfile->op = NULL; + + file_sfile_to_operator_ex(C, op, sfile, filepath); + + if (BLI_exists(sfile->params->dir)) { + fsmenu_insert_entry(ED_fsmenu_get(), + FS_CATEGORY_RECENT, + sfile->params->dir, + NULL, + FS_INSERT_SAVE | FS_INSERT_FIRST); + } + + BLI_make_file_string(BKE_main_blendfile_path(bmain), + filepath, + BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLENDER_BOOKMARK_FILE); + fsmenu_write_file(ED_fsmenu_get(), filepath); + WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC); + } + + return OPERATOR_FINISHED; } void FILE_OT_execute(struct wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Execute File Window"; - ot->description = "Execute selected file"; - ot->idname = "FILE_OT_execute"; + /* identifiers */ + ot->name = "Execute File Window"; + ot->description = "Execute selected file"; + ot->idname = "FILE_OT_execute"; - /* api callbacks */ - ot->exec = file_exec; - ot->poll = file_operator_poll; + /* api callbacks */ + ot->exec = file_exec; + ot->poll = file_operator_poll; - /* properties */ - prop = RNA_def_boolean(ot->srna, "need_active", 0, "Need Active", - "Only execute if there's an active selected file in the file list"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + prop = RNA_def_boolean(ot->srna, + "need_active", + 0, + "Need Active", + "Only execute if there's an active selected file in the file list"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) { - Main *bmain = CTX_data_main(C); - SpaceFile *sfile = CTX_wm_space_file(C); - - if (sfile->params) { - if (BLI_parent_dir(sfile->params->dir)) { - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); - ED_file_change_dir(C); - if (sfile->params->recursion_level > 1) { - /* Disable 'dirtree' recursion when going up in tree. */ - sfile->params->recursion_level = 0; - filelist_setrecursion(sfile->files, sfile->params->recursion_level); - } - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } - } + Main *bmain = CTX_data_main(C); + SpaceFile *sfile = CTX_wm_space_file(C); - return OPERATOR_FINISHED; + if (sfile->params) { + if (BLI_parent_dir(sfile->params->dir)) { + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + ED_file_change_dir(C); + if (sfile->params->recursion_level > 1) { + /* Disable 'dirtree' recursion when going up in tree. */ + sfile->params->recursion_level = 0; + filelist_setrecursion(sfile->files, sfile->params->recursion_level); + } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + } + } + return OPERATOR_FINISHED; } - void FILE_OT_parent(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Parent File"; - ot->description = "Move to parent directory"; - ot->idname = "FILE_OT_parent"; + /* identifiers */ + ot->name = "Parent File"; + ot->description = "Move to parent directory"; + ot->idname = "FILE_OT_parent"; - /* api callbacks */ - ot->exec = file_parent_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_parent_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } - static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) { - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); - struct FSMenu *fsmenu = ED_fsmenu_get(); - - ED_fileselect_clear(wm, sa, sfile); + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ScrArea *sa = CTX_wm_area(C); + struct FSMenu *fsmenu = ED_fsmenu_get(); - /* refresh system directory menu */ - fsmenu_refresh_system_category(fsmenu); + ED_fileselect_clear(wm, sa, sfile); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + /* refresh system directory menu */ + fsmenu_refresh_system_category(fsmenu); - return OPERATOR_FINISHED; + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + return OPERATOR_FINISHED; } void FILE_OT_previous(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Previous Folder"; - ot->description = "Move to previous folder"; - ot->idname = "FILE_OT_previous"; + /* identifiers */ + ot->name = "Previous Folder"; + ot->description = "Move to previous folder"; + ot->idname = "FILE_OT_previous"; - /* api callbacks */ - ot->exec = file_previous_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_previous_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } int file_previous_exec(bContext *C, wmOperator *UNUSED(unused)) { - SpaceFile *sfile = CTX_wm_space_file(C); + SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile->params) { - if (!sfile->folders_next) - sfile->folders_next = folderlist_new(); + if (sfile->params) { + if (!sfile->folders_next) + sfile->folders_next = folderlist_new(); - folderlist_pushdir(sfile->folders_next, sfile->params->dir); - folderlist_popdir(sfile->folders_prev, sfile->params->dir); - folderlist_pushdir(sfile->folders_next, sfile->params->dir); + folderlist_pushdir(sfile->folders_next, sfile->params->dir); + folderlist_popdir(sfile->folders_prev, sfile->params->dir); + folderlist_pushdir(sfile->folders_next, sfile->params->dir); - ED_file_change_dir(C); - } - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + ED_file_change_dir(C); + } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FILE_OT_next(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Next Folder"; - ot->description = "Move to next folder"; - ot->idname = "FILE_OT_next"; + /* identifiers */ + ot->name = "Next Folder"; + ot->description = "Move to next folder"; + ot->idname = "FILE_OT_next"; - /* api callbacks */ - ot->exec = file_next_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_next_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) { - SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile->params) { - if (!sfile->folders_next) - sfile->folders_next = folderlist_new(); + SpaceFile *sfile = CTX_wm_space_file(C); + if (sfile->params) { + if (!sfile->folders_next) + sfile->folders_next = folderlist_new(); - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - folderlist_popdir(sfile->folders_next, sfile->params->dir); + folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + folderlist_popdir(sfile->folders_next, sfile->params->dir); - // update folders_prev so we can check for it in folderlist_clear_next() - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + // update folders_prev so we can check for it in folderlist_clear_next() + folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - ED_file_change_dir(C); - } - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + ED_file_change_dir(C); + } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - /* only meant for timer usage */ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = CTX_wm_space_file(C); - ARegion *ar, *oldar = CTX_wm_region(C); - int offset; - int numfiles, numfiles_layout; - int edit_idx = -1; - int i; - - /* escape if not our timer */ - if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata) - return OPERATOR_PASS_THROUGH; - - numfiles = filelist_files_ensure(sfile->files); - - /* Due to async nature of file listing, we may execute this code before `file_refresh()` - * editing entry is available in our listing, so we also have to handle switching to rename mode here. */ - FileSelectParams *params = ED_fileselect_get_params(sfile); - if ((params->rename_flag & (FILE_PARAMS_RENAME_PENDING | FILE_PARAMS_RENAME_POSTSCROLL_PENDING)) != 0) { - file_params_renamefile_activate(sfile, params); - } - - /* check if we are editing a name */ - for (i = 0; i < numfiles; ++i) { - if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) & (FILE_SEL_EDITING | FILE_SEL_HIGHLIGHTED)) { - edit_idx = i; - break; - } - } - - /* if we are not editing, we are done */ - if (edit_idx == -1) { - /* Do not invalidate timer if filerename is still pending, we might still be building the filelist - * and yet have to find edited entry... */ - if (params->rename_flag == 0) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); - sfile->smoothscroll_timer = NULL; - } - return OPERATOR_PASS_THROUGH; - } - - /* we need the correct area for scrolling */ - ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (!ar || ar->regiontype != RGN_TYPE_WINDOW) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); - sfile->smoothscroll_timer = NULL; - return OPERATOR_PASS_THROUGH; - } - - offset = max_ii(0, ED_fileselect_layout_offset(sfile->layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax)); - - /* scroll offset is the first file in the row/column we are editing in */ - if (sfile->scroll_offset == 0) { - if (sfile->layout->flag & FILE_LAYOUT_HOR) { - sfile->scroll_offset = (edit_idx / sfile->layout->rows) * sfile->layout->rows; - if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->rows; - } - else { - sfile->scroll_offset = (edit_idx / sfile->layout->columns) * sfile->layout->columns; - if (sfile->scroll_offset <= offset) sfile->scroll_offset -= sfile->layout->columns; - } - } - - numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, ar); - /* Using margins helps avoiding scrolling to stop when target item is barely visible on one side of the screen - * (i.e. it centers a bit more the target). */ - int numfiles_layout_margin = max_ii(0, numfiles_layout / 3); - - /* check if we have reached our final scroll position */ - if ((sfile->scroll_offset >= offset + numfiles_layout_margin) && - (sfile->scroll_offset < offset + numfiles_layout - numfiles_layout_margin)) - { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); - sfile->smoothscroll_timer = NULL; - /* Postscroll (after rename has been validated by user) is done, rename process is totally finisehd, cleanup. */ - if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE) != 0) { - params->renamefile[0] = '\0'; - params->rename_flag = 0; - } - return OPERATOR_FINISHED; - } - - /* temporarily set context to the main window region, - * so the scroll operators work */ - CTX_wm_region_set(C, ar); - - /* scroll one step in the desired direction */ - if (sfile->scroll_offset < offset) { - if (sfile->layout->flag & FILE_LAYOUT_HOR) { - WM_operator_name_call(C, "VIEW2D_OT_scroll_left", 0, NULL); - } - else { - WM_operator_name_call(C, "VIEW2D_OT_scroll_up", 0, NULL); - } - - } - else { - if (sfile->layout->flag & FILE_LAYOUT_HOR) { - WM_operator_name_call(C, "VIEW2D_OT_scroll_right", 0, NULL); - } - else { - WM_operator_name_call(C, "VIEW2D_OT_scroll_down", 0, NULL); - } - } - - ED_region_tag_redraw(ar); - - /* and restore context */ - CTX_wm_region_set(C, oldar); - - return OPERATOR_FINISHED; + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ARegion *ar, *oldar = CTX_wm_region(C); + int offset; + int numfiles, numfiles_layout; + int edit_idx = -1; + int i; + + /* escape if not our timer */ + if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata) + return OPERATOR_PASS_THROUGH; + + numfiles = filelist_files_ensure(sfile->files); + + /* Due to async nature of file listing, we may execute this code before `file_refresh()` + * editing entry is available in our listing, so we also have to handle switching to rename mode here. */ + FileSelectParams *params = ED_fileselect_get_params(sfile); + if ((params->rename_flag & + (FILE_PARAMS_RENAME_PENDING | FILE_PARAMS_RENAME_POSTSCROLL_PENDING)) != 0) { + file_params_renamefile_activate(sfile, params); + } + + /* check if we are editing a name */ + for (i = 0; i < numfiles; ++i) { + if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) & + (FILE_SEL_EDITING | FILE_SEL_HIGHLIGHTED)) { + edit_idx = i; + break; + } + } + + /* if we are not editing, we are done */ + if (edit_idx == -1) { + /* Do not invalidate timer if filerename is still pending, we might still be building the filelist + * and yet have to find edited entry... */ + if (params->rename_flag == 0) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); + sfile->smoothscroll_timer = NULL; + } + return OPERATOR_PASS_THROUGH; + } + + /* we need the correct area for scrolling */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (!ar || ar->regiontype != RGN_TYPE_WINDOW) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); + sfile->smoothscroll_timer = NULL; + return OPERATOR_PASS_THROUGH; + } + + offset = max_ii( + 0, + ED_fileselect_layout_offset(sfile->layout, (int)ar->v2d.cur.xmin, (int)-ar->v2d.cur.ymax)); + + /* scroll offset is the first file in the row/column we are editing in */ + if (sfile->scroll_offset == 0) { + if (sfile->layout->flag & FILE_LAYOUT_HOR) { + sfile->scroll_offset = (edit_idx / sfile->layout->rows) * sfile->layout->rows; + if (sfile->scroll_offset <= offset) + sfile->scroll_offset -= sfile->layout->rows; + } + else { + sfile->scroll_offset = (edit_idx / sfile->layout->columns) * sfile->layout->columns; + if (sfile->scroll_offset <= offset) + sfile->scroll_offset -= sfile->layout->columns; + } + } + + numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, ar); + /* Using margins helps avoiding scrolling to stop when target item is barely visible on one side of the screen + * (i.e. it centers a bit more the target). */ + int numfiles_layout_margin = max_ii(0, numfiles_layout / 3); + + /* check if we have reached our final scroll position */ + if ((sfile->scroll_offset >= offset + numfiles_layout_margin) && + (sfile->scroll_offset < offset + numfiles_layout - numfiles_layout_margin)) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); + sfile->smoothscroll_timer = NULL; + /* Postscroll (after rename has been validated by user) is done, rename process is totally finisehd, cleanup. */ + if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE) != 0) { + params->renamefile[0] = '\0'; + params->rename_flag = 0; + } + return OPERATOR_FINISHED; + } + + /* temporarily set context to the main window region, + * so the scroll operators work */ + CTX_wm_region_set(C, ar); + + /* scroll one step in the desired direction */ + if (sfile->scroll_offset < offset) { + if (sfile->layout->flag & FILE_LAYOUT_HOR) { + WM_operator_name_call(C, "VIEW2D_OT_scroll_left", 0, NULL); + } + else { + WM_operator_name_call(C, "VIEW2D_OT_scroll_up", 0, NULL); + } + } + else { + if (sfile->layout->flag & FILE_LAYOUT_HOR) { + WM_operator_name_call(C, "VIEW2D_OT_scroll_right", 0, NULL); + } + else { + WM_operator_name_call(C, "VIEW2D_OT_scroll_down", 0, NULL); + } + } + + ED_region_tag_redraw(ar); + + /* and restore context */ + CTX_wm_region_set(C, oldar); + + return OPERATOR_FINISHED; } - void FILE_OT_smoothscroll(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Smooth Scroll"; - ot->idname = "FILE_OT_smoothscroll"; - ot->description = "Smooth scroll to make editable file visible"; + /* identifiers */ + ot->name = "Smooth Scroll"; + ot->idname = "FILE_OT_smoothscroll"; + ot->description = "Smooth scroll to make editable file visible"; - /* api callbacks */ - ot->invoke = file_smoothscroll_invoke; + /* api callbacks */ + ot->invoke = file_smoothscroll_invoke; - ot->poll = ED_operator_file_active; + ot->poll = ED_operator_file_active; } - static int filepath_drop_exec(bContext *C, wmOperator *op) { - SpaceFile *sfile = CTX_wm_space_file(C); + SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile) { - char filepath[FILE_MAX]; + if (sfile) { + char filepath[FILE_MAX]; - RNA_string_get(op->ptr, "filepath", filepath); - if (!BLI_exists(filepath)) { - BKE_report(op->reports, RPT_ERROR, "File does not exist"); - return OPERATOR_CANCELLED; - } + RNA_string_get(op->ptr, "filepath", filepath); + if (!BLI_exists(filepath)) { + BKE_report(op->reports, RPT_ERROR, "File does not exist"); + return OPERATOR_CANCELLED; + } - file_sfile_filepath_set(sfile, filepath); + file_sfile_filepath_set(sfile, filepath); - if (sfile->op) { - file_sfile_to_operator(C, sfile->op, sfile); - file_draw_check(C); - } + if (sfile->op) { + file_sfile_to_operator(C, sfile->op, sfile); + file_draw_check(C); + } - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - return OPERATOR_FINISHED; - } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + return OPERATOR_FINISHED; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } void FILE_OT_filepath_drop(wmOperatorType *ot) { - ot->name = "File Selector Drop"; - ot->idname = "FILE_OT_filepath_drop"; + ot->name = "File Selector Drop"; + ot->idname = "FILE_OT_filepath_drop"; - ot->exec = filepath_drop_exec; - ot->poll = WM_operator_winactive; + ot->exec = filepath_drop_exec; + ot->poll = WM_operator_winactive; - RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", ""); + RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", ""); } /* create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created. @@ -1750,616 +1796,615 @@ void FILE_OT_filepath_drop(wmOperatorType *ot) */ static int new_folder_path(const char *parent, char *folder, char *name) { - int i = 1; - int len = 0; + int i = 1; + int len = 0; - BLI_strncpy(name, "New Folder", FILE_MAXFILE); - BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */ - /* check whether folder with the name already exists, in this case - * add number to the name. Check length of generated name to avoid - * crazy case of huge number of folders each named 'New Folder (x)' */ - while (BLI_exists(folder) && (len < FILE_MAXFILE)) { - len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i); - BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */ - i++; - } + BLI_strncpy(name, "New Folder", FILE_MAXFILE); + BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */ + /* check whether folder with the name already exists, in this case + * add number to the name. Check length of generated name to avoid + * crazy case of huge number of folders each named 'New Folder (x)' */ + while (BLI_exists(folder) && (len < FILE_MAXFILE)) { + len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i); + BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */ + i++; + } - return (len < FILE_MAXFILE); + return (len < FILE_MAXFILE); } int file_directory_new_exec(bContext *C, wmOperator *op) { - char name[FILE_MAXFILE]; - char path[FILE_MAX]; - bool generate_name = true; - PropertyRNA *prop; - - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); - - if (!sfile->params) { - BKE_report(op->reports, RPT_WARNING, "No parent directory given"); - return OPERATOR_CANCELLED; - } - - path[0] = '\0'; - - if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_get(op->ptr, prop, path); - if (path[0] != '\0') { - generate_name = false; - } - } - - if (generate_name) { - /* create a new, non-existing folder name */ - if (!new_folder_path(sfile->params->dir, path, name)) { - BKE_report(op->reports, RPT_ERROR, "Could not create new folder name"); - return OPERATOR_CANCELLED; - } - } - else { /* We assume we are able to generate a valid name! */ - char org_path[FILE_MAX]; - - BLI_strncpy(org_path, path, sizeof(org_path)); - if (BLI_path_make_safe(path)) { - BKE_reportf(op->reports, RPT_WARNING, "'%s' given path is OS-invalid, creating '%s' path instead", - org_path, path); - } - } - - /* create the file */ - errno = 0; - if (!BLI_dir_create_recursive(path) || - /* Should no more be needed, - * now that BLI_dir_create_recursive returns a success state - but kept just in case. */ - !BLI_exists(path)) - { - BKE_reportf(op->reports, RPT_ERROR, - "Could not create new folder: %s", - errno ? strerror(errno) : "unknown error"); - return OPERATOR_CANCELLED; - } - - - /* now remember file to jump into editing */ - BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE); - sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING; - - /* set timer to smoothly view newly generated file */ - /* max 30 frs/sec */ - if (sfile->smoothscroll_timer != NULL) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); - } - sfile->smoothscroll_timer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER1, 1.0 / 1000.0); - sfile->scroll_offset = 0; - - /* reload dir to make sure we're seeing what's in the directory */ - ED_fileselect_clear(wm, sa, sfile); - - if (RNA_boolean_get(op->ptr, "open")) { - BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); - ED_file_change_dir(C); - } - - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - - return OPERATOR_FINISHED; + char name[FILE_MAXFILE]; + char path[FILE_MAX]; + bool generate_name = true; + PropertyRNA *prop; + + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ScrArea *sa = CTX_wm_area(C); + + if (!sfile->params) { + BKE_report(op->reports, RPT_WARNING, "No parent directory given"); + return OPERATOR_CANCELLED; + } + + path[0] = '\0'; + + if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { + RNA_property_string_get(op->ptr, prop, path); + if (path[0] != '\0') { + generate_name = false; + } + } + + if (generate_name) { + /* create a new, non-existing folder name */ + if (!new_folder_path(sfile->params->dir, path, name)) { + BKE_report(op->reports, RPT_ERROR, "Could not create new folder name"); + return OPERATOR_CANCELLED; + } + } + else { /* We assume we are able to generate a valid name! */ + char org_path[FILE_MAX]; + + BLI_strncpy(org_path, path, sizeof(org_path)); + if (BLI_path_make_safe(path)) { + BKE_reportf(op->reports, + RPT_WARNING, + "'%s' given path is OS-invalid, creating '%s' path instead", + org_path, + path); + } + } + + /* create the file */ + errno = 0; + if (!BLI_dir_create_recursive(path) || + /* Should no more be needed, + * now that BLI_dir_create_recursive returns a success state - but kept just in case. */ + !BLI_exists(path)) { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not create new folder: %s", + errno ? strerror(errno) : "unknown error"); + return OPERATOR_CANCELLED; + } + + /* now remember file to jump into editing */ + BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE); + sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING; + + /* set timer to smoothly view newly generated file */ + /* max 30 frs/sec */ + if (sfile->smoothscroll_timer != NULL) { + WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); + } + sfile->smoothscroll_timer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER1, 1.0 / 1000.0); + sfile->scroll_offset = 0; + + /* reload dir to make sure we're seeing what's in the directory */ + ED_fileselect_clear(wm, sa, sfile); + + if (RNA_boolean_get(op->ptr, "open")) { + BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); + ED_file_change_dir(C); + } + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + + return OPERATOR_FINISHED; } - void FILE_OT_directory_new(struct wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Create New Directory"; - ot->description = "Create a new directory"; - ot->idname = "FILE_OT_directory_new"; + /* identifiers */ + ot->name = "Create New Directory"; + ot->description = "Create a new directory"; + ot->idname = "FILE_OT_directory_new"; - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = file_directory_new_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = file_directory_new_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ - prop = RNA_def_string_dir_path(ot->srna, "directory", NULL, FILE_MAX, "Directory", "Name of new directory"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_string_dir_path( + ot->srna, "directory", NULL, FILE_MAX, "Directory", "Name of new directory"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - /* TODO This should go to BLI_path_utils. */ static void file_expand_directory(bContext *C) { - Main *bmain = CTX_data_main(C); - SpaceFile *sfile = CTX_wm_space_file(C); - - if (sfile->params) { - if (BLI_path_is_rel(sfile->params->dir)) { - /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */ - BLI_path_abs(sfile->params->dir, G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default()); - } - else if (sfile->params->dir[0] == '~') { - char tmpstr[sizeof(sfile->params->dir) - 1]; - BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr)); - BLI_join_dirfile(sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr); - } - - else if (sfile->params->dir[0] == '\0') + Main *bmain = CTX_data_main(C); + SpaceFile *sfile = CTX_wm_space_file(C); + + if (sfile->params) { + if (BLI_path_is_rel(sfile->params->dir)) { + /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */ + BLI_path_abs(sfile->params->dir, + G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default()); + } + else if (sfile->params->dir[0] == '~') { + char tmpstr[sizeof(sfile->params->dir) - 1]; + BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr)); + BLI_join_dirfile( + sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr); + } + + else if (sfile->params->dir[0] == '\0') #ifndef WIN32 - { - sfile->params->dir[0] = '/'; - sfile->params->dir[1] = '\0'; - } + { + sfile->params->dir[0] = '/'; + sfile->params->dir[1] = '\0'; + } #else - { - get_default_root(sfile->params->dir); - } - /* change "C:" --> "C:\", [#28102] */ - else if ((isalpha(sfile->params->dir[0]) && - (sfile->params->dir[1] == ':')) && - (sfile->params->dir[2] == '\0')) - { - sfile->params->dir[2] = '\\'; - sfile->params->dir[3] = '\0'; - } - else if (BLI_path_is_unc(sfile->params->dir)) { - BLI_cleanup_unc(sfile->params->dir, FILE_MAX_LIBEXTRA); - } + { + get_default_root(sfile->params->dir); + } + /* change "C:" --> "C:\", [#28102] */ + else if ((isalpha(sfile->params->dir[0]) && (sfile->params->dir[1] == ':')) && + (sfile->params->dir[2] == '\0')) { + sfile->params->dir[2] = '\\'; + sfile->params->dir[3] = '\0'; + } + else if (BLI_path_is_unc(sfile->params->dir)) { + BLI_cleanup_unc(sfile->params->dir, FILE_MAX_LIBEXTRA); + } #endif - } + } } /* TODO check we still need this, it's annoying to have OS-specific code here... :/ */ #if defined(WIN32) static bool can_create_dir(const char *dir) { - /* for UNC paths we need to check whether the parent of the new - * directory is a proper directory itself and not a share or the - * UNC root (server name) itself. Calling BLI_is_dir does this - */ - if (BLI_path_is_unc(dir)) { - char parent[PATH_MAX]; - BLI_strncpy(parent, dir, PATH_MAX); - BLI_parent_dir(parent); - return BLI_is_dir(parent); - } - return true; + /* for UNC paths we need to check whether the parent of the new + * directory is a proper directory itself and not a share or the + * UNC root (server name) itself. Calling BLI_is_dir does this + */ + if (BLI_path_is_unc(dir)) { + char parent[PATH_MAX]; + BLI_strncpy(parent, dir, PATH_MAX); + BLI_parent_dir(parent); + return BLI_is_dir(parent); + } + return true; } #endif void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UNUSED(arg_but)) { - Main *bmain = CTX_data_main(C); - SpaceFile *sfile = CTX_wm_space_file(C); - - if (sfile->params) { - file_expand_directory(C); - - /* special case, user may have pasted a filepath into the directory */ - if (!filelist_is_dir(sfile->files, sfile->params->dir)) { - char tdir[FILE_MAX_LIBEXTRA]; - char *group, *name; - - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, - sizeof(sfile->params->dir), sizeof(sfile->params->file)); - } - else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { - if (group) { - BLI_path_append(tdir, sizeof(tdir), group); - } - BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); - if (name) { - BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); - } - else { - sfile->params->file[0] = '\0'; - } - } - } - - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); - - if (filelist_is_dir(sfile->files, sfile->params->dir)) { - /* if directory exists, enter it immediately */ - ED_file_change_dir(C); - - /* don't do for now because it selects entire text instead of - * placing cursor at the end */ - /* UI_textbutton_activate_but(C, but); */ - } + Main *bmain = CTX_data_main(C); + SpaceFile *sfile = CTX_wm_space_file(C); + + if (sfile->params) { + file_expand_directory(C); + + /* special case, user may have pasted a filepath into the directory */ + if (!filelist_is_dir(sfile->files, sfile->params->dir)) { + char tdir[FILE_MAX_LIBEXTRA]; + char *group, *name; + + if (BLI_is_file(sfile->params->dir)) { + char path[sizeof(sfile->params->dir)]; + BLI_strncpy(path, sfile->params->dir, sizeof(path)); + BLI_split_dirfile(path, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + } + else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + if (group) { + BLI_path_append(tdir, sizeof(tdir), group); + } + BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + if (name) { + BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + } + else { + sfile->params->file[0] = '\0'; + } + } + } + + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + + if (filelist_is_dir(sfile->files, sfile->params->dir)) { + /* if directory exists, enter it immediately */ + ED_file_change_dir(C); + + /* don't do for now because it selects entire text instead of + * placing cursor at the end */ + /* UI_textbutton_activate_but(C, but); */ + } #if defined(WIN32) - else if (!can_create_dir(sfile->params->dir)) { - const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); - if (lastdir) - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - } + else if (!can_create_dir(sfile->params->dir)) { + const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); + if (lastdir) + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + } #endif - else { - const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); - char tdir[FILE_MAX_LIBEXTRA]; - - /* If we are 'inside' a blend library, we cannot do anything... */ - if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - } - else { - /* if not, ask to create it and enter if confirmed */ - wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); - RNA_boolean_set(&ptr, "open", true); - - if (lastdir) - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); - } - } - - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } + else { + const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); + char tdir[FILE_MAX_LIBEXTRA]; + + /* If we are 'inside' a blend library, we cannot do anything... */ + if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + } + else { + /* if not, ask to create it and enter if confirmed */ + wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_boolean_set(&ptr, "open", true); + + if (lastdir) + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + } + } + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + } } void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg_but) { - Main *bmain = CTX_data_main(C); - SpaceFile *sfile = CTX_wm_space_file(C); - uiBut *but = arg_but; - char matched_file[FILE_MAX]; - char filepath[sizeof(sfile->params->dir)]; + Main *bmain = CTX_data_main(C); + SpaceFile *sfile = CTX_wm_space_file(C); + uiBut *but = arg_but; + char matched_file[FILE_MAX]; + char filepath[sizeof(sfile->params->dir)]; - if (sfile->params) { - int matches; - matched_file[0] = '\0'; - filepath[0] = '\0'; + if (sfile->params) { + int matches; + matched_file[0] = '\0'; + filepath[0] = '\0'; - file_expand_directory(C); + file_expand_directory(C); - matches = file_select_match(sfile, sfile->params->file, matched_file); + matches = file_select_match(sfile, sfile->params->file, matched_file); - /* *After* file_select_match! */ - BLI_filename_make_safe(sfile->params->file); + /* *After* file_select_match! */ + BLI_filename_make_safe(sfile->params->file); - if (matches) { - /* replace the pattern (or filename that the user typed in, - * with the first selected file of the match */ - BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); + if (matches) { + /* replace the pattern (or filename that the user typed in, + * with the first selected file of the match */ + BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + } - if (matches == 1) { - BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); + if (matches == 1) { + BLI_join_dirfile( + filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); - /* if directory, open it and empty filename field */ - if (filelist_is_dir(sfile->files, filepath)) { - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; - ED_file_change_dir(C); - UI_textbutton_activate_but(C, but); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); - } - } - else if (matches > 1) { - file_draw_check(C); - } - } + /* if directory, open it and empty filename field */ + if (filelist_is_dir(sfile->files, filepath)) { + BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath); + BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); + sfile->params->file[0] = '\0'; + ED_file_change_dir(C); + UI_textbutton_activate_but(C, but); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + } + } + else if (matches > 1) { + file_draw_check(C); + } + } } void FILE_OT_refresh(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Refresh Filelist"; - ot->description = "Refresh the file list"; - ot->idname = "FILE_OT_refresh"; + /* identifiers */ + ot->name = "Refresh Filelist"; + ot->description = "Refresh the file list"; + ot->idname = "FILE_OT_refresh"; - /* api callbacks */ - ot->exec = file_refresh_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_refresh_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused)) { - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ScrArea *sa = CTX_wm_area(C); - if (sfile->params) { - sfile->params->flag ^= FILE_HIDE_DOT; - ED_fileselect_clear(wm, sa, sfile); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } + if (sfile->params) { + sfile->params->flag ^= FILE_HIDE_DOT; + ED_fileselect_clear(wm, sa, sfile); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - void FILE_OT_hidedot(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Toggle Hide Dot Files"; - ot->description = "Toggle hide hidden dot files"; - ot->idname = "FILE_OT_hidedot"; + /* identifiers */ + ot->name = "Toggle Hide Dot Files"; + ot->description = "Toggle hide hidden dot files"; + ot->idname = "FILE_OT_hidedot"; - /* api callbacks */ - ot->exec = file_hidedot_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_hidedot_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } ARegion *file_tools_region(ScrArea *sa) { - ARegion *ar, *arnew; + ARegion *ar, *arnew; - if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) - return ar; + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) + return ar; - /* add subdiv level; after header */ - ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + /* add subdiv level; after header */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - /* is error! */ - if (ar == NULL) - return NULL; + /* is error! */ + if (ar == NULL) + return NULL; - arnew = MEM_callocN(sizeof(ARegion), "tools for file"); - BLI_insertlinkafter(&sa->regionbase, ar, arnew); - arnew->regiontype = RGN_TYPE_TOOLS; - arnew->alignment = RGN_ALIGN_LEFT; + arnew = MEM_callocN(sizeof(ARegion), "tools for file"); + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype = RGN_TYPE_TOOLS; + arnew->alignment = RGN_ALIGN_LEFT; - ar = MEM_callocN(sizeof(ARegion), "tool props for file"); - BLI_insertlinkafter(&sa->regionbase, arnew, ar); - ar->regiontype = RGN_TYPE_TOOL_PROPS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + ar = MEM_callocN(sizeof(ARegion), "tool props for file"); + BLI_insertlinkafter(&sa->regionbase, arnew, ar); + ar->regiontype = RGN_TYPE_TOOL_PROPS; + ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - return arnew; + return arnew; } static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused)) { - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = file_tools_region(sa); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = file_tools_region(sa); - if (ar) - ED_region_toggle_hidden(C, ar); + if (ar) + ED_region_toggle_hidden(C, ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void FILE_OT_bookmark_toggle(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Toggle Bookmarks"; - ot->description = "Toggle bookmarks display"; - ot->idname = "FILE_OT_bookmark_toggle"; + /* identifiers */ + ot->name = "Toggle Bookmarks"; + ot->description = "Toggle bookmarks display"; + ot->idname = "FILE_OT_bookmark_toggle"; - /* api callbacks */ - ot->exec = file_bookmark_toggle_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_bookmark_toggle_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } - /** * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add. */ static void filenum_newname(char *name, size_t name_size, int add) { - char head[FILE_MAXFILE], tail[FILE_MAXFILE]; - char name_temp[FILE_MAXFILE]; - int pic; - unsigned short digits; + char head[FILE_MAXFILE], tail[FILE_MAXFILE]; + char name_temp[FILE_MAXFILE]; + int pic; + unsigned short digits; - pic = BLI_stringdec(name, head, tail, &digits); + pic = BLI_stringdec(name, head, tail, &digits); - /* are we going from 100 -> 99 or from 10 -> 9 */ - if (add < 0 && digits > 0) { - int i, exp; - exp = 1; - for (i = digits; i > 1; i--) { - exp *= 10; - } - if (pic >= exp && (pic + add) < exp) { - digits--; - } - } + /* are we going from 100 -> 99 or from 10 -> 9 */ + if (add < 0 && digits > 0) { + int i, exp; + exp = 1; + for (i = digits; i > 1; i--) { + exp *= 10; + } + if (pic >= exp && (pic + add) < exp) { + digits--; + } + } - pic += add; - if (pic < 0) - pic = 0; - BLI_stringenc(name_temp, head, tail, digits, pic); - BLI_strncpy(name, name_temp, name_size); + pic += add; + if (pic < 0) + pic = 0; + BLI_stringenc(name_temp, head, tail, digits, pic); + BLI_strncpy(name, name_temp, name_size); } static int file_filenum_exec(bContext *C, wmOperator *op) { - SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ScrArea *sa = CTX_wm_area(C); - int inc = RNA_int_get(op->ptr, "increment"); - if (sfile->params && (inc != 0)) { - filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc); - ED_area_tag_redraw(sa); - file_draw_check(C); - // WM_event_add_notifier(C, NC_WINDOW, NULL); - } - - return OPERATOR_FINISHED; + int inc = RNA_int_get(op->ptr, "increment"); + if (sfile->params && (inc != 0)) { + filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc); + ED_area_tag_redraw(sa); + file_draw_check(C); + // WM_event_add_notifier(C, NC_WINDOW, NULL); + } + return OPERATOR_FINISHED; } void FILE_OT_filenum(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Increment Number in Filename"; - ot->description = "Increment number in filename"; - ot->idname = "FILE_OT_filenum"; + /* identifiers */ + ot->name = "Increment Number in Filename"; + ot->description = "Increment number in filename"; + ot->idname = "FILE_OT_filenum"; - /* api callbacks */ - ot->exec = file_filenum_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + /* api callbacks */ + ot->exec = file_filenum_exec; + ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ - /* props */ - RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100); + /* props */ + RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100); } static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) { - ScrArea *sa = CTX_wm_area(C); - SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - - if (sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); - if ((0 <= idx) && (idx < numfiles)) { - FileDirEntry *file = filelist_file(sfile->files, idx); - filelist_entry_select_index_set(sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); - BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE); - /* We can skip the pending state, as we can directly set FILE_SEL_EDITING on the expected entry here. */ - sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; - } - ED_area_tag_redraw(sa); - } + ScrArea *sa = CTX_wm_area(C); + SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - return OPERATOR_FINISHED; + if (sfile->params) { + int idx = sfile->params->highlight_file; + int numfiles = filelist_files_ensure(sfile->files); + if ((0 <= idx) && (idx < numfiles)) { + FileDirEntry *file = filelist_file(sfile->files, idx); + filelist_entry_select_index_set( + sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); + BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE); + /* We can skip the pending state, as we can directly set FILE_SEL_EDITING on the expected entry here. */ + sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; + } + ED_area_tag_redraw(sa); + } + return OPERATOR_FINISHED; } static bool file_rename_poll(bContext *C) { - bool poll = ED_operator_file_active(C); - SpaceFile *sfile = CTX_wm_space_file(C); - - if (sfile && sfile->params) { - int idx = sfile->params->highlight_file; - int numfiles = filelist_files_ensure(sfile->files); - - if ((0 <= idx) && (idx < numfiles)) { - FileDirEntry *file = filelist_file(sfile->files, idx); - if (FILENAME_IS_CURRPAR(file->relpath)) { - poll = false; - } - } - - if (sfile->params->highlight_file < 0) { - poll = false; - } - else { - char dir[FILE_MAX_LIBEXTRA]; - if (filelist_islibrary(sfile->files, dir, NULL)) { - poll = false; - } - } - } - else { - poll = false; - } - - return poll; + bool poll = ED_operator_file_active(C); + SpaceFile *sfile = CTX_wm_space_file(C); + + if (sfile && sfile->params) { + int idx = sfile->params->highlight_file; + int numfiles = filelist_files_ensure(sfile->files); + + if ((0 <= idx) && (idx < numfiles)) { + FileDirEntry *file = filelist_file(sfile->files, idx); + if (FILENAME_IS_CURRPAR(file->relpath)) { + poll = false; + } + } + + if (sfile->params->highlight_file < 0) { + poll = false; + } + else { + char dir[FILE_MAX_LIBEXTRA]; + if (filelist_islibrary(sfile->files, dir, NULL)) { + poll = false; + } + } + } + else { + poll = false; + } + + return poll; } void FILE_OT_rename(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rename File or Directory"; - ot->description = "Rename file or file directory"; - ot->idname = "FILE_OT_rename"; - - /* api callbacks */ - ot->exec = file_rename_exec; - ot->poll = file_rename_poll; + /* identifiers */ + ot->name = "Rename File or Directory"; + ot->description = "Rename file or file directory"; + ot->idname = "FILE_OT_rename"; + /* api callbacks */ + ot->exec = file_rename_exec; + ot->poll = file_rename_poll; } static bool file_delete_poll(bContext *C) { - bool poll = ED_operator_file_active(C); - SpaceFile *sfile = CTX_wm_space_file(C); + bool poll = ED_operator_file_active(C); + SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile && sfile->params) { - char dir[FILE_MAX_LIBEXTRA]; - int numfiles = filelist_files_ensure(sfile->files); - int i; - int num_selected = 0; + if (sfile && sfile->params) { + char dir[FILE_MAX_LIBEXTRA]; + int numfiles = filelist_files_ensure(sfile->files); + int i; + int num_selected = 0; - if (filelist_islibrary(sfile->files, dir, NULL)) poll = 0; - for (i = 0; i < numfiles; i++) { - if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { - num_selected++; - } - } - if (num_selected <= 0) { - poll = 0; - } - } - else - poll = 0; + if (filelist_islibrary(sfile->files, dir, NULL)) + poll = 0; + for (i = 0; i < numfiles; i++) { + if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { + num_selected++; + } + } + if (num_selected <= 0) { + poll = 0; + } + } + else + poll = 0; - return poll; + return poll; } int file_delete_exec(bContext *C, wmOperator *op) { - char str[FILE_MAX]; - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); - FileDirEntry *file; - int numfiles = filelist_files_ensure(sfile->files); - int i; - - bool report_error = false; - errno = 0; - for (i = 0; i < numfiles; i++) { - if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { - file = filelist_file(sfile->files, i); - BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath); - if (BLI_delete(str, false, false) != 0 || - BLI_exists(str)) - { - report_error = true; - } - } - } - - if (report_error) { - BKE_reportf(op->reports, RPT_ERROR, - "Could not delete file: %s", - errno ? strerror(errno) : "unknown error"); - } - - ED_fileselect_clear(wm, sa, sfile); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - - return OPERATOR_FINISHED; - + char str[FILE_MAX]; + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ScrArea *sa = CTX_wm_area(C); + FileDirEntry *file; + int numfiles = filelist_files_ensure(sfile->files); + int i; + + bool report_error = false; + errno = 0; + for (i = 0; i < numfiles; i++) { + if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) { + file = filelist_file(sfile->files, i); + BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath); + if (BLI_delete(str, false, false) != 0 || BLI_exists(str)) { + report_error = true; + } + } + } + + if (report_error) { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not delete file: %s", + errno ? strerror(errno) : "unknown error"); + } + + ED_fileselect_clear(wm, sa, sfile); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + + return OPERATOR_FINISHED; } void FILE_OT_delete(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Selected Files"; - ot->description = "Delete selected files"; - ot->idname = "FILE_OT_delete"; + /* identifiers */ + ot->name = "Delete Selected Files"; + ot->description = "Delete selected files"; + ot->idname = "FILE_OT_delete"; - /* api callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = file_delete_exec; - ot->poll = file_delete_poll; /* <- important, handler is on window level */ + /* api callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = file_delete_exec; + ot->poll = file_delete_poll; /* <- important, handler is on window level */ } - void ED_operatormacros_file(void) { -// wmOperatorType *ot; -// wmOperatorTypeMacro *otmacro; + // wmOperatorType *ot; + // wmOperatorTypeMacro *otmacro; - /* future macros */ + /* future macros */ } diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 058ba9bfef3..023dff704c7 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -53,59 +53,58 @@ static bool file_panel_operator_poll(const bContext *C, PanelType *UNUSED(pt)) { - SpaceFile *sfile = CTX_wm_space_file(C); - return (sfile && sfile->op); + SpaceFile *sfile = CTX_wm_space_file(C); + return (sfile && sfile->op); } static void file_panel_operator_header(const bContext *C, Panel *pa) { - SpaceFile *sfile = CTX_wm_space_file(C); - wmOperator *op = sfile->op; + SpaceFile *sfile = CTX_wm_space_file(C); + wmOperator *op = sfile->op; - BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname)); + BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname)); } static void file_panel_operator(const bContext *C, Panel *pa) { - SpaceFile *sfile = CTX_wm_space_file(C); - wmOperator *op = sfile->op; - - UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL); - - /* Hack: temporary hide.*/ - const char *hide[] = {"filepath", "files", "directory", "filename"}; - for (int i = 0; i < ARRAY_SIZE(hide); i++) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); - if (prop) { - RNA_def_property_flag(prop, PROP_HIDDEN); - } - } - - uiTemplateOperatorPropertyButs( - C, pa->layout, op, UI_BUT_LABEL_ALIGN_NONE, - UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); - - /* Hack: temporary hide.*/ - for (int i = 0; i < ARRAY_SIZE(hide); i++) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); - if (prop) { - RNA_def_property_clear_flag(prop, PROP_HIDDEN); - } - } - - UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL); + SpaceFile *sfile = CTX_wm_space_file(C); + wmOperator *op = sfile->op; + + UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL); + + /* Hack: temporary hide.*/ + const char *hide[] = {"filepath", "files", "directory", "filename"}; + for (int i = 0; i < ARRAY_SIZE(hide); i++) { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); + if (prop) { + RNA_def_property_flag(prop, PROP_HIDDEN); + } + } + + uiTemplateOperatorPropertyButs( + C, pa->layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); + + /* Hack: temporary hide.*/ + for (int i = 0; i < ARRAY_SIZE(hide); i++) { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); + if (prop) { + RNA_def_property_clear_flag(prop, PROP_HIDDEN); + } + } + + UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL); } void file_panels_register(ARegionType *art) { - PanelType *pt; - - pt = MEM_callocN(sizeof(PanelType), "spacetype file operator properties"); - strcpy(pt->idname, "FILE_PT_operator"); - strcpy(pt->label, N_("Operator")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->poll = file_panel_operator_poll; - pt->draw_header = file_panel_operator_header; - pt->draw = file_panel_operator; - BLI_addtail(&art->paneltypes, pt); + PanelType *pt; + + pt = MEM_callocN(sizeof(PanelType), "spacetype file operator properties"); + strcpy(pt->idname, "FILE_PT_operator"); + strcpy(pt->label, N_("Operator")); + strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->poll = file_panel_operator_poll; + pt->draw_header = file_panel_operator_header; + pt->draw = file_panel_operator; + BLI_addtail(&art->paneltypes, pt); } diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 0294b635910..a432afc4d99 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -32,13 +32,15 @@ #include "file_intern.h" - void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds) { - int xmin, ymax; - - ED_fileselect_layout_tilepos(layout, file, &xmin, &ymax); - ymax = (int)ar->v2d.tot.ymax - ymax; /* real, view space ymax */ - BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, - ymax - layout->tile_h - layout->tile_border_y, ymax); + int xmin, ymax; + + ED_fileselect_layout_tilepos(layout, file, &xmin, &ymax); + ymax = (int)ar->v2d.tot.ymax - ymax; /* real, view space ymax */ + BLI_rcti_init(r_bounds, + xmin, + xmin + layout->tile_w + layout->tile_border_x, + ymax - layout->tile_h - layout->tile_border_y, + ymax); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 623442b753a..31a59f06079 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -21,7 +21,6 @@ * \ingroup spfile */ - /* global includes */ #include <stdlib.h> @@ -83,249 +82,246 @@ #include "filelist.h" - /* ----------------- FOLDERLIST (previous/next) -------------- */ typedef struct FolderList { - struct FolderList *next, *prev; - char *foldername; + struct FolderList *next, *prev; + char *foldername; } FolderList; ListBase *folderlist_new(void) { - ListBase *p = MEM_callocN(sizeof(*p), __func__); - return p; + ListBase *p = MEM_callocN(sizeof(*p), __func__); + return p; } void folderlist_popdir(struct ListBase *folderlist, char *dir) { - const char *prev_dir; - struct FolderList *folder; - folder = folderlist->last; + const char *prev_dir; + struct FolderList *folder; + folder = folderlist->last; - if (folder) { - /* remove the current directory */ - MEM_freeN(folder->foldername); - BLI_freelinkN(folderlist, folder); + if (folder) { + /* remove the current directory */ + MEM_freeN(folder->foldername); + BLI_freelinkN(folderlist, folder); - folder = folderlist->last; - if (folder) { - prev_dir = folder->foldername; - BLI_strncpy(dir, prev_dir, FILE_MAXDIR); - } - } - /* delete the folder next or use setdir directly before PREVIOUS OP */ + folder = folderlist->last; + if (folder) { + prev_dir = folder->foldername; + BLI_strncpy(dir, prev_dir, FILE_MAXDIR); + } + } + /* delete the folder next or use setdir directly before PREVIOUS OP */ } void folderlist_pushdir(ListBase *folderlist, const char *dir) { - struct FolderList *folder, *previous_folder; - previous_folder = folderlist->last; + struct FolderList *folder, *previous_folder; + previous_folder = folderlist->last; - /* check if already exists */ - if (previous_folder && previous_folder->foldername) { - if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { - return; - } - } + /* check if already exists */ + if (previous_folder && previous_folder->foldername) { + if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { + return; + } + } - /* create next folder element */ - folder = MEM_mallocN(sizeof(*folder), __func__); - folder->foldername = BLI_strdup(dir); + /* create next folder element */ + folder = MEM_mallocN(sizeof(*folder), __func__); + folder->foldername = BLI_strdup(dir); - /* add it to the end of the list */ - BLI_addtail(folderlist, folder); + /* add it to the end of the list */ + BLI_addtail(folderlist, folder); } const char *folderlist_peeklastdir(ListBase *folderlist) { - struct FolderList *folder; + struct FolderList *folder; - if (!folderlist->last) - return NULL; + if (!folderlist->last) + return NULL; - folder = folderlist->last; - return folder->foldername; + folder = folderlist->last; + return folder->foldername; } int folderlist_clear_next(struct SpaceFile *sfile) { - struct FolderList *folder; + struct FolderList *folder; - /* if there is no folder_next there is nothing we can clear */ - if (!sfile->folders_next) - return 0; + /* if there is no folder_next there is nothing we can clear */ + if (!sfile->folders_next) + return 0; - /* if previous_folder, next_folder or refresh_folder operators are executed - * it doesn't clear folder_next */ - folder = sfile->folders_prev->last; - if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) - return 0; + /* if previous_folder, next_folder or refresh_folder operators are executed + * it doesn't clear folder_next */ + folder = sfile->folders_prev->last; + if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) + return 0; - /* eventually clear flist->folders_next */ - return 1; + /* eventually clear flist->folders_next */ + return 1; } /* not listbase itself */ void folderlist_free(ListBase *folderlist) { - if (folderlist) { - FolderList *folder; - for (folder = folderlist->first; folder; folder = folder->next) - MEM_freeN(folder->foldername); - BLI_freelistN(folderlist); - } + if (folderlist) { + FolderList *folder; + for (folder = folderlist->first; folder; folder = folder->next) + MEM_freeN(folder->foldername); + BLI_freelistN(folderlist); + } } ListBase *folderlist_duplicate(ListBase *folderlist) { - if (folderlist) { - ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); - FolderList *folder; + if (folderlist) { + ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); + FolderList *folder; - BLI_duplicatelist(folderlistn, folderlist); + BLI_duplicatelist(folderlistn, folderlist); - for (folder = folderlistn->first; folder; folder = folder->next) { - folder->foldername = MEM_dupallocN(folder->foldername); - } - return folderlistn; - } - return NULL; + for (folder = folderlistn->first; folder; folder = folder->next) { + folder->foldername = MEM_dupallocN(folder->foldername); + } + return folderlistn; + } + return NULL; } - /* ------------------FILELIST------------------------ */ typedef struct FileListInternEntry { - struct FileListInternEntry *next, *prev; + struct FileListInternEntry *next, *prev; - /** ASSET_UUID_LENGTH */ - char uuid[16]; + /** ASSET_UUID_LENGTH */ + char uuid[16]; - /** eFileSel_File_Types */ - int typeflag; - /** ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */ - int blentype; + /** eFileSel_File_Types */ + int typeflag; + /** ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */ + int blentype; - char *relpath; - /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ - char *name; + char *relpath; + /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ + char *name; - BLI_stat_t st; + BLI_stat_t st; } FileListInternEntry; typedef struct FileListIntern { - /** FileListInternEntry items. */ - ListBase entries; - FileListInternEntry **filtered; + /** FileListInternEntry items. */ + ListBase entries; + FileListInternEntry **filtered; - char curr_uuid[16]; /* Used to generate uuid during internal listing. */ + char curr_uuid[16]; /* Used to generate uuid during internal listing. */ } FileListIntern; -#define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */ +#define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */ typedef struct FileListEntryCache { - size_t size; /* The size of the cache... */ + size_t size; /* The size of the cache... */ - int flags; + int flags; - /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */ - ListBase cached_entries; + /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */ + ListBase cached_entries; - /* Block cache: all entries between start and end index. - * used for part of the list on display. */ - FileDirEntry **block_entries; - int block_start_index, block_end_index, block_center_index, block_cursor; + /* Block cache: all entries between start and end index. + * used for part of the list on display. */ + FileDirEntry **block_entries; + int block_start_index, block_end_index, block_center_index, block_cursor; - /* Misc cache: random indices, FIFO behavior. - * Note: Not 100% sure we actually need that, time will say. */ - int misc_cursor; - int *misc_entries_indices; - GHash *misc_entries; + /* Misc cache: random indices, FIFO behavior. + * Note: Not 100% sure we actually need that, time will say. */ + int misc_cursor; + int *misc_entries_indices; + GHash *misc_entries; - /* Allows to quickly get a cached entry from its UUID. */ - GHash *uuids; + /* Allows to quickly get a cached entry from its UUID. */ + GHash *uuids; - /* Previews handling. */ - TaskPool *previews_pool; - ThreadQueue *previews_done; + /* Previews handling. */ + TaskPool *previews_pool; + ThreadQueue *previews_done; } FileListEntryCache; /* FileListCache.flags */ enum { - FLC_IS_INIT = 1 << 0, - FLC_PREVIEWS_ACTIVE = 1 << 1, + FLC_IS_INIT = 1 << 0, + FLC_PREVIEWS_ACTIVE = 1 << 1, }; typedef struct FileListEntryPreview { - char path[FILE_MAX]; - unsigned int flags; - int index; - ImBuf *img; + char path[FILE_MAX]; + unsigned int flags; + int index; + ImBuf *img; } FileListEntryPreview; - typedef struct FileListFilter { - unsigned int filter; - unsigned int filter_id; - char filter_glob[FILE_MAXFILE]; - char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */ - short flags; + unsigned int filter; + unsigned int filter_id; + char filter_glob[FILE_MAXFILE]; + char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */ + short flags; } FileListFilter; /* FileListFilter.flags */ enum { - FLF_DO_FILTER = 1 << 0, - FLF_HIDE_DOT = 1 << 1, - FLF_HIDE_PARENT = 1 << 2, - FLF_HIDE_LIB_DIR = 1 << 3, + FLF_DO_FILTER = 1 << 0, + FLF_HIDE_DOT = 1 << 1, + FLF_HIDE_PARENT = 1 << 2, + FLF_HIDE_LIB_DIR = 1 << 3, }; typedef struct FileList { - FileDirEntryArr filelist; + FileDirEntryArr filelist; - short prv_w; - short prv_h; + short prv_w; + short prv_h; - short flags; + short flags; - short sort; + short sort; - FileListFilter filter_data; + FileListFilter filter_data; - struct FileListIntern filelist_intern; + struct FileListIntern filelist_intern; - struct FileListEntryCache filelist_cache; + struct FileListEntryCache filelist_cache; - /* We need to keep those info outside of actual filelist items, because those are no more persistent - * (only generated on demand, and freed as soon as possible). - * Persistent part (mere list of paths + stat info) is kept as small as possible, and filebrowser-agnostic. - */ - GHash *selection_state; + /* We need to keep those info outside of actual filelist items, because those are no more persistent + * (only generated on demand, and freed as soon as possible). + * Persistent part (mere list of paths + stat info) is kept as small as possible, and filebrowser-agnostic. + */ + GHash *selection_state; - short max_recursion; - short recursion_level; + short max_recursion; + short recursion_level; - struct BlendHandle *libfiledata; + struct BlendHandle *libfiledata; - /* Set given path as root directory, if last bool is true may change given string in place to a valid value. - * Returns True if valid dir. */ - bool (*checkdirf)(struct FileList *, char *, const bool); + /* Set given path as root directory, if last bool is true may change given string in place to a valid value. + * Returns True if valid dir. */ + bool (*checkdirf)(struct FileList *, char *, const bool); - /* Fill filelist (to be called by read job). */ - void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); + /* Fill filelist (to be called by read job). */ + void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); - /* Filter an entry of current filelist. */ - bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + /* Filter an entry of current filelist. */ + bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); } FileList; /* FileList.flags */ enum { - FL_FORCE_RESET = 1 << 0, - FL_IS_READY = 1 << 1, - FL_IS_PENDING = 1 << 2, - FL_NEED_SORTING = 1 << 3, - FL_NEED_FILTERING = 1 << 4, + FL_FORCE_RESET = 1 << 0, + FL_IS_READY = 1 << 1, + FL_IS_PENDING = 1 << 2, + FL_NEED_SORTING = 1 << 3, + FL_NEED_FILTERING = 1 << 4, }; #define SPECIAL_IMG_SIZE 48 @@ -333,27 +329,29 @@ enum { #define SPECIAL_IMG_COLS 4 enum { - SPECIAL_IMG_FOLDER = 0, - SPECIAL_IMG_PARENT = 1, - SPECIAL_IMG_REFRESH = 2, - SPECIAL_IMG_BLENDFILE = 3, - SPECIAL_IMG_SOUNDFILE = 4, - SPECIAL_IMG_MOVIEFILE = 5, - SPECIAL_IMG_PYTHONFILE = 6, - SPECIAL_IMG_TEXTFILE = 7, - SPECIAL_IMG_FONTFILE = 8, - SPECIAL_IMG_UNKNOWNFILE = 9, - SPECIAL_IMG_LOADING = 10, - SPECIAL_IMG_BACKUP = 11, - SPECIAL_IMG_MAX, + SPECIAL_IMG_FOLDER = 0, + SPECIAL_IMG_PARENT = 1, + SPECIAL_IMG_REFRESH = 2, + SPECIAL_IMG_BLENDFILE = 3, + SPECIAL_IMG_SOUNDFILE = 4, + SPECIAL_IMG_MOVIEFILE = 5, + SPECIAL_IMG_PYTHONFILE = 6, + SPECIAL_IMG_TEXTFILE = 7, + SPECIAL_IMG_FONTFILE = 8, + SPECIAL_IMG_UNKNOWNFILE = 9, + SPECIAL_IMG_LOADING = 10, + SPECIAL_IMG_BACKUP = 11, + SPECIAL_IMG_MAX, }; static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; - -static void filelist_readjob_main(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); -static void filelist_readjob_lib(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); -static void filelist_readjob_dir(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); +static void filelist_readjob_main( + struct FileList *, const char *, short *, short *, float *, ThreadMutex *); +static void filelist_readjob_lib( + struct FileList *, const char *, short *, short *, float *, ThreadMutex *); +static void filelist_readjob_dir( + struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* helper, could probably go in BKE actually? */ static int groupname_to_code(const char *group); @@ -364,1053 +362,1114 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size); /* ********** Sort helpers ********** */ -static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2) -{ - /* type is equal to stat.st_mode */ - - if (entry1->typeflag & FILE_TYPE_DIR) { - if (entry2->typeflag & FILE_TYPE_DIR) { - /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs, - * then libs (.blend files), then categories in libs. */ - if (entry1->typeflag & FILE_TYPE_BLENDERLIB) { - if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) { - return 1; - } - } - else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) { - return -1; - } - else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - return 1; - } - } - else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - return -1; - } - } - else { - return -1; - } - } - else if (entry2->typeflag & FILE_TYPE_DIR) { - return 1; - } - - /* make sure "." and ".." are always first */ - if (FILENAME_IS_CURRENT(entry1->relpath)) return -1; - if (FILENAME_IS_CURRENT(entry2->relpath)) return 1; - if (FILENAME_IS_PARENT(entry1->relpath)) return -1; - if (FILENAME_IS_PARENT(entry2->relpath)) return 1; - - return 0; +static int compare_direntry_generic(const FileListInternEntry *entry1, + const FileListInternEntry *entry2) +{ + /* type is equal to stat.st_mode */ + + if (entry1->typeflag & FILE_TYPE_DIR) { + if (entry2->typeflag & FILE_TYPE_DIR) { + /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs, + * then libs (.blend files), then categories in libs. */ + if (entry1->typeflag & FILE_TYPE_BLENDERLIB) { + if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) { + return 1; + } + } + else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) { + return -1; + } + else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + return 1; + } + } + else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + return -1; + } + } + else { + return -1; + } + } + else if (entry2->typeflag & FILE_TYPE_DIR) { + return 1; + } + + /* make sure "." and ".." are always first */ + if (FILENAME_IS_CURRENT(entry1->relpath)) + return -1; + if (FILENAME_IS_CURRENT(entry2->relpath)) + return 1; + if (FILENAME_IS_PARENT(entry1->relpath)) + return -1; + if (FILENAME_IS_PARENT(entry2->relpath)) + return 1; + + return 0; } static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - int ret; + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + int ret; - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } - name1 = entry1->name; - name2 = entry2->name; + name1 = entry1->name; + name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_natstrcmp(name1, name2); } static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - int64_t time1, time2; - int ret; + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + int64_t time1, time2; + int ret; - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } - time1 = (int64_t)entry1->st.st_mtime; - time2 = (int64_t)entry2->st.st_mtime; - if (time1 < time2) return 1; - if (time1 > time2) return -1; + time1 = (int64_t)entry1->st.st_mtime; + time2 = (int64_t)entry2->st.st_mtime; + if (time1 < time2) + return 1; + if (time1 > time2) + return -1; - name1 = entry1->name; - name2 = entry2->name; + name1 = entry1->name; + name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_natstrcmp(name1, name2); } static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - uint64_t size1, size2; - int ret; + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + uint64_t size1, size2; + int ret; - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } - size1 = entry1->st.st_size; - size2 = entry2->st.st_size; - if (size1 < size2) return 1; - if (size1 > size2) return -1; + size1 = entry1->st.st_size; + size2 = entry2->st.st_size; + if (size1 < size2) + return 1; + if (size1 > size2) + return -1; - name1 = entry1->name; - name2 = entry2->name; + name1 = entry1->name; + name2 = entry2->name; - return BLI_natstrcmp(name1, name2); + return BLI_natstrcmp(name1, name2); } static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - char *name1, *name2; - int ret; - - if ((ret = compare_direntry_generic(entry1, entry2))) { - return ret; - } - - if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) return -1; - if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) return 1; - if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) { - if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) return 1; - if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) return -1; - if (entry1->blentype < entry2->blentype) return -1; - if (entry1->blentype > entry2->blentype) return 1; - } - else { - const char *sufix1, *sufix2; - - if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) - sufix1 = strrchr(entry1->relpath, '.'); - if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) - sufix2 = strrchr(entry2->relpath, '.'); - if (!sufix1) sufix1 = ""; - if (!sufix2) sufix2 = ""; - - if ((ret = BLI_strcasecmp(sufix1, sufix2))) { - return ret; - } - } - - name1 = entry1->name; - name2 = entry2->name; - - return BLI_natstrcmp(name1, name2); + const FileListInternEntry *entry1 = a1; + const FileListInternEntry *entry2 = a2; + char *name1, *name2; + int ret; + + if ((ret = compare_direntry_generic(entry1, entry2))) { + return ret; + } + + if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) + return -1; + if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) + return 1; + if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) { + if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) + return 1; + if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) + return -1; + if (entry1->blentype < entry2->blentype) + return -1; + if (entry1->blentype > entry2->blentype) + return 1; + } + else { + const char *sufix1, *sufix2; + + if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) + sufix1 = strrchr(entry1->relpath, '.'); + if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) + sufix2 = strrchr(entry2->relpath, '.'); + if (!sufix1) + sufix1 = ""; + if (!sufix2) + sufix2 = ""; + + if ((ret = BLI_strcasecmp(sufix1, sufix2))) { + return ret; + } + } + + name1 = entry1->name; + name2 = entry2->name; + + return BLI_natstrcmp(name1, name2); } void filelist_sort(struct FileList *filelist) { - if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) { - switch (filelist->sort) { - case FILE_SORT_ALPHA: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL); - break; - case FILE_SORT_TIME: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL); - break; - case FILE_SORT_SIZE: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL); - break; - case FILE_SORT_EXTENSION: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL); - break; - case FILE_SORT_NONE: /* Should never reach this point! */ - default: - BLI_assert(0); - break; - } - - filelist_filter_clear(filelist); - filelist->flags &= ~FL_NEED_SORTING; - } + if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) { + switch (filelist->sort) { + case FILE_SORT_ALPHA: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL); + break; + case FILE_SORT_TIME: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL); + break; + case FILE_SORT_SIZE: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL); + break; + case FILE_SORT_EXTENSION: + BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL); + break; + case FILE_SORT_NONE: /* Should never reach this point! */ + default: + BLI_assert(0); + break; + } + + filelist_filter_clear(filelist); + filelist->flags &= ~FL_NEED_SORTING; + } } void filelist_setsorting(struct FileList *filelist, const short sort) { - if (filelist->sort != sort) { - filelist->sort = sort; - filelist->flags |= FL_NEED_SORTING; - } + if (filelist->sort != sort) { + filelist->sort = sort; + filelist->flags |= FL_NEED_SORTING; + } } /* ********** Filter helpers ********** */ static bool is_hidden_file(const char *filename, FileListFilter *filter) { - char *sep = (char *)BLI_last_slash(filename); - bool is_hidden = false; - - if (filter->flags & FLF_HIDE_DOT) { - if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { - is_hidden = true; /* ignore .file */ - } - else { - int len = strlen(filename); - if ((len > 0) && (filename[len - 1] == '~')) { - is_hidden = true; /* ignore file~ */ - } - } - } - if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) { - if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { - is_hidden = true; /* ignore .. */ - } - } - if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { - is_hidden = true; /* ignore . */ - } - /* filename might actually be a piece of path, in which case we have to check all its parts. */ - if (!is_hidden && sep) { - char tmp_filename[FILE_MAX_LIBEXTRA]; - - BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename)); - sep = tmp_filename + (sep - filename); - while (sep) { - BLI_assert(sep[1] != '\0'); - if (is_hidden_file(sep + 1, filter)) { - is_hidden = true; - break; - } - *sep = '\0'; - sep = (char *)BLI_last_slash(tmp_filename); - } - } - return is_hidden; -} - -static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter) -{ - bool is_filtered = !is_hidden_file(file->relpath, filter); - - if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if (filter->filter) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } - } - } - else { - if (!(file->typeflag & filter->filter)) { - is_filtered = false; - } - } - } - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { - is_filtered = false; - } - } - } - - return is_filtered; + char *sep = (char *)BLI_last_slash(filename); + bool is_hidden = false; + + if (filter->flags & FLF_HIDE_DOT) { + if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { + is_hidden = true; /* ignore .file */ + } + else { + int len = strlen(filename); + if ((len > 0) && (filename[len - 1] == '~')) { + is_hidden = true; /* ignore file~ */ + } + } + } + if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) { + if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { + is_hidden = true; /* ignore .. */ + } + } + if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { + is_hidden = true; /* ignore . */ + } + /* filename might actually be a piece of path, in which case we have to check all its parts. */ + if (!is_hidden && sep) { + char tmp_filename[FILE_MAX_LIBEXTRA]; + + BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename)); + sep = tmp_filename + (sep - filename); + while (sep) { + BLI_assert(sep[1] != '\0'); + if (is_hidden_file(sep + 1, filter)) { + is_hidden = true; + break; + } + *sep = '\0'; + sep = (char *)BLI_last_slash(tmp_filename); + } + } + return is_hidden; +} + +static bool is_filtered_file(FileListInternEntry *file, + const char *UNUSED(root), + FileListFilter *filter) +{ + bool is_filtered = !is_hidden_file(file->relpath, filter); + + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & + (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } + } + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } + } + } + else { + if (!(file->typeflag & filter->filter)) { + is_filtered = false; + } + } + } + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + is_filtered = false; + } + } + } + + return is_filtered; } static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) { - bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; - - BLI_join_dirfile(path, sizeof(path), root, file->relpath); - - if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if (filter->filter || filter->filter_id) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } - } - } - if (is_filtered && group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { - is_filtered = false; - } - else { - unsigned int filter_id = groupname_to_filter_id(group); - if (!(filter_id & filter->filter_id)) { - is_filtered = false; - } - } - } - } - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { - is_filtered = false; - } - } - } - } - else { - is_filtered = is_filtered_file(file, root, filter); - } - - return is_filtered; -} - -static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter) -{ - return !is_hidden_file(file->relpath, filter); + bool is_filtered; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; + + BLI_join_dirfile(path, sizeof(path), root, file->relpath); + + if (BLO_library_path_explode(path, dir, &group, &name)) { + is_filtered = !is_hidden_file(file->relpath, filter); + if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter || filter->filter_id) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & + (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; + } + } + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { + is_filtered = false; + } + } + } + if (is_filtered && group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { + is_filtered = false; + } + else { + unsigned int filter_id = groupname_to_filter_id(group); + if (!(filter_id & filter->filter_id)) { + is_filtered = false; + } + } + } + } + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + is_filtered = false; + } + } + } + } + else { + is_filtered = is_filtered_file(file, root, filter); + } + + return is_filtered; +} + +static bool is_filtered_main(FileListInternEntry *file, + const char *UNUSED(dir), + FileListFilter *filter) +{ + return !is_hidden_file(file->relpath, filter); } static void filelist_filter_clear(FileList *filelist) { - filelist->flags |= FL_NEED_FILTERING; + filelist->flags |= FL_NEED_FILTERING; } void filelist_filter(FileList *filelist) { - int num_filtered = 0; - const int num_files = filelist->filelist.nbr_entries; - FileListInternEntry **filtered_tmp, *file; - - if (filelist->filelist.nbr_entries == 0) { - return; - } - - if (!(filelist->flags & FL_NEED_FILTERING)) { - /* Assume it has already been filtered, nothing else to do! */ - return; - } - - filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR; - if (filelist->max_recursion) { - /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless - * root path is a blend file. */ - char dir[FILE_MAX_LIBEXTRA]; - if (!filelist_islibrary(filelist, dir, NULL)) { - filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; - } - } - - filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__); - - /* Filter remap & count how many files are left after filter in a single loop. */ - for (file = filelist->filelist_intern.entries.first; file; file = file->next) { - if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { - filtered_tmp[num_filtered++] = file; - } - } - - if (filelist->filelist_intern.filtered) { - MEM_freeN(filelist->filelist_intern.filtered); - } - filelist->filelist_intern.filtered = MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, - __func__); - memcpy(filelist->filelist_intern.filtered, filtered_tmp, - sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered); - filelist->filelist.nbr_entries_filtered = num_filtered; -// printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries); - - filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); - filelist->flags &= ~FL_NEED_FILTERING; - - MEM_freeN(filtered_tmp); -} - -void filelist_setfilter_options(FileList *filelist, const bool do_filter, - const bool hide_dot, const bool hide_parent, - const unsigned int filter, const unsigned int filter_id, - const char *filter_glob, const char *filter_search) -{ - bool update = false; - - if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) { - filelist->filter_data.flags ^= FLF_DO_FILTER; - update = true; - } - if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) { - filelist->filter_data.flags ^= FLF_HIDE_DOT; - update = true; - } - if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) { - filelist->filter_data.flags ^= FLF_HIDE_PARENT; - update = true; - } - if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) { - filelist->filter_data.filter = filter; - filelist->filter_data.filter_id = filter_id; - update = true; - } - if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) { - BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob)); - update = true; - } - if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) { - BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, filter_search, '*', - sizeof(filelist->filter_data.filter_search)); - update = true; - } - - if (update) { - /* And now, free filtered data so that we know we have to filter again. */ - filelist_filter_clear(filelist); - } + int num_filtered = 0; + const int num_files = filelist->filelist.nbr_entries; + FileListInternEntry **filtered_tmp, *file; + + if (filelist->filelist.nbr_entries == 0) { + return; + } + + if (!(filelist->flags & FL_NEED_FILTERING)) { + /* Assume it has already been filtered, nothing else to do! */ + return; + } + + filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR; + if (filelist->max_recursion) { + /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless + * root path is a blend file. */ + char dir[FILE_MAX_LIBEXTRA]; + if (!filelist_islibrary(filelist, dir, NULL)) { + filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; + } + } + + filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__); + + /* Filter remap & count how many files are left after filter in a single loop. */ + for (file = filelist->filelist_intern.entries.first; file; file = file->next) { + if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { + filtered_tmp[num_filtered++] = file; + } + } + + if (filelist->filelist_intern.filtered) { + MEM_freeN(filelist->filelist_intern.filtered); + } + filelist->filelist_intern.filtered = MEM_mallocN( + sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, __func__); + memcpy(filelist->filelist_intern.filtered, + filtered_tmp, + sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered); + filelist->filelist.nbr_entries_filtered = num_filtered; + // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries); + + filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); + filelist->flags &= ~FL_NEED_FILTERING; + + MEM_freeN(filtered_tmp); +} + +void filelist_setfilter_options(FileList *filelist, + const bool do_filter, + const bool hide_dot, + const bool hide_parent, + const unsigned int filter, + const unsigned int filter_id, + const char *filter_glob, + const char *filter_search) +{ + bool update = false; + + if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) { + filelist->filter_data.flags ^= FLF_DO_FILTER; + update = true; + } + if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) { + filelist->filter_data.flags ^= FLF_HIDE_DOT; + update = true; + } + if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) { + filelist->filter_data.flags ^= FLF_HIDE_PARENT; + update = true; + } + if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) { + filelist->filter_data.filter = filter; + filelist->filter_data.filter_id = filter_id; + update = true; + } + if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) { + BLI_strncpy( + filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob)); + update = true; + } + if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) { + BLI_strncpy_ensure_pad(filelist->filter_data.filter_search, + filter_search, + '*', + sizeof(filelist->filter_data.filter_search)); + update = true; + } + + if (update) { + /* And now, free filtered data so that we know we have to filter again. */ + filelist_filter_clear(filelist); + } } /* ********** Icon/image helpers ********** */ void filelist_init_icons(void) { - short x, y, k; - ImBuf *bbuf; - ImBuf *ibuf; + short x, y, k; + ImBuf *bbuf; + ImBuf *ibuf; - BLI_assert(G.background == false); + BLI_assert(G.background == false); #ifdef WITH_HEADLESS - bbuf = NULL; + bbuf = NULL; #else - bbuf = IMB_ibImageFromMemory((const uchar *)datatoc_prvicons_png, datatoc_prvicons_png_size, IB_rect, NULL, "<splash>"); + bbuf = IMB_ibImageFromMemory( + (const uchar *)datatoc_prvicons_png, datatoc_prvicons_png_size, IB_rect, NULL, "<splash>"); #endif - if (bbuf) { - for (y = 0; y < SPECIAL_IMG_ROWS; y++) { - for (x = 0; x < SPECIAL_IMG_COLS; x++) { - int tile = SPECIAL_IMG_COLS * y + x; - if (tile < SPECIAL_IMG_MAX) { - ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect); - for (k = 0; k < SPECIAL_IMG_SIZE; k++) { - memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE], &bbuf->rect[(k + y * SPECIAL_IMG_SIZE) * SPECIAL_IMG_SIZE * SPECIAL_IMG_COLS + x * SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE * sizeof(int)); - } - gSpecialFileImages[tile] = ibuf; - } - } - } - IMB_freeImBuf(bbuf); - } + if (bbuf) { + for (y = 0; y < SPECIAL_IMG_ROWS; y++) { + for (x = 0; x < SPECIAL_IMG_COLS; x++) { + int tile = SPECIAL_IMG_COLS * y + x; + if (tile < SPECIAL_IMG_MAX) { + ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect); + for (k = 0; k < SPECIAL_IMG_SIZE; k++) { + memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE], + &bbuf->rect[(k + y * SPECIAL_IMG_SIZE) * SPECIAL_IMG_SIZE * SPECIAL_IMG_COLS + + x * SPECIAL_IMG_SIZE], + SPECIAL_IMG_SIZE * sizeof(int)); + } + gSpecialFileImages[tile] = ibuf; + } + } + } + IMB_freeImBuf(bbuf); + } } void filelist_free_icons(void) { - int i; + int i; - BLI_assert(G.background == false); + BLI_assert(G.background == false); - for (i = 0; i < SPECIAL_IMG_MAX; ++i) { - IMB_freeImBuf(gSpecialFileImages[i]); - gSpecialFileImages[i] = NULL; - } + for (i = 0; i < SPECIAL_IMG_MAX; ++i) { + IMB_freeImBuf(gSpecialFileImages[i]); + gSpecialFileImages[i] = NULL; + } } void filelist_imgsize(struct FileList *filelist, short w, short h) { - filelist->prv_w = w; - filelist->prv_h = h; + filelist->prv_w = w; + filelist->prv_h = h; } static FileDirEntry *filelist_geticon_get_file(struct FileList *filelist, const int index) { - BLI_assert(G.background == false); + BLI_assert(G.background == false); - return filelist_file(filelist, index); + return filelist_file(filelist, index); } ImBuf *filelist_getimage(struct FileList *filelist, const int index) { - FileDirEntry *file = filelist_geticon_get_file(filelist, index); + FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return file->image; + return file->image; } static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char *relpath) { - ImBuf *ibuf = NULL; - - if (typeflag & FILE_TYPE_DIR) { - if (FILENAME_IS_PARENT(relpath)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; - } - else if (FILENAME_IS_CURRENT(relpath)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; - } - else { - ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; - } - } - else if (typeflag & FILE_TYPE_BLENDER) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; - } - else if (typeflag & FILE_TYPE_BLENDERLIB) { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; - } - else if (typeflag & (FILE_TYPE_MOVIE)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; - } - else if (typeflag & FILE_TYPE_SOUND) { - ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; - } - else if (typeflag & FILE_TYPE_PYSCRIPT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; - } - else if (typeflag & FILE_TYPE_FTFONT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; - } - else if (typeflag & FILE_TYPE_TEXT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; - } - else if (typeflag & FILE_TYPE_IMAGE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; - } - else if (typeflag & FILE_TYPE_BLENDER_BACKUP) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; - } - else { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; - } - - return ibuf; + ImBuf *ibuf = NULL; + + if (typeflag & FILE_TYPE_DIR) { + if (FILENAME_IS_PARENT(relpath)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; + } + else if (FILENAME_IS_CURRENT(relpath)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; + } + else { + ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; + } + } + else if (typeflag & FILE_TYPE_BLENDER) { + ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; + } + else if (typeflag & FILE_TYPE_BLENDERLIB) { + ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; + } + else if (typeflag & (FILE_TYPE_MOVIE)) { + ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; + } + else if (typeflag & FILE_TYPE_SOUND) { + ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; + } + else if (typeflag & FILE_TYPE_PYSCRIPT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; + } + else if (typeflag & FILE_TYPE_FTFONT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; + } + else if (typeflag & FILE_TYPE_TEXT) { + ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; + } + else if (typeflag & FILE_TYPE_IMAGE) { + ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; + } + else if (typeflag & FILE_TYPE_BLENDER_BACKUP) { + ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; + } + else { + ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; + } + + return ibuf; } ImBuf *filelist_geticon_image(struct FileList *filelist, const int index) { - FileDirEntry *file = filelist_geticon_get_file(filelist, index); - - return filelist_geticon_image_ex(file->typeflag, file->relpath); -} - -static int filelist_geticon_ex( - const int typeflag, const int blentype, const char *relpath, const bool is_main, const bool ignore_libdir) -{ - if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { - if (FILENAME_IS_PARENT(relpath)) { - return is_main ? ICON_FILE_PARENT : ICON_NONE; - } - else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) { - return ICON_UGLYPACKAGE; - } - else if (typeflag & FILE_TYPE_BLENDER) { - return ICON_FILE_BLEND; - } - else if (is_main) { - /* Do not return icon for folders if icons are not 'main' draw type - * (e.g. when used over previews). */ - return ICON_FILE_FOLDER; - } - } - - if (typeflag & FILE_TYPE_BLENDER) - return ICON_FILE_BLEND; - else if (typeflag & FILE_TYPE_BLENDER_BACKUP) - return ICON_FILE_BACKUP; - else if (typeflag & FILE_TYPE_IMAGE) - return ICON_FILE_IMAGE; - else if (typeflag & FILE_TYPE_MOVIE) - return ICON_FILE_MOVIE; - else if (typeflag & FILE_TYPE_PYSCRIPT) - return ICON_FILE_SCRIPT; - else if (typeflag & FILE_TYPE_SOUND) - return ICON_FILE_SOUND; - else if (typeflag & FILE_TYPE_FTFONT) - return ICON_FILE_FONT; - else if (typeflag & FILE_TYPE_BTX) - return ICON_FILE_BLANK; - else if (typeflag & FILE_TYPE_COLLADA) - return ICON_FILE_BLANK; - else if (typeflag & FILE_TYPE_ALEMBIC) - return ICON_FILE_BLANK; - else if (typeflag & FILE_TYPE_TEXT) - return ICON_FILE_TEXT; - else if (typeflag & FILE_TYPE_BLENDERLIB) { - const int ret = UI_idcode_icon_get(blentype); - if (ret != ICON_NONE) { - return ret; - } - } - return is_main ? ICON_FILE_BLANK : ICON_NONE; + FileDirEntry *file = filelist_geticon_get_file(filelist, index); + + return filelist_geticon_image_ex(file->typeflag, file->relpath); +} + +static int filelist_geticon_ex(const int typeflag, + const int blentype, + const char *relpath, + const bool is_main, + const bool ignore_libdir) +{ + if ((typeflag & FILE_TYPE_DIR) && + !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { + if (FILENAME_IS_PARENT(relpath)) { + return is_main ? ICON_FILE_PARENT : ICON_NONE; + } + else if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) { + return ICON_UGLYPACKAGE; + } + else if (typeflag & FILE_TYPE_BLENDER) { + return ICON_FILE_BLEND; + } + else if (is_main) { + /* Do not return icon for folders if icons are not 'main' draw type + * (e.g. when used over previews). */ + return ICON_FILE_FOLDER; + } + } + + if (typeflag & FILE_TYPE_BLENDER) + return ICON_FILE_BLEND; + else if (typeflag & FILE_TYPE_BLENDER_BACKUP) + return ICON_FILE_BACKUP; + else if (typeflag & FILE_TYPE_IMAGE) + return ICON_FILE_IMAGE; + else if (typeflag & FILE_TYPE_MOVIE) + return ICON_FILE_MOVIE; + else if (typeflag & FILE_TYPE_PYSCRIPT) + return ICON_FILE_SCRIPT; + else if (typeflag & FILE_TYPE_SOUND) + return ICON_FILE_SOUND; + else if (typeflag & FILE_TYPE_FTFONT) + return ICON_FILE_FONT; + else if (typeflag & FILE_TYPE_BTX) + return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_COLLADA) + return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_ALEMBIC) + return ICON_FILE_BLANK; + else if (typeflag & FILE_TYPE_TEXT) + return ICON_FILE_TEXT; + else if (typeflag & FILE_TYPE_BLENDERLIB) { + const int ret = UI_idcode_icon_get(blentype); + if (ret != ICON_NONE) { + return ret; + } + } + return is_main ? ICON_FILE_BLANK : ICON_NONE; } int filelist_geticon(struct FileList *filelist, const int index, const bool is_main) { - FileDirEntry *file = filelist_geticon_get_file(filelist, index); + FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false); + return filelist_geticon_ex(file->typeflag, file->blentype, file->relpath, is_main, false); } /* ********** Main ********** */ -static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change) +static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), + char *r_dir, + const bool do_change) { - if (do_change) { - BLI_make_exist(r_dir); - return true; - } - else { - return BLI_is_dir(r_dir); - } + if (do_change) { + BLI_make_exist(r_dir); + return true; + } + else { + return BLI_is_dir(r_dir); + } } -static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change) +static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), + char *r_dir, + const bool do_change) { - char tdir[FILE_MAX_LIBEXTRA]; - char *name; + char tdir[FILE_MAX_LIBEXTRA]; + char *name; - const bool is_valid = (BLI_is_dir(r_dir) || - (BLO_library_path_explode(r_dir, tdir, NULL, &name) && BLI_is_file(tdir) && !name)); + const bool is_valid = (BLI_is_dir(r_dir) || + (BLO_library_path_explode(r_dir, tdir, NULL, &name) && + BLI_is_file(tdir) && !name)); - if (do_change && !is_valid) { - /* if not a valid library, we need it to be a valid directory! */ - BLI_make_exist(r_dir); - return true; - } - return is_valid; + if (do_change && !is_valid) { + /* if not a valid library, we need it to be a valid directory! */ + BLI_make_exist(r_dir); + return true; + } + return is_valid; } static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change) { - /* TODO */ - return filelist_checkdir_lib(filelist, r_dir, do_change); + /* TODO */ + return filelist_checkdir_lib(filelist, r_dir, do_change); } static void filelist_entry_clear(FileDirEntry *entry) { - if (entry->name) { - MEM_freeN(entry->name); - } - if (entry->description) { - MEM_freeN(entry->description); - } - if (entry->relpath) { - MEM_freeN(entry->relpath); - } - if (entry->image) { - IMB_freeImBuf(entry->image); - } - /* For now, consider FileDirEntryRevision::poin as not owned here, - * so no need to do anything about it */ - - if (!BLI_listbase_is_empty(&entry->variants)) { - FileDirEntryVariant *var; - - for (var = entry->variants.first; var; var = var->next) { - if (var->name) { - MEM_freeN(var->name); - } - if (var->description) { - MEM_freeN(var->description); - } - - if (!BLI_listbase_is_empty(&var->revisions)) { - FileDirEntryRevision *rev; - - for (rev = var->revisions.first; rev; rev = rev->next) { - if (rev->comment) { - MEM_freeN(rev->comment); - } - } - - BLI_freelistN(&var->revisions); - } - } - - /* TODO: tags! */ - - BLI_freelistN(&entry->variants); - } - else if (entry->entry) { - MEM_freeN(entry->entry); - } + if (entry->name) { + MEM_freeN(entry->name); + } + if (entry->description) { + MEM_freeN(entry->description); + } + if (entry->relpath) { + MEM_freeN(entry->relpath); + } + if (entry->image) { + IMB_freeImBuf(entry->image); + } + /* For now, consider FileDirEntryRevision::poin as not owned here, + * so no need to do anything about it */ + + if (!BLI_listbase_is_empty(&entry->variants)) { + FileDirEntryVariant *var; + + for (var = entry->variants.first; var; var = var->next) { + if (var->name) { + MEM_freeN(var->name); + } + if (var->description) { + MEM_freeN(var->description); + } + + if (!BLI_listbase_is_empty(&var->revisions)) { + FileDirEntryRevision *rev; + + for (rev = var->revisions.first; rev; rev = rev->next) { + if (rev->comment) { + MEM_freeN(rev->comment); + } + } + + BLI_freelistN(&var->revisions); + } + } + + /* TODO: tags! */ + + BLI_freelistN(&entry->variants); + } + else if (entry->entry) { + MEM_freeN(entry->entry); + } } static void filelist_entry_free(FileDirEntry *entry) { - filelist_entry_clear(entry); - MEM_freeN(entry); + filelist_entry_clear(entry); + MEM_freeN(entry); } static void filelist_direntryarr_free(FileDirEntryArr *array) { #if 0 - FileDirEntry *entry, *entry_next; + FileDirEntry *entry, *entry_next; - for (entry = array->entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_entry_free(entry); - } - BLI_listbase_clear(&array->entries); + for (entry = array->entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&array->entries); #else - BLI_assert(BLI_listbase_is_empty(&array->entries)); + BLI_assert(BLI_listbase_is_empty(&array->entries)); #endif - array->nbr_entries = 0; - array->nbr_entries_filtered = -1; - array->entry_idx_start = -1; - array->entry_idx_end = -1; + array->nbr_entries = 0; + array->nbr_entries_filtered = -1; + array->entry_idx_start = -1; + array->entry_idx_end = -1; } static void filelist_intern_entry_free(FileListInternEntry *entry) { - if (entry->relpath) { - MEM_freeN(entry->relpath); - } - if (entry->name) { - MEM_freeN(entry->name); - } - MEM_freeN(entry); + if (entry->relpath) { + MEM_freeN(entry->relpath); + } + if (entry->name) { + MEM_freeN(entry->name); + } + MEM_freeN(entry); } static void filelist_intern_free(FileListIntern *filelist_intern) { - FileListInternEntry *entry, *entry_next; + FileListInternEntry *entry, *entry_next; - for (entry = filelist_intern->entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_intern_entry_free(entry); - } - BLI_listbase_clear(&filelist_intern->entries); + for (entry = filelist_intern->entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_intern_entry_free(entry); + } + BLI_listbase_clear(&filelist_intern->entries); - MEM_SAFE_FREE(filelist_intern->filtered); + MEM_SAFE_FREE(filelist_intern->filtered); } -static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid)) +static void filelist_cache_preview_runf(TaskPool *__restrict pool, + void *taskdata, + int UNUSED(threadid)) { - FileListEntryCache *cache = BLI_task_pool_userdata(pool); - FileListEntryPreview *preview = taskdata; + FileListEntryCache *cache = BLI_task_pool_userdata(pool); + FileListEntryPreview *preview = taskdata; - ThumbSource source = 0; + ThumbSource source = 0; -// printf("%s: Start (%d)...\n", __func__, threadid); + // printf("%s: Start (%d)...\n", __func__, threadid); -// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - BLI_assert(preview->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | - FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + BLI_assert(preview->flags & + (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | + FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); - if (preview->flags & FILE_TYPE_IMAGE) { - source = THB_SOURCE_IMAGE; - } - else if (preview->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { - source = THB_SOURCE_BLEND; - } - else if (preview->flags & FILE_TYPE_MOVIE) { - source = THB_SOURCE_MOVIE; - } - else if (preview->flags & FILE_TYPE_FTFONT) { - source = THB_SOURCE_FONT; - } + if (preview->flags & FILE_TYPE_IMAGE) { + source = THB_SOURCE_IMAGE; + } + else if (preview->flags & + (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { + source = THB_SOURCE_BLEND; + } + else if (preview->flags & FILE_TYPE_MOVIE) { + source = THB_SOURCE_MOVIE; + } + else if (preview->flags & FILE_TYPE_FTFONT) { + source = THB_SOURCE_FONT; + } - IMB_thumb_path_lock(preview->path); - preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); - IMB_thumb_path_unlock(preview->path); + IMB_thumb_path_lock(preview->path); + preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); + IMB_thumb_path_unlock(preview->path); - /* Used to tell free func to not free anything. - * Note that we do not care about cas result here, - * we only want value attribution itself to be atomic (and memory barier).*/ - atomic_cas_uint32(&preview->flags, preview->flags, 0); - BLI_thread_queue_push(cache->previews_done, preview); + /* Used to tell free func to not free anything. + * Note that we do not care about cas result here, + * we only want value attribution itself to be atomic (and memory barier).*/ + atomic_cas_uint32(&preview->flags, preview->flags, 0); + BLI_thread_queue_push(cache->previews_done, preview); -// printf("%s: End (%d)...\n", __func__, threadid); + // printf("%s: End (%d)...\n", __func__, threadid); } -static void filelist_cache_preview_freef(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), + void *taskdata, + int UNUSED(threadid)) { - FileListEntryPreview *preview = taskdata; + FileListEntryPreview *preview = taskdata; - /* If preview->flag is empty, it means that preview has already been generated and added to done queue, - * we do not own it anymore. */ - if (preview->flags) { - if (preview->img) { - IMB_freeImBuf(preview->img); - } - MEM_freeN(preview); - } + /* If preview->flag is empty, it means that preview has already been generated and added to done queue, + * we do not own it anymore. */ + if (preview->flags) { + if (preview->img) { + IMB_freeImBuf(preview->img); + } + MEM_freeN(preview); + } } static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) { - if (!cache->previews_pool) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); + if (!cache->previews_pool) { + TaskScheduler *scheduler = BLI_task_scheduler_get(); - cache->previews_pool = BLI_task_pool_create_background(scheduler, cache); - cache->previews_done = BLI_thread_queue_init(); + cache->previews_pool = BLI_task_pool_create_background(scheduler, cache); + cache->previews_done = BLI_thread_queue_init(); - IMB_thumb_locks_acquire(); - } + IMB_thumb_locks_acquire(); + } } static void filelist_cache_previews_clear(FileListEntryCache *cache) { - FileListEntryPreview *preview; + FileListEntryPreview *preview; - if (cache->previews_pool) { - BLI_task_pool_cancel(cache->previews_pool); + if (cache->previews_pool) { + BLI_task_pool_cancel(cache->previews_pool); - while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { -// printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->img) { - IMB_freeImBuf(preview->img); - } - MEM_freeN(preview); - } - } + while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { + // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + if (preview->img) { + IMB_freeImBuf(preview->img); + } + MEM_freeN(preview); + } + } } static void filelist_cache_previews_free(FileListEntryCache *cache) { - if (cache->previews_pool) { - BLI_thread_queue_nowait(cache->previews_done); + if (cache->previews_pool) { + BLI_thread_queue_nowait(cache->previews_done); - filelist_cache_previews_clear(cache); + filelist_cache_previews_clear(cache); - BLI_thread_queue_free(cache->previews_done); - BLI_task_pool_free(cache->previews_pool); - cache->previews_pool = NULL; - cache->previews_done = NULL; + BLI_thread_queue_free(cache->previews_done); + BLI_task_pool_free(cache->previews_pool); + cache->previews_pool = NULL; + cache->previews_done = NULL; - IMB_thumb_locks_release(); - } + IMB_thumb_locks_release(); + } - cache->flags &= ~FLC_PREVIEWS_ACTIVE; + cache->flags &= ~FLC_PREVIEWS_ACTIVE; } static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); + BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); - if (!entry->image && - !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && - (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | - FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) - { - FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); - BLI_join_dirfile(preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); - preview->index = index; - preview->flags = entry->typeflag; - preview->img = NULL; -// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + if (!entry->image && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && + (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | + FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { + FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); + BLI_join_dirfile( + preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); + preview->index = index; + preview->flags = entry->typeflag; + preview->img = NULL; + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - filelist_cache_preview_ensure_running(cache); - BLI_task_pool_push_ex(cache->previews_pool, filelist_cache_preview_runf, preview, - true, filelist_cache_preview_freef, TASK_PRIORITY_LOW); - } + filelist_cache_preview_ensure_running(cache); + BLI_task_pool_push_ex(cache->previews_pool, + filelist_cache_preview_runf, + preview, + true, + filelist_cache_preview_freef, + TASK_PRIORITY_LOW); + } } static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) { - BLI_listbase_clear(&cache->cached_entries); + BLI_listbase_clear(&cache->cached_entries); - cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; - cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); + cache->block_cursor = cache->block_start_index = cache->block_center_index = + cache->block_end_index = 0; + cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); - cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size); - cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, __func__); - copy_vn_i(cache->misc_entries_indices, cache_size, -1); - cache->misc_cursor = 0; + cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size); + cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, + __func__); + copy_vn_i(cache->misc_entries_indices, cache_size, -1); + cache->misc_cursor = 0; - /* XXX This assumes uint is 32 bits and uuid is 128 bits (char[16]), be careful! */ - cache->uuids = BLI_ghash_new_ex( - BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__, cache_size * 2); + /* XXX This assumes uint is 32 bits and uuid is 128 bits (char[16]), be careful! */ + cache->uuids = BLI_ghash_new_ex( + BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__, cache_size * 2); - cache->size = cache_size; - cache->flags = FLC_IS_INIT; + cache->size = cache_size; + cache->flags = FLC_IS_INIT; } static void filelist_cache_free(FileListEntryCache *cache) { - FileDirEntry *entry, *entry_next; + FileDirEntry *entry, *entry_next; - if (!(cache->flags & FLC_IS_INIT)) { - return; - } + if (!(cache->flags & FLC_IS_INIT)) { + return; + } - filelist_cache_previews_free(cache); + filelist_cache_previews_free(cache); - MEM_freeN(cache->block_entries); + MEM_freeN(cache->block_entries); - BLI_ghash_free(cache->misc_entries, NULL, NULL); - MEM_freeN(cache->misc_entries_indices); + BLI_ghash_free(cache->misc_entries, NULL, NULL); + MEM_freeN(cache->misc_entries_indices); - BLI_ghash_free(cache->uuids, NULL, NULL); + BLI_ghash_free(cache->uuids, NULL, NULL); - for (entry = cache->cached_entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_entry_free(entry); - } - BLI_listbase_clear(&cache->cached_entries); + for (entry = cache->cached_entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&cache->cached_entries); } static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) { - FileDirEntry *entry, *entry_next; + FileDirEntry *entry, *entry_next; - if (!(cache->flags & FLC_IS_INIT)) { - return; - } + if (!(cache->flags & FLC_IS_INIT)) { + return; + } - filelist_cache_previews_clear(cache); + filelist_cache_previews_clear(cache); - cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; - if (new_size != cache->size) { - cache->block_entries = MEM_reallocN(cache->block_entries, sizeof(*cache->block_entries) * new_size); - } + cache->block_cursor = cache->block_start_index = cache->block_center_index = + cache->block_end_index = 0; + if (new_size != cache->size) { + cache->block_entries = MEM_reallocN(cache->block_entries, + sizeof(*cache->block_entries) * new_size); + } - BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size); - if (new_size != cache->size) { - cache->misc_entries_indices = MEM_reallocN(cache->misc_entries_indices, - sizeof(*cache->misc_entries_indices) * new_size); - } - copy_vn_i(cache->misc_entries_indices, new_size, -1); + BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size); + if (new_size != cache->size) { + cache->misc_entries_indices = MEM_reallocN(cache->misc_entries_indices, + sizeof(*cache->misc_entries_indices) * new_size); + } + copy_vn_i(cache->misc_entries_indices, new_size, -1); - BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2); + BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2); - cache->size = new_size; + cache->size = new_size; - for (entry = cache->cached_entries.first; entry; entry = entry_next) { - entry_next = entry->next; - filelist_entry_free(entry); - } - BLI_listbase_clear(&cache->cached_entries); + for (entry = cache->cached_entries.first; entry; entry = entry_next) { + entry_next = entry->next; + filelist_entry_free(entry); + } + BLI_listbase_clear(&cache->cached_entries); } FileList *filelist_new(short type) { - FileList *p = MEM_callocN(sizeof(*p), __func__); - - filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); - - p->selection_state = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); - - switch (type) { - case FILE_MAIN: - p->checkdirf = filelist_checkdir_main; - p->read_jobf = filelist_readjob_main; - p->filterf = is_filtered_main; - break; - case FILE_LOADLIB: - p->checkdirf = filelist_checkdir_lib; - p->read_jobf = filelist_readjob_lib; - p->filterf = is_filtered_lib; - break; - default: - p->checkdirf = filelist_checkdir_dir; - p->read_jobf = filelist_readjob_dir; - p->filterf = is_filtered_file; - break; - } - return p; + FileList *p = MEM_callocN(sizeof(*p), __func__); + + filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); + + p->selection_state = BLI_ghash_new( + BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); + + switch (type) { + case FILE_MAIN: + p->checkdirf = filelist_checkdir_main; + p->read_jobf = filelist_readjob_main; + p->filterf = is_filtered_main; + break; + case FILE_LOADLIB: + p->checkdirf = filelist_checkdir_lib; + p->read_jobf = filelist_readjob_lib; + p->filterf = is_filtered_lib; + break; + default: + p->checkdirf = filelist_checkdir_dir; + p->read_jobf = filelist_readjob_dir; + p->filterf = is_filtered_file; + break; + } + return p; } void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection) { - if (!filelist) { - return; - } + if (!filelist) { + return; + } - filelist_filter_clear(filelist); + filelist_filter_clear(filelist); - if (do_cache) { - filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); - } + if (do_cache) { + filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); + } - filelist_intern_free(&filelist->filelist_intern); + filelist_intern_free(&filelist->filelist_intern); - filelist_direntryarr_free(&filelist->filelist); + filelist_direntryarr_free(&filelist->filelist); - if (do_selection && filelist->selection_state) { - BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL); - } + if (do_selection && filelist->selection_state) { + BLI_ghash_clear(filelist->selection_state, MEM_freeN, NULL); + } } void filelist_clear(struct FileList *filelist) { - filelist_clear_ex(filelist, true, true); + filelist_clear_ex(filelist, true, true); } void filelist_free(struct FileList *filelist) { - if (!filelist) { - printf("Attempting to delete empty filelist.\n"); - return; - } + if (!filelist) { + printf("Attempting to delete empty filelist.\n"); + return; + } - /* No need to clear cache & selection_state, we free them anyway. */ - filelist_clear_ex(filelist, false, false); - filelist_cache_free(&filelist->filelist_cache); + /* No need to clear cache & selection_state, we free them anyway. */ + filelist_clear_ex(filelist, false, false); + filelist_cache_free(&filelist->filelist_cache); - if (filelist->selection_state) { - BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL); - filelist->selection_state = NULL; - } + if (filelist->selection_state) { + BLI_ghash_free(filelist->selection_state, MEM_freeN, NULL); + filelist->selection_state = NULL; + } - memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); + memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); - filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING); - filelist->sort = FILE_SORT_NONE; + filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING); + filelist->sort = FILE_SORT_NONE; } void filelist_freelib(struct FileList *filelist) { - if (filelist->libfiledata) - BLO_blendhandle_close(filelist->libfiledata); - filelist->libfiledata = NULL; + if (filelist->libfiledata) + BLO_blendhandle_close(filelist->libfiledata); + filelist->libfiledata = NULL; } BlendHandle *filelist_lib(struct FileList *filelist) { - return filelist->libfiledata; + return filelist->libfiledata; } -static const char *fileentry_uiname(const char *root, const char *relpath, const int typeflag, char *buff) +static const char *fileentry_uiname(const char *root, + const char *relpath, + const int typeflag, + char *buff) { - char *name = NULL; + char *name = NULL; - if (typeflag & FILE_TYPE_BLENDERLIB) { - char abspath[FILE_MAX_LIBEXTRA]; - char *group; + if (typeflag & FILE_TYPE_BLENDERLIB) { + char abspath[FILE_MAX_LIBEXTRA]; + char *group; - BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); - BLO_library_path_explode(abspath, buff, &group, &name); - if (!name) { - name = group; - } - } - /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */ - if (!name) { - if (typeflag & FILE_TYPE_DIR) { - name = (char *)relpath; - } - else { - name = (char *)BLI_path_basename(relpath); - } - } - BLI_assert(name); + BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); + BLO_library_path_explode(abspath, buff, &group, &name); + if (!name) { + name = group; + } + } + /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */ + if (!name) { + if (typeflag & FILE_TYPE_DIR) { + name = (char *)relpath; + } + else { + name = (char *)BLI_path_basename(relpath); + } + } + BLI_assert(name); - return name; + return name; } const char *filelist_dir(struct FileList *filelist) { - return filelist->filelist.root; + return filelist->filelist.root; } bool filelist_is_dir(struct FileList *filelist, const char *path) { - return filelist->checkdirf(filelist, (char *)path, false); + return filelist->checkdirf(filelist, (char *)path, false); } /** @@ -1418,40 +1477,40 @@ bool filelist_is_dir(struct FileList *filelist, const char *path) */ void filelist_setdir(struct FileList *filelist, char *r_dir) { - BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); + BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); - BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); - BLI_assert(is_valid_path); - UNUSED_VARS_NDEBUG(is_valid_path); + BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir); + const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); + BLI_assert(is_valid_path); + UNUSED_VARS_NDEBUG(is_valid_path); - if (!STREQ(filelist->filelist.root, r_dir)) { - BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root)); - filelist->flags |= FL_FORCE_RESET; - } + if (!STREQ(filelist->filelist.root, r_dir)) { + BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root)); + filelist->flags |= FL_FORCE_RESET; + } } void filelist_setrecursion(struct FileList *filelist, const int recursion_level) { - if (filelist->max_recursion != recursion_level) { - filelist->max_recursion = recursion_level; - filelist->flags |= FL_FORCE_RESET; - } + if (filelist->max_recursion != recursion_level) { + filelist->max_recursion = recursion_level; + filelist->flags |= FL_FORCE_RESET; + } } bool filelist_force_reset(struct FileList *filelist) { - return (filelist->flags & FL_FORCE_RESET) != 0; + return (filelist->flags & FL_FORCE_RESET) != 0; } bool filelist_is_ready(struct FileList *filelist) { - return (filelist->flags & FL_IS_READY) != 0; + return (filelist->flags & FL_IS_READY) != 0; } bool filelist_pending(struct FileList *filelist) { - return (filelist->flags & FL_IS_PENDING) != 0; + return (filelist->flags & FL_IS_PENDING) != 0; } /** @@ -1460,740 +1519,759 @@ bool filelist_pending(struct FileList *filelist) */ int filelist_files_ensure(FileList *filelist) { - if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) { - filelist_sort(filelist); - filelist_filter(filelist); - } + if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) { + filelist_sort(filelist); + filelist_filter(filelist); + } - return filelist->filelist.nbr_entries_filtered; + return filelist->filelist.nbr_entries_filtered; } static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index) { - FileListInternEntry *entry = filelist->filelist_intern.filtered[index]; - FileListEntryCache *cache = &filelist->filelist_cache; - FileDirEntry *ret; - FileDirEntryRevision *rev; + FileListInternEntry *entry = filelist->filelist_intern.filtered[index]; + FileListEntryCache *cache = &filelist->filelist_cache; + FileDirEntry *ret; + FileDirEntryRevision *rev; - ret = MEM_callocN(sizeof(*ret), __func__); - rev = MEM_callocN(sizeof(*rev), __func__); + ret = MEM_callocN(sizeof(*ret), __func__); + rev = MEM_callocN(sizeof(*rev), __func__); - rev->size = (uint64_t)entry->st.st_size; + rev->size = (uint64_t)entry->st.st_size; - rev->time = (int64_t)entry->st.st_mtime; + rev->time = (int64_t)entry->st.st_mtime; - ret->entry = rev; - ret->relpath = BLI_strdup(entry->relpath); - ret->name = BLI_strdup(entry->name); - ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath); - memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid)); - ret->blentype = entry->blentype; - ret->typeflag = entry->typeflag; + ret->entry = rev; + ret->relpath = BLI_strdup(entry->relpath); + ret->name = BLI_strdup(entry->name); + ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath); + memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid)); + ret->blentype = entry->blentype; + ret->typeflag = entry->typeflag; - BLI_addtail(&cache->cached_entries, ret); - return ret; + BLI_addtail(&cache->cached_entries, ret); + return ret; } static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) { - BLI_remlink(&filelist->filelist_cache.cached_entries, entry); - filelist_entry_free(entry); + BLI_remlink(&filelist->filelist_cache.cached_entries, entry); + filelist_entry_free(entry); } -static FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request) +static FileDirEntry *filelist_file_ex(struct FileList *filelist, + const int index, + const bool use_request) { - FileDirEntry *ret = NULL, *old; - FileListEntryCache *cache = &filelist->filelist_cache; - const size_t cache_size = cache->size; - int old_index; + FileDirEntry *ret = NULL, *old; + FileListEntryCache *cache = &filelist->filelist_cache; + const size_t cache_size = cache->size; + int old_index; - if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) { - return ret; - } + if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) { + return ret; + } - if (index >= cache->block_start_index && index < cache->block_end_index) { - const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size; - return cache->block_entries[idx]; - } + if (index >= cache->block_start_index && index < cache->block_end_index) { + const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size; + return cache->block_entries[idx]; + } - if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) { - return ret; - } + if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) { + return ret; + } - if (!use_request) { - return NULL; - } + if (!use_request) { + return NULL; + } -// printf("requesting file %d (not yet cached)\n", index); + // printf("requesting file %d (not yet cached)\n", index); - /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */ - ret = filelist_file_create_entry(filelist, index); - old_index = cache->misc_entries_indices[cache->misc_cursor]; - if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) { - BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL); - filelist_file_release_entry(filelist, old); - } - BLI_ghash_insert(cache->misc_entries, POINTER_FROM_INT(index), ret); - BLI_ghash_insert(cache->uuids, ret->uuid, ret); + /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */ + ret = filelist_file_create_entry(filelist, index); + old_index = cache->misc_entries_indices[cache->misc_cursor]; + if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) { + BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL); + filelist_file_release_entry(filelist, old); + } + BLI_ghash_insert(cache->misc_entries, POINTER_FROM_INT(index), ret); + BLI_ghash_insert(cache->uuids, ret->uuid, ret); - cache->misc_entries_indices[cache->misc_cursor] = index; - cache->misc_cursor = (cache->misc_cursor + 1) % cache_size; + cache->misc_entries_indices[cache->misc_cursor] = index; + cache->misc_cursor = (cache->misc_cursor + 1) % cache_size; -#if 0 /* Actually no, only block cached entries should have preview imho. */ - if (cache->previews_pool) { - filelist_cache_previews_push(filelist, ret, index); - } +#if 0 /* Actually no, only block cached entries should have preview imho. */ + if (cache->previews_pool) { + filelist_cache_previews_push(filelist, ret, index); + } #endif - return ret; + return ret; } FileDirEntry *filelist_file(struct FileList *filelist, int index) { - return filelist_file_ex(filelist, index, true); + return filelist_file_ex(filelist, index, true); } int filelist_file_findpath(struct FileList *filelist, const char *filename) { - int fidx = -1; + int fidx = -1; - if (filelist->filelist.nbr_entries_filtered < 0) { - return fidx; - } + if (filelist->filelist.nbr_entries_filtered < 0) { + return fidx; + } - /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though. - * This is only used to find again renamed entry, - * annoying but looks hairy to get rid of it currently. */ + /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though. + * This is only used to find again renamed entry, + * annoying but looks hairy to get rid of it currently. */ - for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { - FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; - if (STREQ(entry->relpath, filename)) { - return fidx; - } - } + for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { + FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; + if (STREQ(entry->relpath, filename)) { + return fidx; + } + } - return -1; + return -1; } FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]) { - if (filelist->filelist.nbr_entries_filtered < 0) { - return NULL; - } + if (filelist->filelist.nbr_entries_filtered < 0) { + return NULL; + } - if (filelist->filelist_cache.uuids) { - FileDirEntry *entry = BLI_ghash_lookup(filelist->filelist_cache.uuids, uuid); - if (entry) { - return entry; - } - } + if (filelist->filelist_cache.uuids) { + FileDirEntry *entry = BLI_ghash_lookup(filelist->filelist_cache.uuids, uuid); + if (entry) { + return entry; + } + } - { - int fidx; + { + int fidx; - for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { - FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; - if (memcmp(entry->uuid, uuid, sizeof(entry->uuid)) == 0) { - return filelist_file(filelist, fidx); - } - } - } + for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) { + FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx]; + if (memcmp(entry->uuid, uuid, sizeof(entry->uuid)) == 0) { + return filelist_file(filelist, fidx); + } + } + } - return NULL; + return NULL; } void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size) { - /* Always keep it power of 2, in [256, 8192] range for now, - * cache being app. twice bigger than requested window. */ - size_t size = 256; - window_size *= 2; + /* Always keep it power of 2, in [256, 8192] range for now, + * cache being app. twice bigger than requested window. */ + size_t size = 256; + window_size *= 2; - while (size < window_size && size < 8192) { - size *= 2; - } + while (size < window_size && size < 8192) { + size *= 2; + } - if (size != filelist->filelist_cache.size) { - filelist_cache_clear(&filelist->filelist_cache, size); - } + if (size != filelist->filelist_cache.size) { + filelist_cache_clear(&filelist->filelist_cache, size); + } } /* Helpers, low-level, they assume cursor + size <= cache_size */ -static bool filelist_file_cache_block_create(FileList *filelist, const int start_index, const int size, int cursor) +static bool filelist_file_cache_block_create(FileList *filelist, + const int start_index, + const int size, + int cursor) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - { - int i, idx; + { + int i, idx; - for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) { - FileDirEntry *entry; + for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) { + FileDirEntry *entry; - /* That entry might have already been requested and stored in misc cache... */ - if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) { - entry = filelist_file_create_entry(filelist, idx); - BLI_ghash_insert(cache->uuids, entry->uuid, entry); - } - cache->block_entries[cursor] = entry; - } - return true; - } + /* That entry might have already been requested and stored in misc cache... */ + if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) { + entry = filelist_file_create_entry(filelist, idx); + BLI_ghash_insert(cache->uuids, entry->uuid, entry); + } + cache->block_entries[cursor] = entry; + } + return true; + } - return false; + return false; } -static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor) +static void filelist_file_cache_block_release(struct FileList *filelist, + const int size, + int cursor) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - { - int i; + { + int i; - for (i = 0; i < size; i++, cursor++) { - FileDirEntry *entry = cache->block_entries[cursor]; -// printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/); - BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL); - filelist_file_release_entry(filelist, entry); + for (i = 0; i < size; i++, cursor++) { + FileDirEntry *entry = cache->block_entries[cursor]; + // printf("%s: release cacheidx %d (%%p %%s)\n", __func__, cursor/*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/); + BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL); + filelist_file_release_entry(filelist, entry); #ifndef NDEBUG - cache->block_entries[cursor] = NULL; + cache->block_entries[cursor] = NULL; #endif - } - } + } + } } /* Load in cache all entries "around" given index (as much as block cache may hold). */ bool filelist_file_cache_block(struct FileList *filelist, const int index) { - FileListEntryCache *cache = &filelist->filelist_cache; - const size_t cache_size = cache->size; - - const int nbr_entries = filelist->filelist.nbr_entries_filtered; - int start_index = max_ii(0, index - (cache_size / 2)); - int end_index = min_ii(nbr_entries, index + (cache_size / 2)); - int i; - const bool full_refresh = (filelist->flags & FL_IS_READY) == 0; - - if ((index < 0) || (index >= nbr_entries)) { -// printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries); - return false; - } - - /* Maximize cached range! */ - if ((end_index - start_index) < cache_size) { - if (start_index == 0) { - end_index = min_ii(nbr_entries, start_index + cache_size); - } - else if (end_index == nbr_entries) { - start_index = max_ii(0, end_index - cache_size); - } - } - - BLI_assert((end_index - start_index) <= cache_size) ; - -// printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__, -// start_index, end_index, index, cache->block_start_index, cache->block_end_index); - - /* If we have something to (re)cache... */ - if (full_refresh || (start_index != cache->block_start_index) || (end_index != cache->block_end_index)) { - if (full_refresh || (start_index >= cache->block_end_index) || (end_index <= cache->block_start_index)) { - int size1 = cache->block_end_index - cache->block_start_index; - int size2 = 0; - int idx1 = cache->block_cursor, idx2 = 0; - -// printf("Full Recaching!\n"); - - if (cache->flags & FLC_PREVIEWS_ACTIVE) { - filelist_cache_previews_clear(cache); - } - - if (idx1 + size1 > cache_size) { - size2 = idx1 + size1 - cache_size; - size1 -= size2; - filelist_file_cache_block_release(filelist, size2, idx2); - } - filelist_file_cache_block_release(filelist, size1, idx1); - - cache->block_start_index = cache->block_end_index = cache->block_cursor = 0; - - /* New cached block does not overlap existing one, simple. */ - if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) { - return false; - } - - cache->block_start_index = start_index; - cache->block_end_index = end_index; - } - else { -// printf("Partial Recaching!\n"); - - /* At this point, we know we keep part of currently cached entries, so update previews - * if needed, and remove everything from working queue - we'll add all newly needed - * entries at the end. */ - if (cache->flags & FLC_PREVIEWS_ACTIVE) { - filelist_cache_previews_update(filelist); - filelist_cache_previews_clear(cache); - } - -// printf("\tpreview cleaned up...\n"); - - if (start_index > cache->block_start_index) { - int size1 = start_index - cache->block_start_index; - int size2 = 0; - int idx1 = cache->block_cursor, idx2 = 0; - -// printf("\tcache releasing: [%d:%d] (%d, %d)\n", -// cache->block_start_index, cache->block_start_index + size1, -// cache->block_cursor, size1); - - if (idx1 + size1 > cache_size) { - size2 = idx1 + size1 - cache_size; - size1 -= size2; - filelist_file_cache_block_release(filelist, size2, idx2); - } - filelist_file_cache_block_release(filelist, size1, idx1); - - cache->block_cursor = (idx1 + size1 + size2) % cache_size; - cache->block_start_index = start_index; - } - if (end_index < cache->block_end_index) { - int size1 = cache->block_end_index - end_index; - int size2 = 0; - int idx1, idx2 = 0; - -// printf("\tcache releasing: [%d:%d] (%d)\n", -// cache->block_end_index - size1, cache->block_end_index, cache->block_cursor); - - idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size; - if (idx1 + size1 > cache_size) { - size2 = idx1 + size1 - cache_size; - size1 -= size2; - filelist_file_cache_block_release(filelist, size2, idx2); - } - filelist_file_cache_block_release(filelist, size1, idx1); - - cache->block_end_index = end_index; - } - -// printf("\tcache cleaned up...\n"); - - if (start_index < cache->block_start_index) { - /* Add (request) needed entries before already cached ones. */ - /* Note: We need some index black magic to wrap around (cycle) - * inside our cache_size array... */ - int size1 = cache->block_start_index - start_index; - int size2 = 0; - int idx1, idx2; - - if (size1 > cache->block_cursor) { - size2 = size1; - size1 -= cache->block_cursor; - size2 -= size1; - idx2 = 0; - idx1 = cache_size - size1; - } - else { - idx1 = cache->block_cursor - size1; - } - - if (size2) { - if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) { - return false; - } - } - if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) { - return false; - } - - cache->block_cursor = idx1; - cache->block_start_index = start_index; - } -// printf("\tstart-extended...\n"); - if (end_index > cache->block_end_index) { - /* Add (request) needed entries after already cached ones. */ - /* Note: We need some index black magic to wrap around (cycle) - * inside our cache_size array... */ - int size1 = end_index - cache->block_end_index; - int size2 = 0; - int idx1, idx2; - - idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size; - if ((idx1 + size1) > cache_size) { - size2 = size1; - size1 = cache_size - idx1; - size2 -= size1; - idx2 = 0; - } - - if (size2) { - if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) { - return false; - } - } - if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) { - return false; - } - - cache->block_end_index = end_index; - } - -// printf("\tend-extended...\n"); - } - } - else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) { - /* We try to always preview visible entries first, so 'restart' preview background task. */ - filelist_cache_previews_update(filelist); - filelist_cache_previews_clear(cache); - } - -// printf("Re-queueing previews...\n"); - - /* Note we try to preview first images around given index - i.e. assumed visible ones. */ - if (cache->flags & FLC_PREVIEWS_ACTIVE) { - for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) { - if ((index - i) >= start_index) { - const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size; - filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i); - } - if ((index + i) < end_index) { - const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size; - filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i); - } - } - } - - cache->block_center_index = index; - -// printf("%s Finished!\n", __func__); - - return true; + FileListEntryCache *cache = &filelist->filelist_cache; + const size_t cache_size = cache->size; + + const int nbr_entries = filelist->filelist.nbr_entries_filtered; + int start_index = max_ii(0, index - (cache_size / 2)); + int end_index = min_ii(nbr_entries, index + (cache_size / 2)); + int i; + const bool full_refresh = (filelist->flags & FL_IS_READY) == 0; + + if ((index < 0) || (index >= nbr_entries)) { + // printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries); + return false; + } + + /* Maximize cached range! */ + if ((end_index - start_index) < cache_size) { + if (start_index == 0) { + end_index = min_ii(nbr_entries, start_index + cache_size); + } + else if (end_index == nbr_entries) { + start_index = max_ii(0, end_index - cache_size); + } + } + + BLI_assert((end_index - start_index) <= cache_size); + + // printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__, + // start_index, end_index, index, cache->block_start_index, cache->block_end_index); + + /* If we have something to (re)cache... */ + if (full_refresh || (start_index != cache->block_start_index) || + (end_index != cache->block_end_index)) { + if (full_refresh || (start_index >= cache->block_end_index) || + (end_index <= cache->block_start_index)) { + int size1 = cache->block_end_index - cache->block_start_index; + int size2 = 0; + int idx1 = cache->block_cursor, idx2 = 0; + + // printf("Full Recaching!\n"); + + if (cache->flags & FLC_PREVIEWS_ACTIVE) { + filelist_cache_previews_clear(cache); + } + + if (idx1 + size1 > cache_size) { + size2 = idx1 + size1 - cache_size; + size1 -= size2; + filelist_file_cache_block_release(filelist, size2, idx2); + } + filelist_file_cache_block_release(filelist, size1, idx1); + + cache->block_start_index = cache->block_end_index = cache->block_cursor = 0; + + /* New cached block does not overlap existing one, simple. */ + if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) { + return false; + } + + cache->block_start_index = start_index; + cache->block_end_index = end_index; + } + else { + // printf("Partial Recaching!\n"); + + /* At this point, we know we keep part of currently cached entries, so update previews + * if needed, and remove everything from working queue - we'll add all newly needed + * entries at the end. */ + if (cache->flags & FLC_PREVIEWS_ACTIVE) { + filelist_cache_previews_update(filelist); + filelist_cache_previews_clear(cache); + } + + // printf("\tpreview cleaned up...\n"); + + if (start_index > cache->block_start_index) { + int size1 = start_index - cache->block_start_index; + int size2 = 0; + int idx1 = cache->block_cursor, idx2 = 0; + + // printf("\tcache releasing: [%d:%d] (%d, %d)\n", + // cache->block_start_index, cache->block_start_index + size1, + // cache->block_cursor, size1); + + if (idx1 + size1 > cache_size) { + size2 = idx1 + size1 - cache_size; + size1 -= size2; + filelist_file_cache_block_release(filelist, size2, idx2); + } + filelist_file_cache_block_release(filelist, size1, idx1); + + cache->block_cursor = (idx1 + size1 + size2) % cache_size; + cache->block_start_index = start_index; + } + if (end_index < cache->block_end_index) { + int size1 = cache->block_end_index - end_index; + int size2 = 0; + int idx1, idx2 = 0; + + // printf("\tcache releasing: [%d:%d] (%d)\n", + // cache->block_end_index - size1, cache->block_end_index, cache->block_cursor); + + idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size; + if (idx1 + size1 > cache_size) { + size2 = idx1 + size1 - cache_size; + size1 -= size2; + filelist_file_cache_block_release(filelist, size2, idx2); + } + filelist_file_cache_block_release(filelist, size1, idx1); + + cache->block_end_index = end_index; + } + + // printf("\tcache cleaned up...\n"); + + if (start_index < cache->block_start_index) { + /* Add (request) needed entries before already cached ones. */ + /* Note: We need some index black magic to wrap around (cycle) + * inside our cache_size array... */ + int size1 = cache->block_start_index - start_index; + int size2 = 0; + int idx1, idx2; + + if (size1 > cache->block_cursor) { + size2 = size1; + size1 -= cache->block_cursor; + size2 -= size1; + idx2 = 0; + idx1 = cache_size - size1; + } + else { + idx1 = cache->block_cursor - size1; + } + + if (size2) { + if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) { + return false; + } + } + if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) { + return false; + } + + cache->block_cursor = idx1; + cache->block_start_index = start_index; + } + // printf("\tstart-extended...\n"); + if (end_index > cache->block_end_index) { + /* Add (request) needed entries after already cached ones. */ + /* Note: We need some index black magic to wrap around (cycle) + * inside our cache_size array... */ + int size1 = end_index - cache->block_end_index; + int size2 = 0; + int idx1, idx2; + + idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size; + if ((idx1 + size1) > cache_size) { + size2 = size1; + size1 = cache_size - idx1; + size2 -= size1; + idx2 = 0; + } + + if (size2) { + if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) { + return false; + } + } + if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) { + return false; + } + + cache->block_end_index = end_index; + } + + // printf("\tend-extended...\n"); + } + } + else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) { + /* We try to always preview visible entries first, so 'restart' preview background task. */ + filelist_cache_previews_update(filelist); + filelist_cache_previews_clear(cache); + } + + // printf("Re-queueing previews...\n"); + + /* Note we try to preview first images around given index - i.e. assumed visible ones. */ + if (cache->flags & FLC_PREVIEWS_ACTIVE) { + for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) { + if ((index - i) >= start_index) { + const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size; + filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i); + } + if ((index + i) < end_index) { + const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size; + filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i); + } + } + } + + cache->block_center_index = index; + + // printf("%s Finished!\n", __func__); + + return true; } void filelist_cache_previews_set(FileList *filelist, const bool use_previews) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) { - return; - } - /* Do not start preview work while listing, gives nasty flickering! */ - else if (use_previews && (filelist->flags & FL_IS_READY)) { - cache->flags |= FLC_PREVIEWS_ACTIVE; + if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) { + return; + } + /* Do not start preview work while listing, gives nasty flickering! */ + else if (use_previews && (filelist->flags & FL_IS_READY)) { + cache->flags |= FLC_PREVIEWS_ACTIVE; - BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL)); + BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL)); -// printf("%s: Init Previews...\n", __func__); + // printf("%s: Init Previews...\n", __func__); - /* No need to populate preview queue here, filelist_file_cache_block() handles this. */ - } - else { -// printf("%s: Clear Previews...\n", __func__); + /* No need to populate preview queue here, filelist_file_cache_block() handles this. */ + } + else { + // printf("%s: Clear Previews...\n", __func__); - filelist_cache_previews_free(cache); - } + filelist_cache_previews_free(cache); + } } bool filelist_cache_previews_update(FileList *filelist) { - FileListEntryCache *cache = &filelist->filelist_cache; - TaskPool *pool = cache->previews_pool; - bool changed = false; - - if (!pool) { - return changed; - } - -// printf("%s: Update Previews...\n", __func__); - - while (!BLI_thread_queue_is_empty(cache->previews_done)) { - FileListEntryPreview *preview = BLI_thread_queue_pop(cache->previews_done); - FileDirEntry *entry; - - /* Paranoid (should never happen currently - * since we consume this queue from a single thread), but... */ - if (!preview) { - continue; - } - /* entry might have been removed from cache in the mean time, - * we do not want to cache it again here. */ - entry = filelist_file_ex(filelist, preview->index, false); - -// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - - if (preview->img) { - /* Due to asynchronous process, a preview for a given image may be generated several times, i.e. - * entry->image may already be set at this point. */ - if (entry && !entry->image) { - entry->image = preview->img; - changed = true; - } - else { - IMB_freeImBuf(preview->img); - } - } - else if (entry) { - /* We want to avoid re-processing this entry continuously! - * Note that, since entries only live in cache, - * preview will be retried quite often anyway. */ - entry->flags |= FILE_ENTRY_INVALID_PREVIEW; - } - - MEM_freeN(preview); - } - - return changed; + FileListEntryCache *cache = &filelist->filelist_cache; + TaskPool *pool = cache->previews_pool; + bool changed = false; + + if (!pool) { + return changed; + } + + // printf("%s: Update Previews...\n", __func__); + + while (!BLI_thread_queue_is_empty(cache->previews_done)) { + FileListEntryPreview *preview = BLI_thread_queue_pop(cache->previews_done); + FileDirEntry *entry; + + /* Paranoid (should never happen currently + * since we consume this queue from a single thread), but... */ + if (!preview) { + continue; + } + /* entry might have been removed from cache in the mean time, + * we do not want to cache it again here. */ + entry = filelist_file_ex(filelist, preview->index, false); + + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + + if (preview->img) { + /* Due to asynchronous process, a preview for a given image may be generated several times, i.e. + * entry->image may already be set at this point. */ + if (entry && !entry->image) { + entry->image = preview->img; + changed = true; + } + else { + IMB_freeImBuf(preview->img); + } + } + else if (entry) { + /* We want to avoid re-processing this entry continuously! + * Note that, since entries only live in cache, + * preview will be retried quite often anyway. */ + entry->flags |= FILE_ENTRY_INVALID_PREVIEW; + } + + MEM_freeN(preview); + } + + return changed; } bool filelist_cache_previews_running(FileList *filelist) { - FileListEntryCache *cache = &filelist->filelist_cache; + FileListEntryCache *cache = &filelist->filelist_cache; - return (cache->previews_pool != NULL); + return (cache->previews_pool != NULL); } /* would recognize .blend as well */ static bool file_is_blend_backup(const char *str) { - const size_t a = strlen(str); - size_t b = 7; - bool retval = 0; + const size_t a = strlen(str); + size_t b = 7; + bool retval = 0; - if (a == 0 || b >= a) { - /* pass */ - } - else { - const char *loc; + if (a == 0 || b >= a) { + /* pass */ + } + else { + const char *loc; - if (a > b + 1) - b++; + if (a > b + 1) + b++; - /* allow .blend1 .blend2 .blend32 */ - loc = BLI_strcasestr(str + a - b, ".blend"); + /* allow .blend1 .blend2 .blend32 */ + loc = BLI_strcasestr(str + a - b, ".blend"); - if (loc) - retval = 1; - } + if (loc) + retval = 1; + } - return (retval); + return (retval); } /* TODO: Maybe we should move this to BLI? * On the other hand, it's using defines from spacefile area, so not sure... */ int ED_path_extension_type(const char *path) { - if (BLO_has_bfile_extension(path)) { - return FILE_TYPE_BLENDER; - } - else if (file_is_blend_backup(path)) { - return FILE_TYPE_BLENDER_BACKUP; - } - else if (BLI_path_extension_check(path, ".app")) { - return FILE_TYPE_APPLICATIONBUNDLE; - } - else if (BLI_path_extension_check(path, ".py")) { - return FILE_TYPE_PYSCRIPT; - } - else if (BLI_path_extension_check_n(path, ".txt", ".glsl", ".osl", ".data", ".pov", ".ini", ".mcr", ".inc", NULL)) { - return FILE_TYPE_TEXT; - } - else if (BLI_path_extension_check_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) { - return FILE_TYPE_FTFONT; - } - else if (BLI_path_extension_check(path, ".btx")) { - return FILE_TYPE_BTX; - } - else if (BLI_path_extension_check(path, ".dae")) { - return FILE_TYPE_COLLADA; - } - else if (BLI_path_extension_check(path, ".abc")) { - return FILE_TYPE_ALEMBIC; - } - else if (BLI_path_extension_check_array(path, imb_ext_image)) { - return FILE_TYPE_IMAGE; - } - else if (BLI_path_extension_check(path, ".ogg")) { - if (IMB_isanim(path)) { - return FILE_TYPE_MOVIE; - } - else { - return FILE_TYPE_SOUND; - } - } - else if (BLI_path_extension_check_array(path, imb_ext_movie)) { - return FILE_TYPE_MOVIE; - } - else if (BLI_path_extension_check_array(path, imb_ext_audio)) { - return FILE_TYPE_SOUND; - } - return 0; + if (BLO_has_bfile_extension(path)) { + return FILE_TYPE_BLENDER; + } + else if (file_is_blend_backup(path)) { + return FILE_TYPE_BLENDER_BACKUP; + } + else if (BLI_path_extension_check(path, ".app")) { + return FILE_TYPE_APPLICATIONBUNDLE; + } + else if (BLI_path_extension_check(path, ".py")) { + return FILE_TYPE_PYSCRIPT; + } + else if (BLI_path_extension_check_n( + path, ".txt", ".glsl", ".osl", ".data", ".pov", ".ini", ".mcr", ".inc", NULL)) { + return FILE_TYPE_TEXT; + } + else if (BLI_path_extension_check_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) { + return FILE_TYPE_FTFONT; + } + else if (BLI_path_extension_check(path, ".btx")) { + return FILE_TYPE_BTX; + } + else if (BLI_path_extension_check(path, ".dae")) { + return FILE_TYPE_COLLADA; + } + else if (BLI_path_extension_check(path, ".abc")) { + return FILE_TYPE_ALEMBIC; + } + else if (BLI_path_extension_check_array(path, imb_ext_image)) { + return FILE_TYPE_IMAGE; + } + else if (BLI_path_extension_check(path, ".ogg")) { + if (IMB_isanim(path)) { + return FILE_TYPE_MOVIE; + } + else { + return FILE_TYPE_SOUND; + } + } + else if (BLI_path_extension_check_array(path, imb_ext_movie)) { + return FILE_TYPE_MOVIE; + } + else if (BLI_path_extension_check_array(path, imb_ext_audio)) { + return FILE_TYPE_SOUND; + } + return 0; } static int file_extension_type(const char *dir, const char *relpath) { - char path[FILE_MAX]; - BLI_join_dirfile(path, sizeof(path), dir, relpath); - return ED_path_extension_type(path); + char path[FILE_MAX]; + BLI_join_dirfile(path, sizeof(path), dir, relpath); + return ED_path_extension_type(path); } int ED_file_extension_icon(const char *path) { - const int type = ED_path_extension_type(path); - - switch (type) { - case FILE_TYPE_BLENDER: - return ICON_FILE_BLEND; - case FILE_TYPE_BLENDER_BACKUP: - return ICON_FILE_BACKUP; - case FILE_TYPE_IMAGE: - return ICON_FILE_IMAGE; - case FILE_TYPE_MOVIE: - return ICON_FILE_MOVIE; - case FILE_TYPE_PYSCRIPT: - return ICON_FILE_SCRIPT; - case FILE_TYPE_SOUND: - return ICON_FILE_SOUND; - case FILE_TYPE_FTFONT: - return ICON_FILE_FONT; - case FILE_TYPE_BTX: - return ICON_FILE_BLANK; - case FILE_TYPE_COLLADA: - return ICON_FILE_BLANK; - case FILE_TYPE_ALEMBIC: - return ICON_FILE_BLANK; - case FILE_TYPE_TEXT: - return ICON_FILE_TEXT; - default: - return ICON_FILE_BLANK; - } + const int type = ED_path_extension_type(path); + + switch (type) { + case FILE_TYPE_BLENDER: + return ICON_FILE_BLEND; + case FILE_TYPE_BLENDER_BACKUP: + return ICON_FILE_BACKUP; + case FILE_TYPE_IMAGE: + return ICON_FILE_IMAGE; + case FILE_TYPE_MOVIE: + return ICON_FILE_MOVIE; + case FILE_TYPE_PYSCRIPT: + return ICON_FILE_SCRIPT; + case FILE_TYPE_SOUND: + return ICON_FILE_SOUND; + case FILE_TYPE_FTFONT: + return ICON_FILE_FONT; + case FILE_TYPE_BTX: + return ICON_FILE_BLANK; + case FILE_TYPE_COLLADA: + return ICON_FILE_BLANK; + case FILE_TYPE_ALEMBIC: + return ICON_FILE_BLANK; + case FILE_TYPE_TEXT: + return ICON_FILE_TEXT; + default: + return ICON_FILE_BLANK; + } } int filelist_empty(struct FileList *filelist) { - return (filelist->filelist.nbr_entries == 0); -} - -unsigned int filelist_entry_select_set( - const FileList *filelist, const FileDirEntry *entry, FileSelType select, unsigned int flag, FileCheckType check) + return (filelist->filelist.nbr_entries == 0); +} + +unsigned int filelist_entry_select_set(const FileList *filelist, + const FileDirEntry *entry, + FileSelType select, + unsigned int flag, + FileCheckType check) { - /* Default NULL pointer if not found is fine here! */ - void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid); - unsigned int entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0; - const unsigned int org_entry_flag = entry_flag; + /* Default NULL pointer if not found is fine here! */ + void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid); + unsigned int entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0; + const unsigned int org_entry_flag = entry_flag; - BLI_assert(entry); - BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); + BLI_assert(entry); + BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); - if (((check == CHECK_ALL)) || - ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || - ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) - { - switch (select) { - case FILE_SEL_REMOVE: - entry_flag &= ~flag; - break; - case FILE_SEL_ADD: - entry_flag |= flag; - break; - case FILE_SEL_TOGGLE: - entry_flag ^= flag; - break; - } - } + if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || + ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) { + switch (select) { + case FILE_SEL_REMOVE: + entry_flag &= ~flag; + break; + case FILE_SEL_ADD: + entry_flag |= flag; + break; + case FILE_SEL_TOGGLE: + entry_flag ^= flag; + break; + } + } - if (entry_flag != org_entry_flag) { - if (es_p) { - if (entry_flag) { - *es_p = POINTER_FROM_UINT(entry_flag); - } - else { - BLI_ghash_remove(filelist->selection_state, entry->uuid, MEM_freeN, NULL); - } - } - else if (entry_flag) { - void *key = MEM_mallocN(sizeof(entry->uuid), __func__); - memcpy(key, entry->uuid, sizeof(entry->uuid)); - BLI_ghash_insert(filelist->selection_state, key, POINTER_FROM_UINT(entry_flag)); - } - } + if (entry_flag != org_entry_flag) { + if (es_p) { + if (entry_flag) { + *es_p = POINTER_FROM_UINT(entry_flag); + } + else { + BLI_ghash_remove(filelist->selection_state, entry->uuid, MEM_freeN, NULL); + } + } + else if (entry_flag) { + void *key = MEM_mallocN(sizeof(entry->uuid), __func__); + memcpy(key, entry->uuid, sizeof(entry->uuid)); + BLI_ghash_insert(filelist->selection_state, key, POINTER_FROM_UINT(entry_flag)); + } + } - return entry_flag; + return entry_flag; } -void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, unsigned int flag, FileCheckType check) +void filelist_entry_select_index_set(FileList *filelist, + const int index, + FileSelType select, + unsigned int flag, + FileCheckType check) { - FileDirEntry *entry = filelist_file(filelist, index); + FileDirEntry *entry = filelist_file(filelist, index); - if (entry) { - filelist_entry_select_set(filelist, entry, select, flag, check); - } + if (entry) { + filelist_entry_select_set(filelist, entry, select, flag, check); + } } -void filelist_entries_select_index_range_set( - FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check) +void filelist_entries_select_index_range_set(FileList *filelist, + FileSelection *sel, + FileSelType select, + unsigned int flag, + FileCheckType check) { - /* select all valid files between first and last indicated */ - if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) && - (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered)) - { - int current_file; - for (current_file = sel->first; current_file <= sel->last; current_file++) { - filelist_entry_select_index_set(filelist, current_file, select, flag, check); - } - } + /* select all valid files between first and last indicated */ + if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) && + (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered)) { + int current_file; + for (current_file = sel->first; current_file <= sel->last; current_file++) { + filelist_entry_select_index_set(filelist, current_file, select, flag, check); + } + } } -unsigned int filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check) +unsigned int filelist_entry_select_get(FileList *filelist, + FileDirEntry *entry, + FileCheckType check) { - BLI_assert(entry); - BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); + BLI_assert(entry); + BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL)); - if (((check == CHECK_ALL)) || - ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || - ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) - { - /* Default NULL pointer if not found is fine here! */ - return POINTER_AS_UINT(BLI_ghash_lookup(filelist->selection_state, entry->uuid)); - } + if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) || + ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) { + /* Default NULL pointer if not found is fine here! */ + return POINTER_AS_UINT(BLI_ghash_lookup(filelist->selection_state, entry->uuid)); + } - return 0; + return 0; } -unsigned int filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check) +unsigned int filelist_entry_select_index_get(FileList *filelist, + const int index, + FileCheckType check) { - FileDirEntry *entry = filelist_file(filelist, index); - - if (entry) { - return filelist_entry_select_get(filelist, entry, check); - } - - return 0; + FileDirEntry *entry = filelist_file(filelist, index); + + if (entry) { + return filelist_entry_select_get(filelist, entry, check); + } + + return 0; } /* WARNING! dir must be FILE_MAX_LIBEXTRA long! */ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group) { - return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); + return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); } static int groupname_to_code(const char *group) { - char buf[BLO_GROUP_MAX]; - char *lslash; + char buf[BLO_GROUP_MAX]; + char *lslash; - BLI_assert(group); + BLI_assert(group); - BLI_strncpy(buf, group, sizeof(buf)); - lslash = (char *)BLI_last_slash(buf); - if (lslash) - lslash[0] = '\0'; + BLI_strncpy(buf, group, sizeof(buf)); + lslash = (char *)BLI_last_slash(buf); + if (lslash) + lslash[0] = '\0'; - return buf[0] ? BKE_idcode_from_name(buf) : 0; + return buf[0] ? BKE_idcode_from_name(buf) : 0; } static unsigned int groupname_to_filter_id(const char *group) { - int id_code = groupname_to_code(group); + int id_code = groupname_to_code(group); - return BKE_idcode_to_idfilter(id_code); + return BKE_idcode_to_idfilter(id_code); } /** @@ -2201,127 +2279,130 @@ static unsigned int groupname_to_filter_id(const char *group) * and main one (used by UI among other things). */ typedef struct TodoDir { - int level; - char *dir; + int level; + char *dir; } TodoDir; -static int filelist_readjob_list_dir( - const char *root, ListBase *entries, const char *filter_glob, - const bool do_lib, const char *main_name, const bool skip_currpar) -{ - struct direntry *files; - int nbr_files, nbr_entries = 0; - - nbr_files = BLI_filelist_dir_contents(root, &files); - if (files) { - int i = nbr_files; - while (i--) { - FileListInternEntry *entry; - - if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) { - continue; - } - - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = MEM_dupallocN(files[i].relname); - entry->st = files[i].s; - - /* Set file type. */ - if (S_ISDIR(files[i].s.st_mode)) { - entry->typeflag = FILE_TYPE_DIR; - } - else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { - /* If we are considering .blend files as libs, promote them to directory status. */ - char name[FILE_MAX]; - - entry->typeflag = FILE_TYPE_BLENDER; - - BLI_join_dirfile(name, sizeof(name), root, entry->relpath); - - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, name) != 0) { - entry->typeflag |= FILE_TYPE_DIR; - } - } - /* Otherwise, do not check extensions for directories! */ - else if (!(entry->typeflag & FILE_TYPE_DIR)) { - entry->typeflag = file_extension_type(root, entry->relpath); - if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { - entry->typeflag |= FILE_TYPE_OPERATOR; - } - } - - BLI_addtail(entries, entry); - nbr_entries++; - } - BLI_filelist_free(files, nbr_files); - } - return nbr_entries; +static int filelist_readjob_list_dir(const char *root, + ListBase *entries, + const char *filter_glob, + const bool do_lib, + const char *main_name, + const bool skip_currpar) +{ + struct direntry *files; + int nbr_files, nbr_entries = 0; + + nbr_files = BLI_filelist_dir_contents(root, &files); + if (files) { + int i = nbr_files; + while (i--) { + FileListInternEntry *entry; + + if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) { + continue; + } + + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = MEM_dupallocN(files[i].relname); + entry->st = files[i].s; + + /* Set file type. */ + if (S_ISDIR(files[i].s.st_mode)) { + entry->typeflag = FILE_TYPE_DIR; + } + else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { + /* If we are considering .blend files as libs, promote them to directory status. */ + char name[FILE_MAX]; + + entry->typeflag = FILE_TYPE_BLENDER; + + BLI_join_dirfile(name, sizeof(name), root, entry->relpath); + + /* prevent current file being used as acceptable dir */ + if (BLI_path_cmp(main_name, name) != 0) { + entry->typeflag |= FILE_TYPE_DIR; + } + } + /* Otherwise, do not check extensions for directories! */ + else if (!(entry->typeflag & FILE_TYPE_DIR)) { + entry->typeflag = file_extension_type(root, entry->relpath); + if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) { + entry->typeflag |= FILE_TYPE_OPERATOR; + } + } + + BLI_addtail(entries, entry); + nbr_entries++; + } + BLI_filelist_free(files, nbr_files); + } + return nbr_entries; } static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar) { - FileListInternEntry *entry; - LinkNode *ln, *names; - int i, nnames, idcode = 0, nbr_entries = 0; - char dir[FILE_MAX_LIBEXTRA], *group; - bool ok; - - struct BlendHandle *libfiledata = NULL; - - /* name test */ - ok = BLO_library_path_explode(root, dir, &group, NULL); - if (!ok) { - return nbr_entries; - } - - /* there we go */ - libfiledata = BLO_blendhandle_from_file(dir, NULL); - if (libfiledata == NULL) { - return nbr_entries; - } - - /* memory for strings is passed into filelist[i].entry->relpath - * and freed in filelist_entry_free. */ - if (group) { - idcode = groupname_to_code(group); - names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames); - } - else { - names = BLO_blendhandle_get_linkable_groups(libfiledata); - nnames = BLI_linklist_count(names); - } - - BLO_blendhandle_close(libfiledata); - - if (!skip_currpar) { - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = BLI_strdup(FILENAME_PARENT); - entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); - BLI_addtail(entries, entry); - nbr_entries++; - } - - for (i = 0, ln = names; i < nnames; i++, ln = ln->next) { - const char *blockname = ln->link; - - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = BLI_strdup(blockname); - entry->typeflag |= FILE_TYPE_BLENDERLIB; - if (!(group && idcode)) { - entry->typeflag |= FILE_TYPE_DIR; - entry->blentype = groupname_to_code(blockname); - } - else { - entry->blentype = idcode; - } - BLI_addtail(entries, entry); - nbr_entries++; - } - - BLI_linklist_free(names, free); - - return nbr_entries; + FileListInternEntry *entry; + LinkNode *ln, *names; + int i, nnames, idcode = 0, nbr_entries = 0; + char dir[FILE_MAX_LIBEXTRA], *group; + bool ok; + + struct BlendHandle *libfiledata = NULL; + + /* name test */ + ok = BLO_library_path_explode(root, dir, &group, NULL); + if (!ok) { + return nbr_entries; + } + + /* there we go */ + libfiledata = BLO_blendhandle_from_file(dir, NULL); + if (libfiledata == NULL) { + return nbr_entries; + } + + /* memory for strings is passed into filelist[i].entry->relpath + * and freed in filelist_entry_free. */ + if (group) { + idcode = groupname_to_code(group); + names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames); + } + else { + names = BLO_blendhandle_get_linkable_groups(libfiledata); + nnames = BLI_linklist_count(names); + } + + BLO_blendhandle_close(libfiledata); + + if (!skip_currpar) { + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = BLI_strdup(FILENAME_PARENT); + entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); + BLI_addtail(entries, entry); + nbr_entries++; + } + + for (i = 0, ln = names; i < nnames; i++, ln = ln->next) { + const char *blockname = ln->link; + + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = BLI_strdup(blockname); + entry->typeflag |= FILE_TYPE_BLENDERLIB; + if (!(group && idcode)) { + entry->typeflag |= FILE_TYPE_DIR; + entry->blentype = groupname_to_code(blockname); + } + else { + entry->blentype = idcode; + } + BLI_addtail(entries, entry); + nbr_entries++; + } + + BLI_linklist_free(names, free); + + return nbr_entries; } #if 0 @@ -2330,428 +2411,453 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const /* Code ***NOT*** updated for job stuff! */ static void filelist_readjob_main_rec(Main *bmain, FileList *filelist) { - ID *id; - FileDirEntry *files, *firstlib = NULL; - ListBase *lb; - int a, fake, idcode, ok, totlib, totbl; - - // filelist->type = FILE_MAIN; // XXX TODO: add modes to filebrowser - - BLI_assert(filelist->filelist.entries == NULL); - - if (filelist->filelist.root[0] == '/') filelist->filelist.root[0] = '\0'; - - if (filelist->filelist.root[0]) { - idcode = groupname_to_code(filelist->filelist.root); - if (idcode == 0) filelist->filelist.root[0] = '\0'; - } - - if (filelist->dir[0] == 0) { - /* make directories */ -#ifdef WITH_FREESTYLE - filelist->filelist.nbr_entries = 24; -#else - filelist->filelist.nbr_entries = 23; -#endif - filelist_resize(filelist, filelist->filelist.nbr_entries); - - for (a = 0; a < filelist->filelist.nbr_entries; a++) { - filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR; - } - - filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT); - filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene"); - filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object"); - filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh"); - filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve"); - filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball"); - filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material"); - filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture"); - filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image"); - filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika"); - filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave"); - filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice"); - filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light"); - filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera"); - filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo"); - filelist->filelist.entries[15].entry->relpath = BLI_strdup("World"); - filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen"); - filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont"); - filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text"); - filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature"); - filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action"); - filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree"); - filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker"); -#ifdef WITH_FREESTYLE - filelist->filelist.entries[23].entry->relpath = BLI_strdup("FreestyleLineStyle"); -#endif - } - else { - /* make files */ - idcode = groupname_to_code(filelist->filelist.root); - - lb = which_libbase(bmain, idcode); - if (lb == NULL) return; - - filelist->filelist.nbr_entries = 0; - for (id = lb->first; id; id = id->next) { - if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { - filelist->filelist.nbr_entries++; - } - } - - /* XXX TODO: if databrowse F4 or append/link - * filelist->flags & FLF_HIDE_PARENT has to be set */ - if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) - filelist->filelist.nbr_entries++; - - if (filelist->filelist.nbr_entries > 0) { - filelist_resize(filelist, filelist->filelist.nbr_entries); - } - - files = filelist->filelist.entries; - - if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) { - files->entry->relpath = BLI_strdup(FILENAME_PARENT); - files->typeflag |= FILE_TYPE_DIR; - - files++; - } - - totlib = totbl = 0; - for (id = lb->first; id; id = id->next) { - ok = 1; - if (ok) { - if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { - if (id->lib == NULL) { - files->entry->relpath = BLI_strdup(id->name + 2); - } - else { - char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3]; - BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->name, id->name + 2); - files->entry->relpath = BLI_strdup(relname); - } -// files->type |= S_IFREG; -#if 0 /* XXX TODO show the selection status of the objects */ - if (!filelist->has_func) { /* F4 DATA BROWSE */ - if (idcode == ID_OB) { - if ( ((Object *)id)->flag & SELECT) files->entry->selflag |= FILE_SEL_SELECTED; - } - else if (idcode == ID_SCE) { - if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->entry->selflag |= FILE_SEL_SELECTED; - } - } -#endif -// files->entry->nr = totbl + 1; - files->entry->poin = id; - fake = id->flag & LIB_FAKEUSER; - if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) { - files->typeflag |= FILE_TYPE_IMAGE; - } -// if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us); -// else if (id->lib) BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us); -// else if (fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us); -// else BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us); - - if (id->lib) { - if (totlib == 0) firstlib = files; - totlib++; - } - - files++; - } - totbl++; - } - } - - /* only qsort of library blocks */ - if (totlib > 1) { - qsort(firstlib, totlib, sizeof(*files), compare_name); - } - } + ID *id; + FileDirEntry *files, *firstlib = NULL; + ListBase *lb; + int a, fake, idcode, ok, totlib, totbl; + + // filelist->type = FILE_MAIN; // XXX TODO: add modes to filebrowser + + BLI_assert(filelist->filelist.entries == NULL); + + if (filelist->filelist.root[0] == '/') filelist->filelist.root[0] = '\0'; + + if (filelist->filelist.root[0]) { + idcode = groupname_to_code(filelist->filelist.root); + if (idcode == 0) filelist->filelist.root[0] = '\0'; + } + + if (filelist->dir[0] == 0) { + /* make directories */ +# ifdef WITH_FREESTYLE + filelist->filelist.nbr_entries = 24; +# else + filelist->filelist.nbr_entries = 23; +# endif + filelist_resize(filelist, filelist->filelist.nbr_entries); + + for (a = 0; a < filelist->filelist.nbr_entries; a++) { + filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR; + } + + filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT); + filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene"); + filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object"); + filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh"); + filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve"); + filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball"); + filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material"); + filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture"); + filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image"); + filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika"); + filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave"); + filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice"); + filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light"); + filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera"); + filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo"); + filelist->filelist.entries[15].entry->relpath = BLI_strdup("World"); + filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen"); + filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont"); + filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text"); + filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature"); + filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action"); + filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree"); + filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker"); +# ifdef WITH_FREESTYLE + filelist->filelist.entries[23].entry->relpath = BLI_strdup("FreestyleLineStyle"); +# endif + } + else { + /* make files */ + idcode = groupname_to_code(filelist->filelist.root); + + lb = which_libbase(bmain, idcode); + if (lb == NULL) return; + + filelist->filelist.nbr_entries = 0; + for (id = lb->first; id; id = id->next) { + if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { + filelist->filelist.nbr_entries++; + } + } + + /* XXX TODO: if databrowse F4 or append/link + * filelist->flags & FLF_HIDE_PARENT has to be set */ + if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) + filelist->filelist.nbr_entries++; + + if (filelist->filelist.nbr_entries > 0) { + filelist_resize(filelist, filelist->filelist.nbr_entries); + } + + files = filelist->filelist.entries; + + if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) { + files->entry->relpath = BLI_strdup(FILENAME_PARENT); + files->typeflag |= FILE_TYPE_DIR; + + files++; + } + + totlib = totbl = 0; + for (id = lb->first; id; id = id->next) { + ok = 1; + if (ok) { + if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') { + if (id->lib == NULL) { + files->entry->relpath = BLI_strdup(id->name + 2); + } + else { + char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3]; + BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->name, id->name + 2); + files->entry->relpath = BLI_strdup(relname); + } +// files->type |= S_IFREG; +# if 0 /* XXX TODO show the selection status of the objects */ + if (!filelist->has_func) { /* F4 DATA BROWSE */ + if (idcode == ID_OB) { + if ( ((Object *)id)->flag & SELECT) files->entry->selflag |= FILE_SEL_SELECTED; + } + else if (idcode == ID_SCE) { + if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->entry->selflag |= FILE_SEL_SELECTED; + } + } +# endif +// files->entry->nr = totbl + 1; + files->entry->poin = id; + fake = id->flag & LIB_FAKEUSER; + if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) { + files->typeflag |= FILE_TYPE_IMAGE; + } +// if (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us); +// else if (id->lib) BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us); +// else if (fake) BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us); +// else BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us); + + if (id->lib) { + if (totlib == 0) firstlib = files; + totlib++; + } + + files++; + } + totbl++; + } + } + + /* only qsort of library blocks */ + if (totlib > 1) { + qsort(firstlib, totlib, sizeof(*files), compare_name); + } + } } #endif -static void filelist_readjob_do( - const bool do_lib, - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - ListBase entries = {0}; - BLI_Stack *todo_dirs; - TodoDir *td_dir; - char dir[FILE_MAX_LIBEXTRA]; - char filter_glob[FILE_MAXFILE]; - const char *root = filelist->filelist.root; - const int max_recursion = filelist->max_recursion; - int nbr_done_dirs = 0, nbr_todo_dirs = 1; - -// BLI_assert(filelist->filtered == NULL); - BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && (filelist->filelist.nbr_entries == 0)); - - todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); - td_dir = BLI_stack_push_r(todo_dirs); - td_dir->level = 1; - - BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); - BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); - - BLI_cleanup_dir(main_name, dir); - td_dir->dir = BLI_strdup(dir); - - while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { - FileListInternEntry *entry; - int nbr_entries = 0; - bool is_lib = do_lib; - - char *subdir; - char rel_subdir[FILE_MAX_LIBEXTRA]; - int recursion_level; - bool skip_currpar; - - td_dir = BLI_stack_peek(todo_dirs); - subdir = td_dir->dir; - recursion_level = td_dir->level; - skip_currpar = (recursion_level > 1); - - BLI_stack_discard(todo_dirs); - - /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over - * entry->relpath itself (nor any path containing it), since it may actually be a datablock - * name inside .blend file, which can have slashes and backslashes! See T46827. - * Note that in the end, this means we 'cache' valid relative subdir once here, - * this is actually better. */ - BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); - BLI_cleanup_dir(root, rel_subdir); - BLI_path_rel(rel_subdir, root); - - if (do_lib) { - nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar); - } - if (!nbr_entries) { - is_lib = false; - nbr_entries = filelist_readjob_list_dir(subdir, &entries, filter_glob, do_lib, main_name, skip_currpar); - } - - for (entry = entries.first; entry; entry = entry->next) { - BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath); - - /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here, - * things would crash way before we overflow that counter! - * Using an atomic operation to avoid having to lock thread... - * Note that we do not really need this here currently, - * since there is a single listing thread, but better - * remain consistent about threading! */ - *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); - - /* Only thing we change in direntry here, so we need to free it first. */ - MEM_freeN(entry->relpath); - entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' - * added by BLI_path_rel to rel_subdir */ - entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir)); - - /* Here we decide whether current filedirentry is to be listed too, or not. */ - if (max_recursion && (is_lib || (recursion_level <= max_recursion))) { - if (((entry->typeflag & FILE_TYPE_DIR) == 0) || FILENAME_IS_CURRPAR(entry->relpath)) { - /* Skip... */ - } - else if (!is_lib && (recursion_level >= max_recursion) && - ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) - { - /* Do not recurse in real directories in this case, only in .blend libs. */ - } - else { - /* We have a directory we want to list, add it to todo list! */ - BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); - BLI_cleanup_dir(main_name, dir); - td_dir = BLI_stack_push_r(todo_dirs); - td_dir->level = recursion_level + 1; - td_dir->dir = BLI_strdup(dir); - nbr_todo_dirs++; - } - } - } - - if (nbr_entries) { - BLI_mutex_lock(lock); - - *do_update = true; - - BLI_movelisttolist(&filelist->filelist.entries, &entries); - filelist->filelist.nbr_entries += nbr_entries; - - BLI_mutex_unlock(lock); - } - - nbr_done_dirs++; - *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; - MEM_freeN(subdir); - } - - /* If we were interrupted by stop, stack may not be empty and we need to free - * pending dir paths. */ - while (!BLI_stack_is_empty(todo_dirs)) { - td_dir = BLI_stack_peek(todo_dirs); - MEM_freeN(td_dir->dir); - BLI_stack_discard(todo_dirs); - } - BLI_stack_free(todo_dirs); +static void filelist_readjob_do(const bool do_lib, + FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + ListBase entries = {0}; + BLI_Stack *todo_dirs; + TodoDir *td_dir; + char dir[FILE_MAX_LIBEXTRA]; + char filter_glob[FILE_MAXFILE]; + const char *root = filelist->filelist.root; + const int max_recursion = filelist->max_recursion; + int nbr_done_dirs = 0, nbr_todo_dirs = 1; + + // BLI_assert(filelist->filtered == NULL); + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == 0)); + + todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); + td_dir = BLI_stack_push_r(todo_dirs); + td_dir->level = 1; + + BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); + BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); + + BLI_cleanup_dir(main_name, dir); + td_dir->dir = BLI_strdup(dir); + + while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { + FileListInternEntry *entry; + int nbr_entries = 0; + bool is_lib = do_lib; + + char *subdir; + char rel_subdir[FILE_MAX_LIBEXTRA]; + int recursion_level; + bool skip_currpar; + + td_dir = BLI_stack_peek(todo_dirs); + subdir = td_dir->dir; + recursion_level = td_dir->level; + skip_currpar = (recursion_level > 1); + + BLI_stack_discard(todo_dirs); + + /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over + * entry->relpath itself (nor any path containing it), since it may actually be a datablock + * name inside .blend file, which can have slashes and backslashes! See T46827. + * Note that in the end, this means we 'cache' valid relative subdir once here, + * this is actually better. */ + BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); + BLI_cleanup_dir(root, rel_subdir); + BLI_path_rel(rel_subdir, root); + + if (do_lib) { + nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar); + } + if (!nbr_entries) { + is_lib = false; + nbr_entries = filelist_readjob_list_dir( + subdir, &entries, filter_glob, do_lib, main_name, skip_currpar); + } + + for (entry = entries.first; entry; entry = entry->next) { + BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath); + + /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here, + * things would crash way before we overflow that counter! + * Using an atomic operation to avoid having to lock thread... + * Note that we do not really need this here currently, + * since there is a single listing thread, but better + * remain consistent about threading! */ + *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32( + (uint32_t *)filelist->filelist_intern.curr_uuid, 1); + + /* Only thing we change in direntry here, so we need to free it first. */ + MEM_freeN(entry->relpath); + entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' + * added by BLI_path_rel to rel_subdir */ + entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir)); + + /* Here we decide whether current filedirentry is to be listed too, or not. */ + if (max_recursion && (is_lib || (recursion_level <= max_recursion))) { + if (((entry->typeflag & FILE_TYPE_DIR) == 0) || FILENAME_IS_CURRPAR(entry->relpath)) { + /* Skip... */ + } + else if (!is_lib && (recursion_level >= max_recursion) && + ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) { + /* Do not recurse in real directories in this case, only in .blend libs. */ + } + else { + /* We have a directory we want to list, add it to todo list! */ + BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); + BLI_cleanup_dir(main_name, dir); + td_dir = BLI_stack_push_r(todo_dirs); + td_dir->level = recursion_level + 1; + td_dir->dir = BLI_strdup(dir); + nbr_todo_dirs++; + } + } + } + + if (nbr_entries) { + BLI_mutex_lock(lock); + + *do_update = true; + + BLI_movelisttolist(&filelist->filelist.entries, &entries); + filelist->filelist.nbr_entries += nbr_entries; + + BLI_mutex_unlock(lock); + } + + nbr_done_dirs++; + *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; + MEM_freeN(subdir); + } + + /* If we were interrupted by stop, stack may not be empty and we need to free + * pending dir paths. */ + while (!BLI_stack_is_empty(todo_dirs)) { + td_dir = BLI_stack_peek(todo_dirs); + MEM_freeN(td_dir->dir); + BLI_stack_discard(todo_dirs); + } + BLI_stack_free(todo_dirs); +} + +static void filelist_readjob_dir(FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock); +} + +static void filelist_readjob_lib(FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock); +} + +static void filelist_readjob_main(FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock) +{ + /* TODO! */ + filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock); } -static void filelist_readjob_dir( - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock); -} - -static void filelist_readjob_lib( - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock); -} - -static void filelist_readjob_main( - FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock) -{ - /* TODO! */ - filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock); -} - - typedef struct FileListReadJob { - ThreadMutex lock; - char main_name[FILE_MAX]; - struct FileList *filelist; - /** XXX We may use a simpler struct here... just a linked list and root path? */ - struct FileList *tmp_filelist; + ThreadMutex lock; + char main_name[FILE_MAX]; + struct FileList *filelist; + /** XXX We may use a simpler struct here... just a linked list and root path? */ + struct FileList *tmp_filelist; } FileListReadJob; static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = flrjv; -// printf("START filelist reading (%d files, main thread: %d)\n", -// flrj->filelist->filelist.nbr_entries, BLI_thread_is_main()); + // printf("START filelist reading (%d files, main thread: %d)\n", + // flrj->filelist->filelist.nbr_entries, BLI_thread_is_main()); - BLI_mutex_lock(&flrj->lock); + BLI_mutex_lock(&flrj->lock); - BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist); + BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist); - flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); + flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); - BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); - flrj->tmp_filelist->filelist.nbr_entries = 0; + BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); + flrj->tmp_filelist->filelist.nbr_entries = 0; - flrj->tmp_filelist->filelist_intern.filtered = NULL; - BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); - memset(flrj->tmp_filelist->filelist_intern.curr_uuid, 0, sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid)); + flrj->tmp_filelist->filelist_intern.filtered = NULL; + BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); + memset(flrj->tmp_filelist->filelist_intern.curr_uuid, + 0, + sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid)); - flrj->tmp_filelist->libfiledata = NULL; - memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); - flrj->tmp_filelist->selection_state = NULL; + flrj->tmp_filelist->libfiledata = NULL; + memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); + flrj->tmp_filelist->selection_state = NULL; - BLI_mutex_unlock(&flrj->lock); + BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf(flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock); + flrj->tmp_filelist->read_jobf( + flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock); } static void filelist_readjob_update(void *flrjv) { - FileListReadJob *flrj = flrjv; - FileListIntern *fl_intern = &flrj->filelist->filelist_intern; - ListBase new_entries = {NULL}; - int nbr_entries, new_nbr_entries = 0; + FileListReadJob *flrj = flrjv; + FileListIntern *fl_intern = &flrj->filelist->filelist_intern; + ListBase new_entries = {NULL}; + int nbr_entries, new_nbr_entries = 0; - BLI_movelisttolist(&new_entries, &fl_intern->entries); - nbr_entries = flrj->filelist->filelist.nbr_entries; + BLI_movelisttolist(&new_entries, &fl_intern->entries); + nbr_entries = flrj->filelist->filelist.nbr_entries; - BLI_mutex_lock(&flrj->lock); + BLI_mutex_lock(&flrj->lock); - if (flrj->tmp_filelist->filelist.nbr_entries) { - /* We just move everything out of 'thread context' into final list. */ - new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries; - BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries); - flrj->tmp_filelist->filelist.nbr_entries = 0; - } + if (flrj->tmp_filelist->filelist.nbr_entries) { + /* We just move everything out of 'thread context' into final list. */ + new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries; + BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries); + flrj->tmp_filelist->filelist.nbr_entries = 0; + } - BLI_mutex_unlock(&flrj->lock); + BLI_mutex_unlock(&flrj->lock); - if (new_nbr_entries) { - /* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */ - filelist_clear_ex(flrj->filelist, true, false); + if (new_nbr_entries) { + /* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */ + filelist_clear_ex(flrj->filelist, true, false); - flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING); - } + flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING); + } - /* if no new_nbr_entries, this is NOP */ - BLI_movelisttolist(&fl_intern->entries, &new_entries); - flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries; + /* if no new_nbr_entries, this is NOP */ + BLI_movelisttolist(&fl_intern->entries, &new_entries); + flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries; } static void filelist_readjob_endjob(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = flrjv; - /* In case there would be some dangling update... */ - filelist_readjob_update(flrjv); + /* In case there would be some dangling update... */ + filelist_readjob_update(flrjv); - flrj->filelist->flags &= ~FL_IS_PENDING; - flrj->filelist->flags |= FL_IS_READY; + flrj->filelist->flags &= ~FL_IS_PENDING; + flrj->filelist->flags |= FL_IS_READY; } static void filelist_readjob_free(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = flrjv; -// printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries); + // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries); - if (flrj->tmp_filelist) { - /* tmp_filelist shall never ever be filtered! */ - BLI_assert(flrj->tmp_filelist->filelist.nbr_entries == 0); - BLI_assert(BLI_listbase_is_empty(&flrj->tmp_filelist->filelist.entries)); + if (flrj->tmp_filelist) { + /* tmp_filelist shall never ever be filtered! */ + BLI_assert(flrj->tmp_filelist->filelist.nbr_entries == 0); + BLI_assert(BLI_listbase_is_empty(&flrj->tmp_filelist->filelist.entries)); - filelist_freelib(flrj->tmp_filelist); - filelist_free(flrj->tmp_filelist); - MEM_freeN(flrj->tmp_filelist); - } + filelist_freelib(flrj->tmp_filelist); + filelist_free(flrj->tmp_filelist); + MEM_freeN(flrj->tmp_filelist); + } - BLI_mutex_end(&flrj->lock); + BLI_mutex_end(&flrj->lock); - MEM_freeN(flrj); + MEM_freeN(flrj); } void filelist_readjob_start(FileList *filelist, const bContext *C) { - Main *bmain = CTX_data_main(C); - wmJob *wm_job; - FileListReadJob *flrj; + Main *bmain = CTX_data_main(C); + wmJob *wm_job; + FileListReadJob *flrj; - /* prepare job data */ - flrj = MEM_callocN(sizeof(*flrj), __func__); - flrj->filelist = filelist; - BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); + /* prepare job data */ + flrj = MEM_callocN(sizeof(*flrj), __func__); + flrj->filelist = filelist; + BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); - filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); - filelist->flags |= FL_IS_PENDING; + filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); + filelist->flags |= FL_IS_PENDING; - BLI_mutex_init(&flrj->lock); + BLI_mutex_init(&flrj->lock); - /* setup job */ - wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Listing Dirs...", - WM_JOB_PROGRESS, WM_JOB_TYPE_FILESEL_READDIR); - WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); - WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); - WM_jobs_callbacks(wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); + /* setup job */ + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + CTX_wm_area(C), + "Listing Dirs...", + WM_JOB_PROGRESS, + WM_JOB_TYPE_FILESEL_READDIR); + WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); + WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_callbacks( + wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); - /* start the job */ - WM_jobs_start(CTX_wm_manager(C), wm_job); + /* start the job */ + WM_jobs_start(CTX_wm_manager(C), wm_job); } void filelist_readjob_stop(wmWindowManager *wm, ScrArea *sa) { - WM_jobs_kill_type(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); + WM_jobs_kill_type(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); } int filelist_readjob_running(wmWindowManager *wm, ScrArea *sa) { - return WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); + return WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR); } diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 0cfef16c00d..caf77246797 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -21,7 +21,6 @@ * \ingroup spfile */ - #ifndef __FILELIST_H__ #define __FILELIST_H__ @@ -37,82 +36,101 @@ struct wmWindowManager; struct FileDirEntry; typedef enum FileSelType { - FILE_SEL_REMOVE = 0, - FILE_SEL_ADD = 1, - FILE_SEL_TOGGLE = 2, + FILE_SEL_REMOVE = 0, + FILE_SEL_ADD = 1, + FILE_SEL_TOGGLE = 2, } FileSelType; typedef enum FileCheckType { - CHECK_DIRS = 1, - CHECK_FILES = 2, - CHECK_ALL = 3, + CHECK_DIRS = 1, + CHECK_FILES = 2, + CHECK_ALL = 3, } FileCheckType; -struct ListBase *folderlist_new(void); -void folderlist_free(struct ListBase *folderlist); -struct ListBase *folderlist_duplicate(ListBase *folderlist); -void folderlist_popdir(struct ListBase *folderlist, char *dir); -void folderlist_pushdir(struct ListBase *folderlist, const char *dir); -const char *folderlist_peeklastdir(struct ListBase *folderdist); -int folderlist_clear_next(struct SpaceFile *sfile); - - -void filelist_setsorting(struct FileList *filelist, const short sort); -void filelist_sort(struct FileList *filelist); - -void filelist_setfilter_options(struct FileList *filelist, const bool do_filter, - const bool hide_dot, const bool hide_parent, - const unsigned int filter, const unsigned int filter_id, - const char *filter_glob, const char *filter_search); -void filelist_filter(struct FileList *filelist); - -void filelist_init_icons(void); -void filelist_free_icons(void); -void filelist_imgsize(struct FileList *filelist, short w, short h); -struct ImBuf *filelist_getimage(struct FileList *filelist, const int index); -struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index); -int filelist_geticon(struct FileList *filelist, const int index, const bool is_main); - -struct FileList *filelist_new(short type); -void filelist_clear(struct FileList *filelist); -void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection); -void filelist_free(struct FileList *filelist); - -const char *filelist_dir(struct FileList *filelist); -bool filelist_is_dir(struct FileList *filelist, const char *path); -void filelist_setdir(struct FileList *filelist, char *r_dir); - -int filelist_files_ensure(struct FileList *filelist); -int filelist_empty(struct FileList *filelist); -FileDirEntry *filelist_file(struct FileList *filelist, int index); -int filelist_file_findpath(struct FileList *filelist, const char *file); -FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); -void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size); -bool filelist_file_cache_block(struct FileList *filelist, const int index); - -bool filelist_force_reset(struct FileList *filelist); -bool filelist_pending(struct FileList *filelist); -bool filelist_is_ready(struct FileList *filelist); - -unsigned int filelist_entry_select_set(const struct FileList *filelist, const struct FileDirEntry *entry, FileSelType select, unsigned int flag, FileCheckType check); -void filelist_entry_select_index_set(struct FileList *filelist, const int index, FileSelType select, unsigned int flag, FileCheckType check); -void filelist_entries_select_index_range_set(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check); -unsigned int filelist_entry_select_get(struct FileList *filelist, struct FileDirEntry *entry, FileCheckType check); -unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check); - -void filelist_setrecursion(struct FileList *filelist, const int recursion_level); +struct ListBase *folderlist_new(void); +void folderlist_free(struct ListBase *folderlist); +struct ListBase *folderlist_duplicate(ListBase *folderlist); +void folderlist_popdir(struct ListBase *folderlist, char *dir); +void folderlist_pushdir(struct ListBase *folderlist, const char *dir); +const char *folderlist_peeklastdir(struct ListBase *folderdist); +int folderlist_clear_next(struct SpaceFile *sfile); + +void filelist_setsorting(struct FileList *filelist, const short sort); +void filelist_sort(struct FileList *filelist); + +void filelist_setfilter_options(struct FileList *filelist, + const bool do_filter, + const bool hide_dot, + const bool hide_parent, + const unsigned int filter, + const unsigned int filter_id, + const char *filter_glob, + const char *filter_search); +void filelist_filter(struct FileList *filelist); + +void filelist_init_icons(void); +void filelist_free_icons(void); +void filelist_imgsize(struct FileList *filelist, short w, short h); +struct ImBuf *filelist_getimage(struct FileList *filelist, const int index); +struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index); +int filelist_geticon(struct FileList *filelist, const int index, const bool is_main); + +struct FileList *filelist_new(short type); +void filelist_clear(struct FileList *filelist); +void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection); +void filelist_free(struct FileList *filelist); + +const char *filelist_dir(struct FileList *filelist); +bool filelist_is_dir(struct FileList *filelist, const char *path); +void filelist_setdir(struct FileList *filelist, char *r_dir); + +int filelist_files_ensure(struct FileList *filelist); +int filelist_empty(struct FileList *filelist); +FileDirEntry *filelist_file(struct FileList *filelist, int index); +int filelist_file_findpath(struct FileList *filelist, const char *file); +FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); +void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size); +bool filelist_file_cache_block(struct FileList *filelist, const int index); + +bool filelist_force_reset(struct FileList *filelist); +bool filelist_pending(struct FileList *filelist); +bool filelist_is_ready(struct FileList *filelist); + +unsigned int filelist_entry_select_set(const struct FileList *filelist, + const struct FileDirEntry *entry, + FileSelType select, + unsigned int flag, + FileCheckType check); +void filelist_entry_select_index_set(struct FileList *filelist, + const int index, + FileSelType select, + unsigned int flag, + FileCheckType check); +void filelist_entries_select_index_range_set(struct FileList *filelist, + FileSelection *sel, + FileSelType select, + unsigned int flag, + FileCheckType check); +unsigned int filelist_entry_select_get(struct FileList *filelist, + struct FileDirEntry *entry, + FileCheckType check); +unsigned int filelist_entry_select_index_get(struct FileList *filelist, + const int index, + FileCheckType check); + +void filelist_setrecursion(struct FileList *filelist, const int recursion_level); struct BlendHandle *filelist_lib(struct FileList *filelist); -bool filelist_islibrary(struct FileList *filelist, char *dir, char **group); -void filelist_freelib(struct FileList *filelist); +bool filelist_islibrary(struct FileList *filelist, char *dir, char **group); +void filelist_freelib(struct FileList *filelist); -void filelist_readjob_start(struct FileList *filelist, const struct bContext *C); -void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa); -int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa); +void filelist_readjob_start(struct FileList *filelist, const struct bContext *C); +void filelist_readjob_stop(struct wmWindowManager *wm, struct ScrArea *sa); +int filelist_readjob_running(struct wmWindowManager *wm, struct ScrArea *sa); -bool filelist_cache_previews_update(struct FileList *filelist); -void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews); -bool filelist_cache_previews_running(struct FileList *filelist); +bool filelist_cache_previews_update(struct FileList *filelist); +void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews); +bool filelist_cache_previews_running(struct FileList *filelist); #ifdef __cplusplus } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 3ab08b5ac71..24689d52110 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -21,7 +21,6 @@ * \ingroup spfile */ - #include <string.h> #include <stdio.h> #include <math.h> @@ -72,10 +71,10 @@ FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) { - if (!sfile->params) { - ED_fileselect_set_params(sfile); - } - return sfile->params; + if (!sfile->params) { + ED_fileselect_set_params(sfile); + } + return sfile->params; } /** @@ -83,237 +82,245 @@ FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) * the previously used settings to be used here rather then overriding them */ short ED_fileselect_set_params(SpaceFile *sfile) { - FileSelectParams *params; - wmOperator *op = sfile->op; - - const char *blendfile_path = BKE_main_blendfile_path_from_global(); - - /* create new parameters if necessary */ - if (!sfile->params) { - sfile->params = MEM_callocN(sizeof(FileSelectParams), "fileselparams"); - /* set path to most recently opened .blend */ - BLI_split_dirfile(blendfile_path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); - sfile->params->filter_glob[0] = '\0'; - /* set the default thumbnails size */ - sfile->params->thumbnail_size = 128; - } - - params = sfile->params; - - /* set the parameters from the operator, if it exists */ - if (op) { - PropertyRNA *prop; - const bool is_files = (RNA_struct_find_property(op->ptr, "files") != NULL); - const bool is_filepath = (RNA_struct_find_property(op->ptr, "filepath") != NULL); - const bool is_filename = (RNA_struct_find_property(op->ptr, "filename") != NULL); - const bool is_directory = (RNA_struct_find_property(op->ptr, "directory") != NULL); - const bool is_relative_path = (RNA_struct_find_property(op->ptr, "relative_path") != NULL); - - BLI_strncpy_utf8(params->title, RNA_struct_ui_name(op->type->srna), sizeof(params->title)); - - if ((prop = RNA_struct_find_property(op->ptr, "filemode"))) { - params->type = RNA_property_int_get(op->ptr, prop); - } - else { - params->type = FILE_SPECIAL; - } - - if (is_filepath && RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { - char name[FILE_MAX]; - RNA_string_get(op->ptr, "filepath", name); - if (params->type == FILE_LOADLIB) { - BLI_strncpy(params->dir, name, sizeof(params->dir)); - sfile->params->file[0] = '\0'; - } - else { - BLI_split_dirfile(name, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); - } - } - else { - if (is_directory && RNA_struct_property_is_set_ex(op->ptr, "directory", false)) { - RNA_string_get(op->ptr, "directory", params->dir); - sfile->params->file[0] = '\0'; - } - - if (is_filename && RNA_struct_property_is_set_ex(op->ptr, "filename", false)) { - RNA_string_get(op->ptr, "filename", params->file); - } - } - - if (params->dir[0]) { - BLI_cleanup_dir(blendfile_path, params->dir); - BLI_path_abs(params->dir, blendfile_path); - } - - if (is_directory == true && is_filename == false && is_filepath == false && is_files == false) { - params->flag |= FILE_DIRSEL_ONLY; - } - else { - params->flag &= ~FILE_DIRSEL_ONLY; - } - - params->filter = 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_blenlib"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDERLIB : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_backup"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER_BACKUP : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_image"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_IMAGE : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_movie"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_MOVIE : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_python"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_PYSCRIPT : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_font"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FTFONT : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_sound"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_SOUND : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) - params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0; - if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) { - /* Protection against pyscripts not setting proper size limit... */ - char *tmp = RNA_property_string_get_alloc( - op->ptr, prop, params->filter_glob, sizeof(params->filter_glob), NULL); - if (tmp != params->filter_glob) { - BLI_strncpy(params->filter_glob, tmp, sizeof(params->filter_glob)); - MEM_freeN(tmp); - - /* Fix stupid things that truncating might have generated, - * like last group being a 'match everything' wildcard-only one... */ - BLI_path_extension_glob_validate(params->filter_glob); - } - params->filter |= (FILE_TYPE_OPERATOR | FILE_TYPE_FOLDER); - } - else { - params->filter_glob[0] = '\0'; - } - - if (params->filter != 0) { - if (U.uiflag & USER_FILTERFILEEXTS) { - params->flag |= FILE_FILTER; - } - else { - params->flag &= ~FILE_FILTER; - } - } - - /* For now, always init filterid to 'all true' */ - params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD | - FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | FILTER_ID_MA | - FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | - FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | - FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | - FILTER_ID_LP; - - if (U.uiflag & USER_HIDE_DOT) { - params->flag |= FILE_HIDE_DOT; - } - else { - params->flag &= ~FILE_HIDE_DOT; - } - - - if (params->type == FILE_LOADLIB) { - params->flag |= RNA_boolean_get(op->ptr, "link") ? FILE_LINK : 0; - params->flag |= RNA_boolean_get(op->ptr, "autoselect") ? FILE_AUTOSELECT : 0; - params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0; - } - - if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) { - params->display = RNA_property_enum_get(op->ptr, prop); - } - - if ((prop = RNA_struct_find_property(op->ptr, "sort_method"))) { - params->sort = RNA_property_enum_get(op->ptr, prop); - } - else { - params->sort = FILE_SORT_ALPHA; - } - - if (params->display == FILE_DEFAULTDISPLAY) { - if(params->display_previous == FILE_DEFAULTDISPLAY){ - if (U.uiflag & USER_SHOW_THUMBNAILS) { - if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) { - params->display = FILE_IMGDISPLAY; - } - else { - params->display = FILE_SHORTDISPLAY; - } - } - else { - params->display = FILE_SHORTDISPLAY; - } - } - else { - params->display = params->display_previous; - } - } - - if (is_relative_path) { - if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { - if (!RNA_property_is_set_ex(op->ptr, prop, false)) { - RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_RELPATHS) != 0); - } - } - } - } - else { - /* default values, if no operator */ - params->type = FILE_UNIX; - params->flag |= FILE_HIDE_DOT; - params->flag &= ~FILE_DIRSEL_ONLY; - params->display = FILE_SHORTDISPLAY; - params->display_previous = FILE_DEFAULTDISPLAY; - params->sort = FILE_SORT_ALPHA; - params->filter = 0; - params->filter_glob[0] = '\0'; - } - - /* operator has no setting for this */ - params->active_file = -1; - - - /* initialize the list with previous folders */ - if (!sfile->folders_prev) - sfile->folders_prev = folderlist_new(); - - if (!sfile->params->dir[0]) { - if (blendfile_path[0] != '\0') { - BLI_split_dir_part(blendfile_path, sfile->params->dir, sizeof(sfile->params->dir)); - } - else { - const char *doc_path = BKE_appdir_folder_default(); - if (doc_path) { - BLI_strncpy(sfile->params->dir, doc_path, sizeof(sfile->params->dir)); - } - } - } - - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - - /* switching thumbnails needs to recalc layout [#28809] */ - if (sfile->layout) { - sfile->layout->dirty = true; - } - - return 1; + FileSelectParams *params; + wmOperator *op = sfile->op; + + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + + /* create new parameters if necessary */ + if (!sfile->params) { + sfile->params = MEM_callocN(sizeof(FileSelectParams), "fileselparams"); + /* set path to most recently opened .blend */ + BLI_split_dirfile(blendfile_path, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + sfile->params->filter_glob[0] = '\0'; + /* set the default thumbnails size */ + sfile->params->thumbnail_size = 128; + } + + params = sfile->params; + + /* set the parameters from the operator, if it exists */ + if (op) { + PropertyRNA *prop; + const bool is_files = (RNA_struct_find_property(op->ptr, "files") != NULL); + const bool is_filepath = (RNA_struct_find_property(op->ptr, "filepath") != NULL); + const bool is_filename = (RNA_struct_find_property(op->ptr, "filename") != NULL); + const bool is_directory = (RNA_struct_find_property(op->ptr, "directory") != NULL); + const bool is_relative_path = (RNA_struct_find_property(op->ptr, "relative_path") != NULL); + + BLI_strncpy_utf8(params->title, RNA_struct_ui_name(op->type->srna), sizeof(params->title)); + + if ((prop = RNA_struct_find_property(op->ptr, "filemode"))) { + params->type = RNA_property_int_get(op->ptr, prop); + } + else { + params->type = FILE_SPECIAL; + } + + if (is_filepath && RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { + char name[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", name); + if (params->type == FILE_LOADLIB) { + BLI_strncpy(params->dir, name, sizeof(params->dir)); + sfile->params->file[0] = '\0'; + } + else { + BLI_split_dirfile(name, + sfile->params->dir, + sfile->params->file, + sizeof(sfile->params->dir), + sizeof(sfile->params->file)); + } + } + else { + if (is_directory && RNA_struct_property_is_set_ex(op->ptr, "directory", false)) { + RNA_string_get(op->ptr, "directory", params->dir); + sfile->params->file[0] = '\0'; + } + + if (is_filename && RNA_struct_property_is_set_ex(op->ptr, "filename", false)) { + RNA_string_get(op->ptr, "filename", params->file); + } + } + + if (params->dir[0]) { + BLI_cleanup_dir(blendfile_path, params->dir); + BLI_path_abs(params->dir, blendfile_path); + } + + if (is_directory == true && is_filename == false && is_filepath == false && + is_files == false) { + params->flag |= FILE_DIRSEL_ONLY; + } + else { + params->flag &= ~FILE_DIRSEL_ONLY; + } + + params->filter = 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_blenlib"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDERLIB : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_backup"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER_BACKUP : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_image"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_IMAGE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_movie"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_MOVIE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_python"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_PYSCRIPT : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_font"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FTFONT : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_sound"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_SOUND : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_TEXT : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_FOLDER : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BTX : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_alembic"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_ALEMBIC : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) { + /* Protection against pyscripts not setting proper size limit... */ + char *tmp = RNA_property_string_get_alloc( + op->ptr, prop, params->filter_glob, sizeof(params->filter_glob), NULL); + if (tmp != params->filter_glob) { + BLI_strncpy(params->filter_glob, tmp, sizeof(params->filter_glob)); + MEM_freeN(tmp); + + /* Fix stupid things that truncating might have generated, + * like last group being a 'match everything' wildcard-only one... */ + BLI_path_extension_glob_validate(params->filter_glob); + } + params->filter |= (FILE_TYPE_OPERATOR | FILE_TYPE_FOLDER); + } + else { + params->filter_glob[0] = '\0'; + } + + if (params->filter != 0) { + if (U.uiflag & USER_FILTERFILEEXTS) { + params->flag |= FILE_FILTER; + } + else { + params->flag &= ~FILE_FILTER; + } + } + + /* For now, always init filterid to 'all true' */ + params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | + FILTER_ID_GD | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | + FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | + FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | + FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | + FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | + FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP; + + if (U.uiflag & USER_HIDE_DOT) { + params->flag |= FILE_HIDE_DOT; + } + else { + params->flag &= ~FILE_HIDE_DOT; + } + + if (params->type == FILE_LOADLIB) { + params->flag |= RNA_boolean_get(op->ptr, "link") ? FILE_LINK : 0; + params->flag |= RNA_boolean_get(op->ptr, "autoselect") ? FILE_AUTOSELECT : 0; + params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0; + } + + if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) { + params->display = RNA_property_enum_get(op->ptr, prop); + } + + if ((prop = RNA_struct_find_property(op->ptr, "sort_method"))) { + params->sort = RNA_property_enum_get(op->ptr, prop); + } + else { + params->sort = FILE_SORT_ALPHA; + } + + if (params->display == FILE_DEFAULTDISPLAY) { + if (params->display_previous == FILE_DEFAULTDISPLAY) { + if (U.uiflag & USER_SHOW_THUMBNAILS) { + if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) { + params->display = FILE_IMGDISPLAY; + } + else { + params->display = FILE_SHORTDISPLAY; + } + } + else { + params->display = FILE_SHORTDISPLAY; + } + } + else { + params->display = params->display_previous; + } + } + + if (is_relative_path) { + if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { + if (!RNA_property_is_set_ex(op->ptr, prop, false)) { + RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_RELPATHS) != 0); + } + } + } + } + else { + /* default values, if no operator */ + params->type = FILE_UNIX; + params->flag |= FILE_HIDE_DOT; + params->flag &= ~FILE_DIRSEL_ONLY; + params->display = FILE_SHORTDISPLAY; + params->display_previous = FILE_DEFAULTDISPLAY; + params->sort = FILE_SORT_ALPHA; + params->filter = 0; + params->filter_glob[0] = '\0'; + } + + /* operator has no setting for this */ + params->active_file = -1; + + /* initialize the list with previous folders */ + if (!sfile->folders_prev) + sfile->folders_prev = folderlist_new(); + + if (!sfile->params->dir[0]) { + if (blendfile_path[0] != '\0') { + BLI_split_dir_part(blendfile_path, sfile->params->dir, sizeof(sfile->params->dir)); + } + else { + const char *doc_path = BKE_appdir_folder_default(); + if (doc_path) { + BLI_strncpy(sfile->params->dir, doc_path, sizeof(sfile->params->dir)); + } + } + } + + folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + + /* switching thumbnails needs to recalc layout [#28809] */ + if (sfile->layout) { + sfile->layout->dirty = true; + } + + return 1; } void ED_fileselect_reset_params(SpaceFile *sfile) { - sfile->params->type = FILE_UNIX; - sfile->params->flag = 0; - sfile->params->title[0] = '\0'; - sfile->params->active_file = -1; + sfile->params->type = FILE_UNIX; + sfile->params->flag = 0; + sfile->params->title[0] = '\0'; + sfile->params->active_file = -1; } /** @@ -321,458 +328,467 @@ void ED_fileselect_reset_params(SpaceFile *sfile) */ void fileselect_file_set(SpaceFile *sfile, const int index) { - const struct FileDirEntry *file = filelist_file(sfile->files, index); - if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) { - BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE); - } + const struct FileDirEntry *file = filelist_file(sfile->files, index); + if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) { + BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE); + } } int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar) { - int numfiles; - - /* Values in pixels. - * - * - *_item: size of each (row|col), (including padding) - * - *_view: (x|y) size of the view. - * - *_over: extra pixels, to take into account, when the fit isnt exact - * (needed since you may see the end of the previous column and the beginning of the next). - * - * Could be more clever and take scrolling into account, - * but for now don't bother. - */ - if (layout->flag & FILE_LAYOUT_HOR) { - const int x_item = layout->tile_w + (2 * layout->tile_border_x); - const int x_view = (int)(BLI_rctf_size_x(&ar->v2d.cur)); - const int x_over = x_item - (x_view % x_item); - numfiles = (int)((float)(x_view + x_over) / (float)(x_item)); - return numfiles * layout->rows; - } - else { - const int y_item = layout->tile_h + (2 * layout->tile_border_y); - const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)); - const int y_over = y_item - (y_view % y_item); - numfiles = (int)((float)(y_view + y_over) / (float)(y_item)); - return numfiles * layout->columns; - } + int numfiles; + + /* Values in pixels. + * + * - *_item: size of each (row|col), (including padding) + * - *_view: (x|y) size of the view. + * - *_over: extra pixels, to take into account, when the fit isnt exact + * (needed since you may see the end of the previous column and the beginning of the next). + * + * Could be more clever and take scrolling into account, + * but for now don't bother. + */ + if (layout->flag & FILE_LAYOUT_HOR) { + const int x_item = layout->tile_w + (2 * layout->tile_border_x); + const int x_view = (int)(BLI_rctf_size_x(&ar->v2d.cur)); + const int x_over = x_item - (x_view % x_item); + numfiles = (int)((float)(x_view + x_over) / (float)(x_item)); + return numfiles * layout->rows; + } + else { + const int y_item = layout->tile_h + (2 * layout->tile_border_y); + const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)); + const int y_over = y_item - (y_view % y_item); + numfiles = (int)((float)(y_view + y_over) / (float)(y_item)); + return numfiles * layout->columns; + } } static bool is_inside(int x, int y, int cols, int rows) { - return ((x >= 0) && (x < cols) && (y >= 0) && (y < rows)); + return ((x >= 0) && (x < cols) && (y >= 0) && (y < rows)); } FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *rect) { - int colmin, colmax, rowmin, rowmax; - FileSelection sel; - sel.first = sel.last = -1; - - if (layout == NULL) - return sel; - - colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x); - rowmin = (rect->ymin) / (layout->tile_h + 2 * layout->tile_border_y); - colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x); - rowmax = (rect->ymax) / (layout->tile_h + 2 * layout->tile_border_y); - - if (is_inside(colmin, rowmin, layout->columns, layout->rows) || - is_inside(colmax, rowmax, layout->columns, layout->rows) ) - { - CLAMP(colmin, 0, layout->columns - 1); - CLAMP(rowmin, 0, layout->rows - 1); - CLAMP(colmax, 0, layout->columns - 1); - CLAMP(rowmax, 0, layout->rows - 1); - } - - if ((colmin > layout->columns - 1) || (rowmin > layout->rows - 1)) { - sel.first = -1; - } - else { - if (layout->flag & FILE_LAYOUT_HOR) - sel.first = layout->rows * colmin + rowmin; - else - sel.first = colmin + layout->columns * rowmin; - } - if ((colmax > layout->columns - 1) || (rowmax > layout->rows - 1)) { - sel.last = -1; - } - else { - if (layout->flag & FILE_LAYOUT_HOR) - sel.last = layout->rows * colmax + rowmax; - else - sel.last = colmax + layout->columns * rowmax; - } - - return sel; + int colmin, colmax, rowmin, rowmax; + FileSelection sel; + sel.first = sel.last = -1; + + if (layout == NULL) + return sel; + + colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x); + rowmin = (rect->ymin) / (layout->tile_h + 2 * layout->tile_border_y); + colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x); + rowmax = (rect->ymax) / (layout->tile_h + 2 * layout->tile_border_y); + + if (is_inside(colmin, rowmin, layout->columns, layout->rows) || + is_inside(colmax, rowmax, layout->columns, layout->rows)) { + CLAMP(colmin, 0, layout->columns - 1); + CLAMP(rowmin, 0, layout->rows - 1); + CLAMP(colmax, 0, layout->columns - 1); + CLAMP(rowmax, 0, layout->rows - 1); + } + + if ((colmin > layout->columns - 1) || (rowmin > layout->rows - 1)) { + sel.first = -1; + } + else { + if (layout->flag & FILE_LAYOUT_HOR) + sel.first = layout->rows * colmin + rowmin; + else + sel.first = colmin + layout->columns * rowmin; + } + if ((colmax > layout->columns - 1) || (rowmax > layout->rows - 1)) { + sel.last = -1; + } + else { + if (layout->flag & FILE_LAYOUT_HOR) + sel.last = layout->rows * colmax + rowmax; + else + sel.last = colmax + layout->columns * rowmax; + } + + return sel; } int ED_fileselect_layout_offset(FileLayout *layout, int x, int y) { - int offsetx, offsety; - int active_file; + int offsetx, offsety; + int active_file; - if (layout == NULL) - return -1; + if (layout == NULL) + return -1; - offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x); - offsety = (y) / (layout->tile_h + 2 * layout->tile_border_y); + offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x); + offsety = (y) / (layout->tile_h + 2 * layout->tile_border_y); - if (offsetx > layout->columns - 1) return -1; - if (offsety > layout->rows - 1) return -1; + if (offsetx > layout->columns - 1) + return -1; + if (offsety > layout->rows - 1) + return -1; - if (layout->flag & FILE_LAYOUT_HOR) - active_file = layout->rows * offsetx + offsety; - else - active_file = offsetx + layout->columns * offsety; - return active_file; + if (layout->flag & FILE_LAYOUT_HOR) + active_file = layout->rows * offsetx + offsety; + else + active_file = offsetx + layout->columns * offsety; + return active_file; } void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y) { - if (layout->flag == FILE_LAYOUT_HOR) { - *x = layout->tile_border_x + (tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x); - *y = layout->tile_border_y + (tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y); - } - else { - *x = layout->tile_border_x + ((tile) % layout->columns) * (layout->tile_w + 2 * layout->tile_border_x); - *y = layout->tile_border_y + ((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y); - } + if (layout->flag == FILE_LAYOUT_HOR) { + *x = layout->tile_border_x + + (tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x); + *y = layout->tile_border_y + + (tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y); + } + else { + *x = layout->tile_border_x + + ((tile) % layout->columns) * (layout->tile_w + 2 * layout->tile_border_x); + *y = layout->tile_border_y + + ((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y); + } } float file_string_width(const char *str) { - uiStyle *style = UI_style_get(); - float width; + uiStyle *style = UI_style_get(); + float width; - UI_fontstyle_set(&style->widget); - if (style->widget.kerning == 1) { /* for BLF_width */ - BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT); - } + UI_fontstyle_set(&style->widget); + if (style->widget.kerning == 1) { /* for BLF_width */ + BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT); + } - width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + width = BLF_width(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - if (style->widget.kerning == 1) { - BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT); - } + if (style->widget.kerning == 1) { + BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT); + } - return width; + return width; } float file_font_pointsize(void) { #if 0 - float s; - char tmp[2] = "X"; - uiStyle *style = UI_style_get(); - UI_fontstyle_set(&style->widget); - s = BLF_height(style->widget.uifont_id, tmp); - return style->widget.points; + float s; + char tmp[2] = "X"; + uiStyle *style = UI_style_get(); + UI_fontstyle_set(&style->widget); + s = BLF_height(style->widget.uifont_id, tmp); + return style->widget.points; #else - uiStyle *style = UI_style_get(); - UI_fontstyle_set(&style->widget); - return style->widget.points * UI_DPI_FAC; + uiStyle *style = UI_style_get(); + UI_fontstyle_set(&style->widget); + return style->widget.points * UI_DPI_FAC; #endif } static void column_widths(FileSelectParams *params, struct FileLayout *layout) { - int i; - const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); - - for (i = 0; i < MAX_FILE_COLUMN; ++i) { - layout->column_widths[i] = 0; - } - - layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X; - /* Biggest possible reasonable values... */ - layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89"); - layout->column_widths[COLUMN_TIME] = file_string_width("23:59"); - layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB"); + int i; + const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); + + for (i = 0; i < MAX_FILE_COLUMN; ++i) { + layout->column_widths[i] = 0; + } + + layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X; + /* Biggest possible reasonable values... */ + layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89"); + layout->column_widths[COLUMN_TIME] = file_string_width("23:59"); + layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB"); } void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) { - FileSelectParams *params = ED_fileselect_get_params(sfile); - FileLayout *layout = NULL; - View2D *v2d = &ar->v2d; - int maxlen = 0; - int numfiles; - int textheight; - - if (sfile->layout == NULL) { - sfile->layout = MEM_callocN(sizeof(struct FileLayout), "file_layout"); - sfile->layout->dirty = true; - } - else if (sfile->layout->dirty == false) { - return; - } - - numfiles = filelist_files_ensure(sfile->files); - textheight = (int)file_font_pointsize(); - layout = sfile->layout; - layout->textheight = textheight; - - if (params->display == FILE_IMGDISPLAY) { - layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; - layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; - layout->tile_border_x = 0.3f * UI_UNIT_X; - layout->tile_border_y = 0.3f * UI_UNIT_X; - layout->prv_border_x = 0.3f * UI_UNIT_X; - layout->prv_border_y = 0.3f * UI_UNIT_Y; - layout->tile_w = layout->prv_w + 2 * layout->prv_border_x; - layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight; - layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x); - layout->columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x); - if (layout->columns > 0) - layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero - else { - layout->columns = 1; - layout->rows = numfiles + 1; // XXX dirty, modulo is zero - } - layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) + layout->tile_border_y * 2; - layout->flag = FILE_LAYOUT_VER; - } - else { - int column_space = 0.6f * UI_UNIT_X; - int column_icon_space = 0.2f * UI_UNIT_X; - - layout->prv_w = 0; - layout->prv_h = 0; - layout->tile_border_x = 0.4f * UI_UNIT_X; - layout->tile_border_y = 0.1f * UI_UNIT_Y; - layout->prv_border_x = 0; - layout->prv_border_y = 0; - layout->tile_h = textheight * 3 / 2; - layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y); - /* Padding by full scrollbar H is too much, can overlap tile border Y. */ - layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) / - (layout->tile_h + 2 * layout->tile_border_y); - - column_widths(params, layout); - - if (params->display == FILE_SHORTDISPLAY) { - maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space + - (int)layout->column_widths[COLUMN_NAME] + column_space + - (int)layout->column_widths[COLUMN_SIZE] + column_space; - } - else { - maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space + - (int)layout->column_widths[COLUMN_NAME] + column_space + - (int)layout->column_widths[COLUMN_DATE] + column_space + - (int)layout->column_widths[COLUMN_TIME] + column_space + - (int)layout->column_widths[COLUMN_SIZE] + column_space; - } - layout->tile_w = maxlen; - if (layout->rows > 0) - layout->columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero - else { - layout->rows = 1; - layout->columns = numfiles + 1; // XXX dirty, modulo is zero - } - layout->width = sfile->layout->columns * (layout->tile_w + 2 * layout->tile_border_x) + layout->tile_border_x * 2; - layout->flag = FILE_LAYOUT_HOR; - } - params->display_previous = params->display; - layout->dirty = false; + FileSelectParams *params = ED_fileselect_get_params(sfile); + FileLayout *layout = NULL; + View2D *v2d = &ar->v2d; + int maxlen = 0; + int numfiles; + int textheight; + + if (sfile->layout == NULL) { + sfile->layout = MEM_callocN(sizeof(struct FileLayout), "file_layout"); + sfile->layout->dirty = true; + } + else if (sfile->layout->dirty == false) { + return; + } + + numfiles = filelist_files_ensure(sfile->files); + textheight = (int)file_font_pointsize(); + layout = sfile->layout; + layout->textheight = textheight; + + if (params->display == FILE_IMGDISPLAY) { + layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; + layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; + layout->tile_border_x = 0.3f * UI_UNIT_X; + layout->tile_border_y = 0.3f * UI_UNIT_X; + layout->prv_border_x = 0.3f * UI_UNIT_X; + layout->prv_border_y = 0.3f * UI_UNIT_Y; + layout->tile_w = layout->prv_w + 2 * layout->prv_border_x; + layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight; + layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x); + layout->columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x); + if (layout->columns > 0) + layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero + else { + layout->columns = 1; + layout->rows = numfiles + 1; // XXX dirty, modulo is zero + } + layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) + + layout->tile_border_y * 2; + layout->flag = FILE_LAYOUT_VER; + } + else { + int column_space = 0.6f * UI_UNIT_X; + int column_icon_space = 0.2f * UI_UNIT_X; + + layout->prv_w = 0; + layout->prv_h = 0; + layout->tile_border_x = 0.4f * UI_UNIT_X; + layout->tile_border_y = 0.1f * UI_UNIT_Y; + layout->prv_border_x = 0; + layout->prv_border_y = 0; + layout->tile_h = textheight * 3 / 2; + layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y); + /* Padding by full scrollbar H is too much, can overlap tile border Y. */ + layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) / + (layout->tile_h + 2 * layout->tile_border_y); + + column_widths(params, layout); + + if (params->display == FILE_SHORTDISPLAY) { + maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space + + (int)layout->column_widths[COLUMN_NAME] + column_space + + (int)layout->column_widths[COLUMN_SIZE] + column_space; + } + else { + maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space + + (int)layout->column_widths[COLUMN_NAME] + column_space + + (int)layout->column_widths[COLUMN_DATE] + column_space + + (int)layout->column_widths[COLUMN_TIME] + column_space + + (int)layout->column_widths[COLUMN_SIZE] + column_space; + } + layout->tile_w = maxlen; + if (layout->rows > 0) + layout->columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero + else { + layout->rows = 1; + layout->columns = numfiles + 1; // XXX dirty, modulo is zero + } + layout->width = sfile->layout->columns * (layout->tile_w + 2 * layout->tile_border_x) + + layout->tile_border_x * 2; + layout->flag = FILE_LAYOUT_HOR; + } + params->display_previous = params->display; + layout->dirty = false; } FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar) { - if (!sfile->layout) { - ED_fileselect_init_layout(sfile, ar); - } - return sfile->layout; + if (!sfile->layout) { + ED_fileselect_init_layout(sfile, ar); + } + return sfile->layout; } void ED_file_change_dir(bContext *C) { - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - ScrArea *sa = CTX_wm_area(C); + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + ScrArea *sa = CTX_wm_area(C); - if (sfile->params) { - ED_fileselect_clear(wm, sa, sfile); + if (sfile->params) { + ED_fileselect_clear(wm, sa, sfile); - /* Clear search string, it is very rare to want to keep that filter while changing dir, - * and usually very annoying to keep it actually! */ - sfile->params->filter_search[0] = '\0'; - sfile->params->active_file = -1; + /* Clear search string, it is very rare to want to keep that filter while changing dir, + * and usually very annoying to keep it actually! */ + sfile->params->filter_search[0] = '\0'; + sfile->params->active_file = -1; - if (!filelist_is_dir(sfile->files, sfile->params->dir)) { - BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); - /* could return but just refresh the current dir */ - } - filelist_setdir(sfile->files, sfile->params->dir); + if (!filelist_is_dir(sfile->files, sfile->params->dir)) { + BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); + /* could return but just refresh the current dir */ + } + filelist_setdir(sfile->files, sfile->params->dir); - if (folderlist_clear_next(sfile)) - folderlist_free(sfile->folders_next); + if (folderlist_clear_next(sfile)) + folderlist_free(sfile->folders_next); - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - file_draw_check(C); - } + file_draw_check(C); + } } int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file) { - int match = 0; - - int i; - FileDirEntry *file; - int n = filelist_files_ensure(sfile->files); - - /* select any file that matches the pattern, this includes exact match - * if the user selects a single file by entering the filename - */ - for (i = 0; i < n; i++) { - file = filelist_file(sfile->files, i); - /* Do not check whether file is a file or dir here! Causes T44243 - * (we do accept dirs at this stage). */ - if (fnmatch(pattern, file->relpath, 0) == 0) { - filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); - if (!match) { - BLI_strncpy(matched_file, file->relpath, FILE_MAX); - } - match++; - } - } - - return match; + int match = 0; + + int i; + FileDirEntry *file; + int n = filelist_files_ensure(sfile->files); + + /* select any file that matches the pattern, this includes exact match + * if the user selects a single file by entering the filename + */ + for (i = 0; i < n; i++) { + file = filelist_file(sfile->files, i); + /* Do not check whether file is a file or dir here! Causes T44243 + * (we do accept dirs at this stage). */ + if (fnmatch(pattern, file->relpath, 0) == 0) { + filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + if (!match) { + BLI_strncpy(matched_file, file->relpath, FILE_MAX); + } + match++; + } + } + + return match; } int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) { - SpaceFile *sfile = CTX_wm_space_file(C); - int match = AUTOCOMPLETE_NO_MATCH; - - /* search if str matches the beginning of name */ - if (str[0] && sfile->files) { - char dirname[FILE_MAX]; - - DIR *dir; - struct dirent *de; - - BLI_split_dir_part(str, dirname, sizeof(dirname)); - - dir = opendir(dirname); - - if (dir) { - AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX); - - while ((de = readdir(dir)) != NULL) { - if (FILENAME_IS_CURRPAR(de->d_name)) { - /* pass */ - } - else { - char path[FILE_MAX]; - BLI_stat_t status; - - BLI_join_dirfile(path, sizeof(path), dirname, de->d_name); - - if (BLI_stat(path, &status) == 0) { - if (S_ISDIR(status.st_mode)) { /* is subdir */ - UI_autocomplete_update_name(autocpl, path); - } - } - } - } - closedir(dir); - - match = UI_autocomplete_end(autocpl, str); - if (match == AUTOCOMPLETE_FULL_MATCH) { - BLI_add_slash(str); - } - } - } - - return match; + SpaceFile *sfile = CTX_wm_space_file(C); + int match = AUTOCOMPLETE_NO_MATCH; + + /* search if str matches the beginning of name */ + if (str[0] && sfile->files) { + char dirname[FILE_MAX]; + + DIR *dir; + struct dirent *de; + + BLI_split_dir_part(str, dirname, sizeof(dirname)); + + dir = opendir(dirname); + + if (dir) { + AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX); + + while ((de = readdir(dir)) != NULL) { + if (FILENAME_IS_CURRPAR(de->d_name)) { + /* pass */ + } + else { + char path[FILE_MAX]; + BLI_stat_t status; + + BLI_join_dirfile(path, sizeof(path), dirname, de->d_name); + + if (BLI_stat(path, &status) == 0) { + if (S_ISDIR(status.st_mode)) { /* is subdir */ + UI_autocomplete_update_name(autocpl, path); + } + } + } + } + closedir(dir); + + match = UI_autocomplete_end(autocpl, str); + if (match == AUTOCOMPLETE_FULL_MATCH) { + BLI_add_slash(str); + } + } + } + + return match; } int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v)) { - SpaceFile *sfile = CTX_wm_space_file(C); - int match = AUTOCOMPLETE_NO_MATCH; - - /* search if str matches the beginning of name */ - if (str[0] && sfile->files) { - AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX); - int nentries = filelist_files_ensure(sfile->files); - int i; - - for (i = 0; i < nentries; ++i) { - FileDirEntry *file = filelist_file(sfile->files, i); - UI_autocomplete_update_name(autocpl, file->relpath); - } - match = UI_autocomplete_end(autocpl, str); - } - - return match; + SpaceFile *sfile = CTX_wm_space_file(C); + int match = AUTOCOMPLETE_NO_MATCH; + + /* search if str matches the beginning of name */ + if (str[0] && sfile->files) { + AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX); + int nentries = filelist_files_ensure(sfile->files); + int i; + + for (i = 0; i < nentries; ++i) { + FileDirEntry *file = filelist_file(sfile->files, i); + UI_autocomplete_update_name(autocpl, file->relpath); + } + match = UI_autocomplete_end(autocpl, str); + } + + return match; } void ED_fileselect_clear(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) { - /* only NULL in rare cases - [#29734] */ - if (sfile->files) { - filelist_readjob_stop(wm, sa); - filelist_freelib(sfile->files); - filelist_clear(sfile->files); - } - - sfile->params->highlight_file = -1; - WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); + /* only NULL in rare cases - [#29734] */ + if (sfile->files) { + filelist_readjob_stop(wm, sa); + filelist_freelib(sfile->files); + filelist_clear(sfile->files); + } + + sfile->params->highlight_file = -1; + WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); } void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile) { - if (!sfile) return; - if (sfile->op) { - WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL); - sfile->op = NULL; - } - - folderlist_free(sfile->folders_prev); - folderlist_free(sfile->folders_next); - - if (sfile->files) { - ED_fileselect_clear(wm, sa, sfile); - filelist_free(sfile->files); - MEM_freeN(sfile->files); - sfile->files = NULL; - } + if (!sfile) + return; + if (sfile->op) { + WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL); + sfile->op = NULL; + } + + folderlist_free(sfile->folders_prev); + folderlist_free(sfile->folders_next); + + if (sfile->files) { + ED_fileselect_clear(wm, sa, sfile); + filelist_free(sfile->files); + MEM_freeN(sfile->files); + sfile->files = NULL; + } } /** Helper used by both main update code, and smoothscroll timer, to try to enable rename editing from * params->renamefile name. */ void file_params_renamefile_activate(SpaceFile *sfile, FileSelectParams *params) { - BLI_assert(params->rename_flag != 0); - - if ((params->rename_flag & (FILE_PARAMS_RENAME_ACTIVE | FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE)) != 0) { - return; - } - - BLI_assert(params->renamefile[0] != '\0'); - - const int idx = filelist_file_findpath(sfile->files, params->renamefile); - if (idx >= 0) { - FileDirEntry *file = filelist_file(sfile->files, idx); - BLI_assert(file != NULL); - - if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) { - filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); - params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; - } - else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) { - filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); - params->renamefile[0] = '\0'; - params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE; - } - } - /* File listing is now async, only reset renaming if matching entry is not found - * when file listing is not done. */ - else if (filelist_is_ready(sfile->files)) { - params->renamefile[0] = '\0'; - params->rename_flag = 0; - } + BLI_assert(params->rename_flag != 0); + + if ((params->rename_flag & (FILE_PARAMS_RENAME_ACTIVE | FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE)) != + 0) { + return; + } + + BLI_assert(params->renamefile[0] != '\0'); + + const int idx = filelist_file_findpath(sfile->files, params->renamefile); + if (idx >= 0) { + FileDirEntry *file = filelist_file(sfile->files, idx); + BLI_assert(file != NULL); + + if ((params->rename_flag & FILE_PARAMS_RENAME_PENDING) != 0) { + filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); + params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; + } + else if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_PENDING) != 0) { + filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL); + params->renamefile[0] = '\0'; + params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE; + } + } + /* File listing is now async, only reset renaming if matching entry is not found + * when file listing is not done. */ + else if (filelist_is_ready(sfile->files)) { + params->renamefile[0] = '\0'; + params->rename_flag = 0; + } } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index c3c85600121..f14148abe86 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -21,7 +21,6 @@ * \ingroup spfile */ - #include <stdlib.h> #include <string.h> #include <stdio.h> @@ -37,698 +36,721 @@ #include "ED_fileselect.h" #ifdef WIN32 - /* Need to include windows.h so _WIN32_IE is defined. */ +/* Need to include windows.h so _WIN32_IE is defined. */ # include <windows.h> - /* For SHGetSpecialFolderPath, has to be done before BLI_winstuff +/* For SHGetSpecialFolderPath, has to be done before BLI_winstuff * because 'near' is disabled through BLI_windstuff. */ # include <shlobj.h> # include "BLI_winstuff.h" #endif #ifdef __APPLE__ -#include <Carbon/Carbon.h> +# include <Carbon/Carbon.h> #endif /* __APPLE__ */ #ifdef __linux__ -#include <mntent.h> -#include "BLI_fileops_types.h" +# include <mntent.h> +# include "BLI_fileops_types.h" #endif -#include "fsmenu.h" /* include ourselves */ - +#include "fsmenu.h" /* include ourselves */ /* FSMENU HANDLING */ typedef struct FSMenu { - FSMenuEntry *fsmenu_system; - FSMenuEntry *fsmenu_system_bookmarks; - FSMenuEntry *fsmenu_bookmarks; - FSMenuEntry *fsmenu_recent; + FSMenuEntry *fsmenu_system; + FSMenuEntry *fsmenu_system_bookmarks; + FSMenuEntry *fsmenu_bookmarks; + FSMenuEntry *fsmenu_recent; } FSMenu; static FSMenu *g_fsmenu = NULL; FSMenu *ED_fsmenu_get(void) { - if (!g_fsmenu) { - g_fsmenu = MEM_callocN(sizeof(struct FSMenu), "fsmenu"); - } - return g_fsmenu; + if (!g_fsmenu) { + g_fsmenu = MEM_callocN(sizeof(struct FSMenu), "fsmenu"); + } + return g_fsmenu; } struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category) { - FSMenuEntry *fsm_head = NULL; - - switch (category) { - case FS_CATEGORY_SYSTEM: - fsm_head = fsmenu->fsmenu_system; - break; - case FS_CATEGORY_SYSTEM_BOOKMARKS: - fsm_head = fsmenu->fsmenu_system_bookmarks; - break; - case FS_CATEGORY_BOOKMARKS: - fsm_head = fsmenu->fsmenu_bookmarks; - break; - case FS_CATEGORY_RECENT: - fsm_head = fsmenu->fsmenu_recent; - break; - } - return fsm_head; + FSMenuEntry *fsm_head = NULL; + + switch (category) { + case FS_CATEGORY_SYSTEM: + fsm_head = fsmenu->fsmenu_system; + break; + case FS_CATEGORY_SYSTEM_BOOKMARKS: + fsm_head = fsmenu->fsmenu_system_bookmarks; + break; + case FS_CATEGORY_BOOKMARKS: + fsm_head = fsmenu->fsmenu_bookmarks; + break; + case FS_CATEGORY_RECENT: + fsm_head = fsmenu->fsmenu_recent; + break; + } + return fsm_head; } void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head) { - switch (category) { - case FS_CATEGORY_SYSTEM: - fsmenu->fsmenu_system = fsm_head; - break; - case FS_CATEGORY_SYSTEM_BOOKMARKS: - fsmenu->fsmenu_system_bookmarks = fsm_head; - break; - case FS_CATEGORY_BOOKMARKS: - fsmenu->fsmenu_bookmarks = fsm_head; - break; - case FS_CATEGORY_RECENT: - fsmenu->fsmenu_recent = fsm_head; - break; - } + switch (category) { + case FS_CATEGORY_SYSTEM: + fsmenu->fsmenu_system = fsm_head; + break; + case FS_CATEGORY_SYSTEM_BOOKMARKS: + fsmenu->fsmenu_system_bookmarks = fsm_head; + break; + case FS_CATEGORY_BOOKMARKS: + fsmenu->fsmenu_bookmarks = fsm_head; + break; + case FS_CATEGORY_RECENT: + fsmenu->fsmenu_recent = fsm_head; + break; + } } int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category) { - FSMenuEntry *fsm_iter; - int count = 0; + FSMenuEntry *fsm_iter; + int count = 0; - for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter; fsm_iter = fsm_iter->next) { - count++; - } + for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter; fsm_iter = fsm_iter->next) { + count++; + } - return count; + return count; } FSMenuEntry *ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index) { - FSMenuEntry *fsm_iter; + FSMenuEntry *fsm_iter; - for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && index; fsm_iter = fsm_iter->next) { - index--; - } + for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && index; + fsm_iter = fsm_iter->next) { + index--; + } - return fsm_iter; + return fsm_iter; } char *ED_fsmenu_entry_get_path(struct FSMenuEntry *fsentry) { - return fsentry->path; + return fsentry->path; } void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path) { - if ((!fsentry->path || !path || !STREQ(path, fsentry->path)) && (fsentry->path != path)) { - char tmp_name[FILE_MAXFILE]; + if ((!fsentry->path || !path || !STREQ(path, fsentry->path)) && (fsentry->path != path)) { + char tmp_name[FILE_MAXFILE]; - MEM_SAFE_FREE(fsentry->path); + MEM_SAFE_FREE(fsentry->path); - fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL; + fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL; - BLI_make_file_string("/", tmp_name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(ED_fsmenu_get(), tmp_name); - } + BLI_make_file_string("/", + tmp_name, + BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLENDER_BOOKMARK_FILE); + fsmenu_write_file(ED_fsmenu_get(), tmp_name); + } } static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size) { - int offset = 0; - int len = name_size; - - if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) { - /* use as size */ - len += 1; - } - - BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size)); - if (!name[0]) { - name[0] = '/'; - name[1] = '\0'; - } + int offset = 0; + int len = name_size; + + if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) { + /* use as size */ + len += 1; + } + + BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size)); + if (!name[0]) { + name[0] = '/'; + name[1] = '\0'; + } } char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry) { - if (fsentry->name[0]) { - return fsentry->name; - } - else { - /* Here we abuse fsm_iter->name, keeping first char NULL. */ - char *name = fsentry->name + 1; - size_t name_size = sizeof(fsentry->name) - 1; - - fsmenu_entry_generate_name(fsentry, name, name_size); - return name; - } + if (fsentry->name[0]) { + return fsentry->name; + } + else { + /* Here we abuse fsm_iter->name, keeping first char NULL. */ + char *name = fsentry->name + 1; + size_t name_size = sizeof(fsentry->name) - 1; + + fsmenu_entry_generate_name(fsentry, name, name_size); + return name; + } } void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name) { - if (!STREQ(name, fsentry->name)) { - char tmp_name[FILE_MAXFILE]; - size_t tmp_name_size = sizeof(tmp_name); - - fsmenu_entry_generate_name(fsentry, tmp_name, tmp_name_size); - if (!name[0] || STREQ(tmp_name, name)) { - /* reset name to default behavior. */ - fsentry->name[0] = '\0'; - } - else { - BLI_strncpy(fsentry->name, name, sizeof(fsentry->name)); - } - - BLI_make_file_string("/", tmp_name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); - fsmenu_write_file(ED_fsmenu_get(), tmp_name); - } + if (!STREQ(name, fsentry->name)) { + char tmp_name[FILE_MAXFILE]; + size_t tmp_name_size = sizeof(tmp_name); + + fsmenu_entry_generate_name(fsentry, tmp_name, tmp_name_size); + if (!name[0] || STREQ(tmp_name, name)) { + /* reset name to default behavior. */ + fsentry->name[0] = '\0'; + } + else { + BLI_strncpy(fsentry->name, name, sizeof(fsentry->name)); + } + + BLI_make_file_string("/", + tmp_name, + BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), + BLENDER_BOOKMARK_FILE); + fsmenu_write_file(ED_fsmenu_get(), tmp_name); + } } void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry) { - if (fsentry->path && fsentry->path[0]) { + if (fsentry->path && fsentry->path[0]) { #ifdef WIN32 - /* XXX Special case, always consider those as valid. - * Thanks to Windows, which can spend five seconds to perform a mere stat() call on those paths... - * See T43684. - */ - const char *exceptions[] = {"A:\\", "B:\\", NULL}; - const size_t exceptions_len[] = {strlen(exceptions[0]), strlen(exceptions[1]), 0}; - int i; - - for (i = 0; exceptions[i]; i++) { - if (STRCASEEQLEN(fsentry->path, exceptions[i], exceptions_len[i])) { - fsentry->valid = true; - return; - } - } + /* XXX Special case, always consider those as valid. + * Thanks to Windows, which can spend five seconds to perform a mere stat() call on those paths... + * See T43684. + */ + const char *exceptions[] = {"A:\\", "B:\\", NULL}; + const size_t exceptions_len[] = {strlen(exceptions[0]), strlen(exceptions[1]), 0}; + int i; + + for (i = 0; exceptions[i]; i++) { + if (STRCASEEQLEN(fsentry->path, exceptions[i], exceptions_len[i])) { + fsentry->valid = true; + return; + } + } #endif - fsentry->valid = BLI_is_dir(fsentry->path); - } - else { - fsentry->valid = false; - } + fsentry->valid = BLI_is_dir(fsentry->path); + } + else { + fsentry->valid = false; + } } short fsmenu_can_save(struct FSMenu *fsmenu, FSMenuCategory category, int idx) { - FSMenuEntry *fsm_iter; + FSMenuEntry *fsm_iter; - for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && idx; fsm_iter = fsm_iter->next) { - idx--; - } + for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && idx; + fsm_iter = fsm_iter->next) { + idx--; + } - return fsm_iter ? fsm_iter->save : 0; + return fsm_iter ? fsm_iter->save : 0; } -void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, FSMenuInsert flag) +void fsmenu_insert_entry(struct FSMenu *fsmenu, + FSMenuCategory category, + const char *path, + const char *name, + FSMenuInsert flag) { - FSMenuEntry *fsm_prev; - FSMenuEntry *fsm_iter; - FSMenuEntry *fsm_head; - - fsm_head = ED_fsmenu_get_category(fsmenu, category); - fsm_prev = fsm_head; /* this is odd and not really correct? */ - - for (fsm_iter = fsm_head; fsm_iter; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) { - if (fsm_iter->path) { - const int cmp_ret = BLI_path_cmp(path, fsm_iter->path); - if (cmp_ret == 0) { - if (flag & FS_INSERT_FIRST) { - if (fsm_iter != fsm_head) { - fsm_prev->next = fsm_iter->next; - fsm_iter->next = fsm_head; - ED_fsmenu_set_category(fsmenu, category, fsm_iter); - } - } - return; - } - else if ((flag & FS_INSERT_SORTED) && cmp_ret < 0) { - break; - } - } - else { - /* if we're bookmarking this, file should come - * before the last separator, only automatically added - * current dir go after the last sep. */ - if (flag & FS_INSERT_SAVE) { - break; - } - } - } - - fsm_iter = MEM_mallocN(sizeof(*fsm_iter), "fsme"); - fsm_iter->path = BLI_strdup(path); - fsm_iter->save = (flag & FS_INSERT_SAVE) != 0; - - if ((category == FS_CATEGORY_RECENT) && (!name || !name[0])) { - /* Special handling when adding new recent entry - check if dir exists in some other categories, - * and try to use name from there if so. */ - FSMenuCategory cats[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS}; - int i = ARRAY_SIZE(cats); - - while (i--) { - FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]); - - for (; tfsm; tfsm = tfsm->next) { - if (STREQ(tfsm->path, fsm_iter->path)) { - if (tfsm->name[0]) { - name = tfsm->name; - } - break; - } - } - if (tfsm) { - break; - } - } - } - - if (name && name[0]) { - BLI_strncpy(fsm_iter->name, name, sizeof(fsm_iter->name)); - } - else { - fsm_iter->name[0] = '\0'; - } - fsmenu_entry_refresh_valid(fsm_iter); - - if (fsm_prev) { - if (flag & FS_INSERT_FIRST) { - fsm_iter->next = fsm_head; - ED_fsmenu_set_category(fsmenu, category, fsm_iter); - } - else { - fsm_iter->next = fsm_prev->next; - fsm_prev->next = fsm_iter; - } - } - else { - fsm_iter->next = fsm_head; - ED_fsmenu_set_category(fsmenu, category, fsm_iter); - } + FSMenuEntry *fsm_prev; + FSMenuEntry *fsm_iter; + FSMenuEntry *fsm_head; + + fsm_head = ED_fsmenu_get_category(fsmenu, category); + fsm_prev = fsm_head; /* this is odd and not really correct? */ + + for (fsm_iter = fsm_head; fsm_iter; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) { + if (fsm_iter->path) { + const int cmp_ret = BLI_path_cmp(path, fsm_iter->path); + if (cmp_ret == 0) { + if (flag & FS_INSERT_FIRST) { + if (fsm_iter != fsm_head) { + fsm_prev->next = fsm_iter->next; + fsm_iter->next = fsm_head; + ED_fsmenu_set_category(fsmenu, category, fsm_iter); + } + } + return; + } + else if ((flag & FS_INSERT_SORTED) && cmp_ret < 0) { + break; + } + } + else { + /* if we're bookmarking this, file should come + * before the last separator, only automatically added + * current dir go after the last sep. */ + if (flag & FS_INSERT_SAVE) { + break; + } + } + } + + fsm_iter = MEM_mallocN(sizeof(*fsm_iter), "fsme"); + fsm_iter->path = BLI_strdup(path); + fsm_iter->save = (flag & FS_INSERT_SAVE) != 0; + + if ((category == FS_CATEGORY_RECENT) && (!name || !name[0])) { + /* Special handling when adding new recent entry - check if dir exists in some other categories, + * and try to use name from there if so. */ + FSMenuCategory cats[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS}; + int i = ARRAY_SIZE(cats); + + while (i--) { + FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]); + + for (; tfsm; tfsm = tfsm->next) { + if (STREQ(tfsm->path, fsm_iter->path)) { + if (tfsm->name[0]) { + name = tfsm->name; + } + break; + } + } + if (tfsm) { + break; + } + } + } + + if (name && name[0]) { + BLI_strncpy(fsm_iter->name, name, sizeof(fsm_iter->name)); + } + else { + fsm_iter->name[0] = '\0'; + } + fsmenu_entry_refresh_valid(fsm_iter); + + if (fsm_prev) { + if (flag & FS_INSERT_FIRST) { + fsm_iter->next = fsm_head; + ED_fsmenu_set_category(fsmenu, category, fsm_iter); + } + else { + fsm_iter->next = fsm_prev->next; + fsm_prev->next = fsm_iter; + } + } + else { + fsm_iter->next = fsm_head; + ED_fsmenu_set_category(fsmenu, category, fsm_iter); + } } void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx) { - FSMenuEntry *fsm_prev = NULL; - FSMenuEntry *fsm_iter; - FSMenuEntry *fsm_head; - - fsm_head = ED_fsmenu_get_category(fsmenu, category); - - for (fsm_iter = fsm_head; fsm_iter && idx; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) - idx--; - - if (fsm_iter) { - /* you should only be able to remove entries that were - * not added by default, like windows drives. - * also separators (where path == NULL) shouldn't be removed */ - if (fsm_iter->save && fsm_iter->path) { - - /* remove fsme from list */ - if (fsm_prev) { - fsm_prev->next = fsm_iter->next; - } - else { - fsm_head = fsm_iter->next; - ED_fsmenu_set_category(fsmenu, category, fsm_head); - } - /* free entry */ - MEM_freeN(fsm_iter->path); - MEM_freeN(fsm_iter); - } - } + FSMenuEntry *fsm_prev = NULL; + FSMenuEntry *fsm_iter; + FSMenuEntry *fsm_head; + + fsm_head = ED_fsmenu_get_category(fsmenu, category); + + for (fsm_iter = fsm_head; fsm_iter && idx; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) + idx--; + + if (fsm_iter) { + /* you should only be able to remove entries that were + * not added by default, like windows drives. + * also separators (where path == NULL) shouldn't be removed */ + if (fsm_iter->save && fsm_iter->path) { + + /* remove fsme from list */ + if (fsm_prev) { + fsm_prev->next = fsm_iter->next; + } + else { + fsm_head = fsm_iter->next; + ED_fsmenu_set_category(fsmenu, category, fsm_head); + } + /* free entry */ + MEM_freeN(fsm_iter->path); + MEM_freeN(fsm_iter); + } + } } void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename) { - FSMenuEntry *fsm_iter = NULL; - char fsm_name[FILE_MAX]; - int nwritten = 0; - - FILE *fp = BLI_fopen(filename, "w"); - if (!fp) return; - - fprintf(fp, "[Bookmarks]\n"); - for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsm_iter; fsm_iter = fsm_iter->next) { - if (fsm_iter->path && fsm_iter->save) { - fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name)); - if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) { - fprintf(fp, "!%s\n", fsm_iter->name); - } - fprintf(fp, "%s\n", fsm_iter->path); - } - } - fprintf(fp, "[Recent]\n"); - for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT); fsm_iter && (nwritten < FSMENU_RECENT_MAX); fsm_iter = fsm_iter->next, ++nwritten) { - if (fsm_iter->path && fsm_iter->save) { - fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name)); - if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) { - fprintf(fp, "!%s\n", fsm_iter->name); - } - fprintf(fp, "%s\n", fsm_iter->path); - } - } - fclose(fp); + FSMenuEntry *fsm_iter = NULL; + char fsm_name[FILE_MAX]; + int nwritten = 0; + + FILE *fp = BLI_fopen(filename, "w"); + if (!fp) + return; + + fprintf(fp, "[Bookmarks]\n"); + for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsm_iter; + fsm_iter = fsm_iter->next) { + if (fsm_iter->path && fsm_iter->save) { + fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name)); + if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) { + fprintf(fp, "!%s\n", fsm_iter->name); + } + fprintf(fp, "%s\n", fsm_iter->path); + } + } + fprintf(fp, "[Recent]\n"); + for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT); + fsm_iter && (nwritten < FSMENU_RECENT_MAX); + fsm_iter = fsm_iter->next, ++nwritten) { + if (fsm_iter->path && fsm_iter->save) { + fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name)); + if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) { + fprintf(fp, "!%s\n", fsm_iter->name); + } + fprintf(fp, "%s\n", fsm_iter->path); + } + } + fclose(fp); } void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename) { - char line[FILE_MAXDIR]; - char name[FILE_MAXFILE]; - FSMenuCategory category = FS_CATEGORY_BOOKMARKS; - FILE *fp; - - fp = BLI_fopen(filename, "r"); - if (!fp) return; - - name[0] = '\0'; - - while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */ - if (STREQLEN(line, "[Bookmarks]", 11)) { - category = FS_CATEGORY_BOOKMARKS; - } - else if (STREQLEN(line, "[Recent]", 8)) { - category = FS_CATEGORY_RECENT; - } - else if (line[0] == '!') { - int len = strlen(line); - if (len > 0) { - if (line[len - 1] == '\n') { - line[len - 1] = '\0'; - } - BLI_strncpy(name, line + 1, sizeof(name)); - } - } - else { - int len = strlen(line); - if (len > 0) { - if (line[len - 1] == '\n') { - line[len - 1] = '\0'; - } - /* don't do this because it can be slow on network drives, - * having a bookmark from a drive that's ejected or so isn't - * all _that_ bad */ + char line[FILE_MAXDIR]; + char name[FILE_MAXFILE]; + FSMenuCategory category = FS_CATEGORY_BOOKMARKS; + FILE *fp; + + fp = BLI_fopen(filename, "r"); + if (!fp) + return; + + name[0] = '\0'; + + while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */ + if (STREQLEN(line, "[Bookmarks]", 11)) { + category = FS_CATEGORY_BOOKMARKS; + } + else if (STREQLEN(line, "[Recent]", 8)) { + category = FS_CATEGORY_RECENT; + } + else if (line[0] == '!') { + int len = strlen(line); + if (len > 0) { + if (line[len - 1] == '\n') { + line[len - 1] = '\0'; + } + BLI_strncpy(name, line + 1, sizeof(name)); + } + } + else { + int len = strlen(line); + if (len > 0) { + if (line[len - 1] == '\n') { + line[len - 1] = '\0'; + } + /* don't do this because it can be slow on network drives, + * having a bookmark from a drive that's ejected or so isn't + * all _that_ bad */ #if 0 - if (BLI_exists(line)) + if (BLI_exists(line)) #endif - { - fsmenu_insert_entry(fsmenu, category, line, name, FS_INSERT_SAVE); - } - } - /* always reset name. */ - name[0] = '\0'; - } - } - fclose(fp); + { + fsmenu_insert_entry(fsmenu, category, line, name, FS_INSERT_SAVE); + } + } + /* always reset name. */ + name[0] = '\0'; + } + } + fclose(fp); } void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) { - char line[FILE_MAXDIR]; + char line[FILE_MAXDIR]; #ifdef WIN32 - /* Add the drive names to the listing */ - { - wchar_t wline[FILE_MAXDIR]; - __int64 tmp; - char tmps[4], *name; - int i; - - tmp = GetLogicalDrives(); - - for (i = 0; i < 26; i++) { - if ((tmp >> i) & 1) { - tmps[0] = 'A' + i; - tmps[1] = ':'; - tmps[2] = '\\'; - tmps[3] = '\0'; - name = NULL; - - /* Flee from horrible win querying hover floppy drives! */ - if (i > 1) { - /* Try to get volume label as well... */ - BLI_strncpy_wchar_from_utf8(wline, tmps, 4); - if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) { - size_t label_len; - - BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4); - - label_len = MIN2(strlen(line), FILE_MAXDIR - 6); - BLI_snprintf(line + label_len, 6, " (%.2s)", tmps); - - name = line; - } - } - - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED); - } - } - - /* Adding Desktop and My Documents */ - if (read_bookmarks) { - SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0); - BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR); - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); - SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0); - BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR); - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); - } - } -#else -#ifdef __APPLE__ - { - /* Get mounted volumes better method OSX 10.6 and higher, see: */ - /*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/ - - /* we get all volumes sorted including network and do not relay - * on user-defined finder visibility, less confusing */ - - CFURLRef cfURL = NULL; - CFURLEnumeratorResult result = kCFURLEnumeratorSuccess; - CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL); - - while (result != kCFURLEnumeratorEnd) { - char defPath[FILE_MAX]; - - result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL); - if (result != kCFURLEnumeratorSuccess) - continue; - - CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX); - - /* Add end slash for consistency with other platforms */ - BLI_add_slash(defPath); - - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, FS_INSERT_SORTED); - } - - CFRelease(volEnum); - - /* Finally get user favorite places */ - if (read_bookmarks) { - UInt32 seed; - LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL); - CFArrayRef pathesArray = LSSharedFileListCopySnapshot(list, &seed); - CFIndex pathesCount = CFArrayGetCount(pathesArray); - - for (CFIndex i = 0; i < pathesCount; i++) { - LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i); - - CFURLRef cfURL = NULL; - OSErr err = LSSharedFileListItemResolve(itemRef, - kLSSharedFileListNoUserInteraction | - kLSSharedFileListDoNotMountVolumes, - &cfURL, NULL); - if (err != noErr || !cfURL) - continue; - - CFStringRef pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); - - if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8)) - continue; - - /* Add end slash for consistency with other platforms */ - BLI_add_slash(line); - - /* Exclude "all my files" as it makes no sense in blender fileselector */ - /* Exclude "airdrop" if wlan not active as it would show "" ) */ - if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) { - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_LAST); - } - - CFRelease(pathString); - CFRelease(cfURL); - } - - CFRelease(pathesArray); - CFRelease(list); - } - } + /* Add the drive names to the listing */ + { + wchar_t wline[FILE_MAXDIR]; + __int64 tmp; + char tmps[4], *name; + int i; + + tmp = GetLogicalDrives(); + + for (i = 0; i < 26; i++) { + if ((tmp >> i) & 1) { + tmps[0] = 'A' + i; + tmps[1] = ':'; + tmps[2] = '\\'; + tmps[3] = '\0'; + name = NULL; + + /* Flee from horrible win querying hover floppy drives! */ + if (i > 1) { + /* Try to get volume label as well... */ + BLI_strncpy_wchar_from_utf8(wline, tmps, 4); + if (GetVolumeInformationW( + wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) { + size_t label_len; + + BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4); + + label_len = MIN2(strlen(line), FILE_MAXDIR - 6); + BLI_snprintf(line + label_len, 6, " (%.2s)", tmps); + + name = line; + } + } + + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED); + } + } + + /* Adding Desktop and My Documents */ + if (read_bookmarks) { + SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0); + BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR); + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); + SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0); + BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR); + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); + } + } #else - /* unix */ - { - const char *home = BLI_getenv("HOME"); - - if (read_bookmarks && home) { - BLI_snprintf(line, sizeof(line), "%s/", home); - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); - BLI_snprintf(line, sizeof(line), "%s/Desktop/", home); - if (BLI_exists(line)) { - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); - } - } - - { - int found = 0; -#ifdef __linux__ - /* loop over mount points */ - struct mntent *mnt; - int len; - FILE *fp; - - fp = setmntent(MOUNTED, "r"); - if (fp == NULL) { - fprintf(stderr, "could not get a list of mounted filesystems\n"); - } - else { - while ((mnt = getmntent(fp))) { - if (STRPREFIX(mnt->mnt_dir, "/boot")) { - /* Hide share not usable to the user. */ - continue; - } - else if (!STRPREFIX(mnt->mnt_fsname, "/dev")) { - continue; - } - else if (STRPREFIX(mnt->mnt_fsname, "/dev/loop")) { - /* The dev/loop* entries are SNAPS used by desktop environment - * (Gnome) no need for them to show up in the list. */ - continue; - } - - len = strlen(mnt->mnt_dir); - if (len && mnt->mnt_dir[len - 1] != '/') { - BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir); - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, NULL, FS_INSERT_SORTED); - } - else { - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, FS_INSERT_SORTED); - } - - found = 1; - } - if (endmntent(fp) == 0) { - fprintf(stderr, "could not close the list of mounted filesystems\n"); - } - } - /* Check gvfs shares. */ - const char * const xdg_runtime_dir = BLI_getenv("XDG_RUNTIME_DIR"); - if (xdg_runtime_dir != NULL) { - struct direntry *dir; - char name[FILE_MAX]; - BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/"); - const uint dir_len = BLI_filelist_dir_contents(name, &dir); - for (uint i = 0; i < dir_len; i++) { - if ((dir[i].type & S_IFDIR)) { - const char *dirname = dir[i].relname; - if (dirname[0] != '.') { - /* Dir names contain a lot of unwanted text. - * Assuming every entry ends with the share name */ - const char *label = strstr(dirname, "share="); - if (label != NULL) { - /* Move pointer so "share=" is trimmed off - * or use full dirname as label. */ - const char *label_test = label + 6; - label = *label_test ? label_test : dirname; - } - BLI_snprintf(line, sizeof(line), "%s%s/", name, dirname); - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, label, FS_INSERT_SORTED); - found = 1; - } - } - } - BLI_filelist_free(dir, dir_len); - } -#endif - - /* fallback */ - if (!found) - fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, FS_INSERT_SORTED); - } - } -#endif +# ifdef __APPLE__ + { + /* Get mounted volumes better method OSX 10.6 and higher, see: */ + /*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/ + + /* we get all volumes sorted including network and do not relay + * on user-defined finder visibility, less confusing */ + + CFURLRef cfURL = NULL; + CFURLEnumeratorResult result = kCFURLEnumeratorSuccess; + CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes( + NULL, kCFURLEnumeratorSkipInvisibles, NULL); + + while (result != kCFURLEnumeratorEnd) { + char defPath[FILE_MAX]; + + result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL); + if (result != kCFURLEnumeratorSuccess) + continue; + + CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX); + + /* Add end slash for consistency with other platforms */ + BLI_add_slash(defPath); + + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, FS_INSERT_SORTED); + } + + CFRelease(volEnum); + + /* Finally get user favorite places */ + if (read_bookmarks) { + UInt32 seed; + LSSharedFileListRef list = LSSharedFileListCreate( + NULL, kLSSharedFileListFavoriteItems, NULL); + CFArrayRef pathesArray = LSSharedFileListCopySnapshot(list, &seed); + CFIndex pathesCount = CFArrayGetCount(pathesArray); + + for (CFIndex i = 0; i < pathesCount; i++) { + LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex( + pathesArray, i); + + CFURLRef cfURL = NULL; + OSErr err = LSSharedFileListItemResolve(itemRef, + kLSSharedFileListNoUserInteraction | + kLSSharedFileListDoNotMountVolumes, + &cfURL, + NULL); + if (err != noErr || !cfURL) + continue; + + CFStringRef pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); + + if (pathString == NULL || + !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8)) + continue; + + /* Add end slash for consistency with other platforms */ + BLI_add_slash(line); + + /* Exclude "all my files" as it makes no sense in blender fileselector */ + /* Exclude "airdrop" if wlan not active as it would show "" ) */ + if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) { + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_LAST); + } + + CFRelease(pathString); + CFRelease(cfURL); + } + + CFRelease(pathesArray); + CFRelease(list); + } + } +# else + /* unix */ + { + const char *home = BLI_getenv("HOME"); + + if (read_bookmarks && home) { + BLI_snprintf(line, sizeof(line), "%s/", home); + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); + BLI_snprintf(line, sizeof(line), "%s/Desktop/", home); + if (BLI_exists(line)) { + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED); + } + } + + { + int found = 0; +# ifdef __linux__ + /* loop over mount points */ + struct mntent *mnt; + int len; + FILE *fp; + + fp = setmntent(MOUNTED, "r"); + if (fp == NULL) { + fprintf(stderr, "could not get a list of mounted filesystems\n"); + } + else { + while ((mnt = getmntent(fp))) { + if (STRPREFIX(mnt->mnt_dir, "/boot")) { + /* Hide share not usable to the user. */ + continue; + } + else if (!STRPREFIX(mnt->mnt_fsname, "/dev")) { + continue; + } + else if (STRPREFIX(mnt->mnt_fsname, "/dev/loop")) { + /* The dev/loop* entries are SNAPS used by desktop environment + * (Gnome) no need for them to show up in the list. */ + continue; + } + + len = strlen(mnt->mnt_dir); + if (len && mnt->mnt_dir[len - 1] != '/') { + BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir); + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, NULL, FS_INSERT_SORTED); + } + else { + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, FS_INSERT_SORTED); + } + + found = 1; + } + if (endmntent(fp) == 0) { + fprintf(stderr, "could not close the list of mounted filesystems\n"); + } + } + /* Check gvfs shares. */ + const char *const xdg_runtime_dir = BLI_getenv("XDG_RUNTIME_DIR"); + if (xdg_runtime_dir != NULL) { + struct direntry *dir; + char name[FILE_MAX]; + BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/"); + const uint dir_len = BLI_filelist_dir_contents(name, &dir); + for (uint i = 0; i < dir_len; i++) { + if ((dir[i].type & S_IFDIR)) { + const char *dirname = dir[i].relname; + if (dirname[0] != '.') { + /* Dir names contain a lot of unwanted text. + * Assuming every entry ends with the share name */ + const char *label = strstr(dirname, "share="); + if (label != NULL) { + /* Move pointer so "share=" is trimmed off + * or use full dirname as label. */ + const char *label_test = label + 6; + label = *label_test ? label_test : dirname; + } + BLI_snprintf(line, sizeof(line), "%s%s/", name, dirname); + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, label, FS_INSERT_SORTED); + found = 1; + } + } + } + BLI_filelist_free(dir, dir_len); + } +# endif + + /* fallback */ + if (!found) + fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, FS_INSERT_SORTED); + } + } +# endif #endif } - static void fsmenu_free_category(struct FSMenu *fsmenu, FSMenuCategory category) { - FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category); + FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category); - while (fsm_iter) { - FSMenuEntry *fsm_next = fsm_iter->next; + while (fsm_iter) { + FSMenuEntry *fsm_next = fsm_iter->next; - if (fsm_iter->path) { - MEM_freeN(fsm_iter->path); - } - MEM_freeN(fsm_iter); + if (fsm_iter->path) { + MEM_freeN(fsm_iter->path); + } + MEM_freeN(fsm_iter); - fsm_iter = fsm_next; - } + fsm_iter = fsm_next; + } } void fsmenu_refresh_system_category(struct FSMenu *fsmenu) { - fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM); - ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM, NULL); + fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM); + ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM, NULL); - fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); - ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, NULL); + fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); + ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, NULL); - /* Add all entries to system category */ - fsmenu_read_system(fsmenu, true); + /* Add all entries to system category */ + fsmenu_read_system(fsmenu, true); } void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu) { - int categories[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; - int i; - - for (i = sizeof(categories) / sizeof(*categories); i--; ) { - FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]); - for ( ; fsm_iter; fsm_iter = fsm_iter->next) { - fsmenu_entry_refresh_valid(fsm_iter); - } - } + int categories[] = { + FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT}; + int i; + + for (i = sizeof(categories) / sizeof(*categories); i--;) { + FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]); + for (; fsm_iter; fsm_iter = fsm_iter->next) { + fsmenu_entry_refresh_valid(fsm_iter); + } + } } void fsmenu_free(void) { - if (g_fsmenu) { - fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_BOOKMARKS); - fsmenu_free_category(g_fsmenu, FS_CATEGORY_RECENT); - MEM_freeN(g_fsmenu); - } - - g_fsmenu = NULL; + if (g_fsmenu) { + fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM); + fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS); + fsmenu_free_category(g_fsmenu, FS_CATEGORY_BOOKMARKS); + fsmenu_free_category(g_fsmenu, FS_CATEGORY_RECENT); + MEM_freeN(g_fsmenu); + } + + g_fsmenu = NULL; } int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir) { - FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category); - int i; + FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category); + int i; - for (i = 0; fsm_iter; fsm_iter = fsm_iter->next, i++) { - if (BLI_path_cmp(dir, fsm_iter->path) == 0) { - return i; - } - } + for (i = 0; fsm_iter; fsm_iter = fsm_iter->next, i++) { + if (BLI_path_cmp(dir, fsm_iter->path) == 0) { + return i; + } + } - return -1; + return -1; } diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h index f20016e6895..cb0dccf0499 100644 --- a/source/blender/editors/space_file/fsmenu.h +++ b/source/blender/editors/space_file/fsmenu.h @@ -21,7 +21,6 @@ * \ingroup spfile */ - #ifndef __FSMENU_H__ #define __FSMENU_H__ @@ -38,36 +37,42 @@ struct FSMenuEntry; * Duplicate entries are not added. * \param flag: Options for inserting the entry. */ -void fsmenu_insert_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *path, const char *name, const enum FSMenuInsert flag); +void fsmenu_insert_entry(struct FSMenu *fsmenu, + enum FSMenuCategory category, + const char *path, + const char *name, + const enum FSMenuInsert flag); /** Refresh 'valid' status of given menu entry */ void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry); /** Return whether the entry was created by the user and can be saved and deleted */ -short fsmenu_can_save(struct FSMenu *fsmenu, enum FSMenuCategory category, int index); +short fsmenu_can_save(struct FSMenu *fsmenu, enum FSMenuCategory category, int index); /** Removes the fsmenu entry at the given \a index. */ -void fsmenu_remove_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, int index); +void fsmenu_remove_entry(struct FSMenu *fsmenu, enum FSMenuCategory category, int index); /** saves the 'bookmarks' to the specified file */ -void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename); +void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename); /** reads the 'bookmarks' from the specified file */ -void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename); +void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename); /** adds system specific directories */ -void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks); +void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks); /** Free's all the memory associated with the fsmenu */ -void fsmenu_free(void); +void fsmenu_free(void); /** Refresh system directory menu */ -void fsmenu_refresh_system_category(struct FSMenu *fsmenu); +void fsmenu_refresh_system_category(struct FSMenu *fsmenu); /** Refresh 'valid' status of all menu entries */ -void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu); +void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu); /** Get active index based on given directory. */ -int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir); +int fsmenu_get_active_indices(struct FSMenu *fsmenu, + enum FSMenuCategory category, + const char *dir); #endif diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 5a4b0e36ae1..53bcf7068f4 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -26,11 +26,9 @@ #include "MEM_guardedalloc.h" - #include "BLI_blenlib.h" #include "BLI_utildefines.h" - #include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_screen.h" @@ -52,8 +50,7 @@ #include "UI_resources.h" #include "UI_view2d.h" - -#include "file_intern.h" // own include +#include "file_intern.h" // own include #include "fsmenu.h" #include "filelist.h" #include "GPU_framebuffer.h" @@ -62,653 +59,666 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - ARegion *ar; - SpaceFile *sfile; - - sfile = MEM_callocN(sizeof(SpaceFile), "initfile"); - sfile->spacetype = SPACE_FILE; - - /* header */ - ar = MEM_callocN(sizeof(ARegion), "header for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_HEADER; - /* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */ - ar->alignment = RGN_ALIGN_TOP; - - /* Tools region */ - ar = MEM_callocN(sizeof(ARegion), "tools region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOLS; - ar->alignment = RGN_ALIGN_LEFT; - - /* Tool props (aka operator) region */ - ar = MEM_callocN(sizeof(ARegion), "tool props region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOL_PROPS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - - /* ui list region */ - ar = MEM_callocN(sizeof(ARegion), "ui region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_UI; - ar->alignment = RGN_ALIGN_TOP; - - /* main region */ - ar = MEM_callocN(sizeof(ARegion), "main region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_WINDOW; - ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); - ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - ar->v2d.keeptot = V2D_KEEPTOT_STRICT; - ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; - - return (SpaceLink *)sfile; + ARegion *ar; + SpaceFile *sfile; + + sfile = MEM_callocN(sizeof(SpaceFile), "initfile"); + sfile->spacetype = SPACE_FILE; + + /* header */ + ar = MEM_callocN(sizeof(ARegion), "header for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_HEADER; + /* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */ + ar->alignment = RGN_ALIGN_TOP; + + /* Tools region */ + ar = MEM_callocN(sizeof(ARegion), "tools region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_LEFT; + + /* Tool props (aka operator) region */ + ar = MEM_callocN(sizeof(ARegion), "tool props region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOL_PROPS; + ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + + /* ui list region */ + ar = MEM_callocN(sizeof(ARegion), "ui region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_UI; + ar->alignment = RGN_ALIGN_TOP; + + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_WINDOW; + ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); + ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + ar->v2d.keeptot = V2D_KEEPTOT_STRICT; + ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; + + return (SpaceLink *)sfile; } /* not spacelink itself */ static void file_free(SpaceLink *sl) { - SpaceFile *sfile = (SpaceFile *) sl; - - BLI_assert(sfile->previews_timer == NULL); - - if (sfile->files) { - // XXXXX would need to do thumbnails_stop here, but no context available - filelist_freelib(sfile->files); - filelist_free(sfile->files); - MEM_freeN(sfile->files); - sfile->files = NULL; - } - - if (sfile->folders_prev) { - folderlist_free(sfile->folders_prev); - MEM_freeN(sfile->folders_prev); - sfile->folders_prev = NULL; - } - - if (sfile->folders_next) { - folderlist_free(sfile->folders_next); - MEM_freeN(sfile->folders_next); - sfile->folders_next = NULL; - } - - if (sfile->params) { - MEM_freeN(sfile->params); - sfile->params = NULL; - } - - if (sfile->layout) { - MEM_freeN(sfile->layout); - sfile->layout = NULL; - } + SpaceFile *sfile = (SpaceFile *)sl; + + BLI_assert(sfile->previews_timer == NULL); + + if (sfile->files) { + // XXXXX would need to do thumbnails_stop here, but no context available + filelist_freelib(sfile->files); + filelist_free(sfile->files); + MEM_freeN(sfile->files); + sfile->files = NULL; + } + + if (sfile->folders_prev) { + folderlist_free(sfile->folders_prev); + MEM_freeN(sfile->folders_prev); + sfile->folders_prev = NULL; + } + + if (sfile->folders_next) { + folderlist_free(sfile->folders_next); + MEM_freeN(sfile->folders_next); + sfile->folders_next = NULL; + } + + if (sfile->params) { + MEM_freeN(sfile->params); + sfile->params = NULL; + } + + if (sfile->layout) { + MEM_freeN(sfile->layout); + sfile->layout = NULL; + } } - /* spacetype; init callback, area size changes, screen set, etc */ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa) { - SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; + SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; - /* refresh system directory list */ - fsmenu_refresh_system_category(ED_fsmenu_get()); + /* refresh system directory list */ + fsmenu_refresh_system_category(ED_fsmenu_get()); - /* Update bookmarks 'valid' state. - * Done here, because it seems BLI_is_dir() can have huge impact on performances - * in some cases, on win systems... See T43684. - */ - fsmenu_refresh_bookmarks_status(ED_fsmenu_get()); + /* Update bookmarks 'valid' state. + * Done here, because it seems BLI_is_dir() can have huge impact on performances + * in some cases, on win systems... See T43684. + */ + fsmenu_refresh_bookmarks_status(ED_fsmenu_get()); - if (sfile->layout) sfile->layout->dirty = true; + if (sfile->layout) + sfile->layout->dirty = true; } static void file_exit(wmWindowManager *wm, ScrArea *sa) { - SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; + SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; - if (sfile->previews_timer) { - WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer); - sfile->previews_timer = NULL; - } + if (sfile->previews_timer) { + WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer); + sfile->previews_timer = NULL; + } - ED_fileselect_exit(wm, sa, sfile); + ED_fileselect_exit(wm, sa, sfile); } static SpaceLink *file_duplicate(SpaceLink *sl) { - SpaceFile *sfileo = (SpaceFile *)sl; - SpaceFile *sfilen = MEM_dupallocN(sl); + SpaceFile *sfileo = (SpaceFile *)sl; + SpaceFile *sfilen = MEM_dupallocN(sl); - /* clear or remove stuff from old */ - sfilen->op = NULL; /* file window doesn't own operators */ + /* clear or remove stuff from old */ + sfilen->op = NULL; /* file window doesn't own operators */ - sfilen->previews_timer = NULL; - sfilen->smoothscroll_timer = NULL; + sfilen->previews_timer = NULL; + sfilen->smoothscroll_timer = NULL; - if (sfileo->params) { - sfilen->files = filelist_new(sfileo->params->type); - sfilen->params = MEM_dupallocN(sfileo->params); - filelist_setdir(sfilen->files, sfilen->params->dir); - } + if (sfileo->params) { + sfilen->files = filelist_new(sfileo->params->type); + sfilen->params = MEM_dupallocN(sfileo->params); + filelist_setdir(sfilen->files, sfilen->params->dir); + } - if (sfileo->folders_prev) - sfilen->folders_prev = folderlist_duplicate(sfileo->folders_prev); + if (sfileo->folders_prev) + sfilen->folders_prev = folderlist_duplicate(sfileo->folders_prev); - if (sfileo->folders_next) - sfilen->folders_next = folderlist_duplicate(sfileo->folders_next); + if (sfileo->folders_next) + sfilen->folders_next = folderlist_duplicate(sfileo->folders_next); - if (sfileo->layout) { - sfilen->layout = MEM_dupallocN(sfileo->layout); - } - return (SpaceLink *)sfilen; + if (sfileo->layout) { + sfilen->layout = MEM_dupallocN(sfileo->layout); + } + return (SpaceLink *)sfilen; } static void file_refresh(const bContext *C, ScrArea *sa) { - wmWindowManager *wm = CTX_wm_manager(C); - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - struct FSMenu *fsmenu = ED_fsmenu_get(); - - if (!sfile->folders_prev) { - sfile->folders_prev = folderlist_new(); - } - if (!sfile->files) { - sfile->files = filelist_new(params->type); - params->highlight_file = -1; /* added this so it opens nicer (ton) */ - } - filelist_setdir(sfile->files, params->dir); - filelist_setrecursion(sfile->files, params->recursion_level); - filelist_setsorting(sfile->files, params->sort); - filelist_setfilter_options(sfile->files, (params->flag & FILE_FILTER) != 0, - (params->flag & FILE_HIDE_DOT) != 0, - false, /* TODO hide_parent, should be controllable? */ - params->filter, - params->filter_id, - params->filter_glob, - params->filter_search); - - /* Update the active indices of bookmarks & co. */ - sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir); - sfile->system_bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, params->dir); - sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir); - sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir); - - if (filelist_force_reset(sfile->files)) { - filelist_readjob_stop(wm, sa); - filelist_clear(sfile->files); - } - - if (filelist_empty(sfile->files)) { - if (!filelist_pending(sfile->files)) { - filelist_readjob_start(sfile->files, C); - } - } - - filelist_sort(sfile->files); - filelist_filter(sfile->files); - - if (params->display == FILE_IMGDISPLAY) { - filelist_cache_previews_set(sfile->files, true); - } - else { - filelist_cache_previews_set(sfile->files, false); - if (sfile->previews_timer) { - WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer); - sfile->previews_timer = NULL; - } - } - - if (params->rename_flag != 0) { - file_params_renamefile_activate(sfile, params); - } - - if (sfile->layout) { - sfile->layout->dirty = true; - } - - /* Might be called with NULL sa, see file_main_region_draw() below. */ - if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) { - /* Create TOOLS/TOOL_PROPS regions. */ - file_tools_region(sa); - - ED_area_initialize(wm, CTX_wm_window(C), sa); - } - - ED_area_tag_redraw(sa); + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_params(sfile); + struct FSMenu *fsmenu = ED_fsmenu_get(); + + if (!sfile->folders_prev) { + sfile->folders_prev = folderlist_new(); + } + if (!sfile->files) { + sfile->files = filelist_new(params->type); + params->highlight_file = -1; /* added this so it opens nicer (ton) */ + } + filelist_setdir(sfile->files, params->dir); + filelist_setrecursion(sfile->files, params->recursion_level); + filelist_setsorting(sfile->files, params->sort); + filelist_setfilter_options(sfile->files, + (params->flag & FILE_FILTER) != 0, + (params->flag & FILE_HIDE_DOT) != 0, + false, /* TODO hide_parent, should be controllable? */ + params->filter, + params->filter_id, + params->filter_glob, + params->filter_search); + + /* Update the active indices of bookmarks & co. */ + sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir); + sfile->system_bookmarknr = fsmenu_get_active_indices( + fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, params->dir); + sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir); + sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir); + + if (filelist_force_reset(sfile->files)) { + filelist_readjob_stop(wm, sa); + filelist_clear(sfile->files); + } + + if (filelist_empty(sfile->files)) { + if (!filelist_pending(sfile->files)) { + filelist_readjob_start(sfile->files, C); + } + } + + filelist_sort(sfile->files); + filelist_filter(sfile->files); + + if (params->display == FILE_IMGDISPLAY) { + filelist_cache_previews_set(sfile->files, true); + } + else { + filelist_cache_previews_set(sfile->files, false); + if (sfile->previews_timer) { + WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer); + sfile->previews_timer = NULL; + } + } + + if (params->rename_flag != 0) { + file_params_renamefile_activate(sfile, params); + } + + if (sfile->layout) { + sfile->layout->dirty = true; + } + + /* Might be called with NULL sa, see file_main_region_draw() below. */ + if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) { + /* Create TOOLS/TOOL_PROPS regions. */ + file_tools_region(sa); + + ED_area_initialize(wm, CTX_wm_window(C), sa); + } + + ED_area_tag_redraw(sa); } -static void file_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene)) +static void file_listener(wmWindow *UNUSED(win), + ScrArea *sa, + wmNotifier *wmn, + Scene *UNUSED(scene)) { - SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; - - /* context changes */ - switch (wmn->category) { - case NC_SPACE: - switch (wmn->data) { - case ND_SPACE_FILE_LIST: - ED_area_tag_refresh(sa); - break; - case ND_SPACE_FILE_PARAMS: - ED_area_tag_refresh(sa); - break; - case ND_SPACE_FILE_PREVIEW: - if (sfile->files && filelist_cache_previews_update(sfile->files)) { - ED_area_tag_refresh(sa); - } - break; - } - break; - } + SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; + + /* context changes */ + switch (wmn->category) { + case NC_SPACE: + switch (wmn->data) { + case ND_SPACE_FILE_LIST: + ED_area_tag_refresh(sa); + break; + case ND_SPACE_FILE_PARAMS: + ED_area_tag_refresh(sa); + break; + case ND_SPACE_FILE_PREVIEW: + if (sfile->files && filelist_cache_previews_update(sfile->files)) { + ED_area_tag_refresh(sa); + } + break; + } + break; + } } /* add handlers, stuff you only do once or on area/region changes */ static void file_main_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); - /* own keymaps */ - keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + /* own keymaps */ + keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap = WM_keymap_ensure(wm->defaultconf, "File Browser Main", SPACE_FILE, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + keymap = WM_keymap_ensure(wm->defaultconf, "File Browser Main", SPACE_FILE, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void file_main_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void file_main_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_SPACE: - switch (wmn->data) { - case ND_SPACE_FILE_LIST: - ED_region_tag_redraw(ar); - break; - case ND_SPACE_FILE_PARAMS: - ED_region_tag_redraw(ar); - break; - } - break; - } + /* context changes */ + switch (wmn->category) { + case NC_SPACE: + switch (wmn->data) { + case ND_SPACE_FILE_LIST: + ED_region_tag_redraw(ar); + break; + case ND_SPACE_FILE_PARAMS: + ED_region_tag_redraw(ar); + break; + } + break; + } } -static void file_main_region_message_subscribe( - const struct bContext *UNUSED(C), - struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), - struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, - struct wmMsgBus *mbus) +static void file_main_region_message_subscribe(const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), + struct Scene *UNUSED(scene), + struct bScreen *screen, + struct ScrArea *sa, + struct ARegion *ar, + struct wmMsgBus *mbus) { - SpaceFile *sfile = sa->spacedata.first; - FileSelectParams *params = ED_fileselect_get_params(sfile); - /* This is a bit odd that a region owns the subscriber for an area, - * keep for now since all subscribers for WM are regions. - * May be worth re-visiting later. */ - wmMsgSubscribeValue msg_sub_value_area_tag_refresh = { - .owner = ar, - .user_data = sa, - .notify = ED_area_do_msg_notify_tag_refresh, - }; - - /* SpaceFile itself. */ - { - PointerRNA ptr; - RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr); - - /* All properties for this space type. */ - WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); - } - - /* FileSelectParams */ - { - PointerRNA ptr; - RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr); - - /* All properties for this space type. */ - WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); - } + SpaceFile *sfile = sa->spacedata.first; + FileSelectParams *params = ED_fileselect_get_params(sfile); + /* This is a bit odd that a region owns the subscriber for an area, + * keep for now since all subscribers for WM are regions. + * May be worth re-visiting later. */ + wmMsgSubscribeValue msg_sub_value_area_tag_refresh = { + .owner = ar, + .user_data = sa, + .notify = ED_area_do_msg_notify_tag_refresh, + }; + + /* SpaceFile itself. */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } + + /* FileSelectParams */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } } static void file_main_region_draw(const bContext *C, ARegion *ar) { - /* draw entirely, view changes should be handled here */ - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - - View2D *v2d = &ar->v2d; - View2DScrollers *scrollers; - float col[3]; - - /* Needed, because filelist is not initialized on loading */ - if (!sfile->files || filelist_empty(sfile->files)) - file_refresh(C, NULL); - - /* clear and setup matrix */ - UI_GetThemeColor3fv(TH_BACK, col); - GPU_clear_color(col[0], col[1], col[2], 0.0); - GPU_clear(GPU_COLOR_BIT); - - /* Allow dynamically sliders to be set, saves notifiers etc. */ - - if (params->display == FILE_IMGDISPLAY) { - v2d->scroll = V2D_SCROLL_RIGHT; - v2d->keepofs &= ~V2D_LOCKOFS_Y; - v2d->keepofs |= V2D_LOCKOFS_X; - } - else { - v2d->scroll = V2D_SCROLL_BOTTOM; - v2d->keepofs &= ~V2D_LOCKOFS_X; - v2d->keepofs |= V2D_LOCKOFS_Y; - - /* XXX this happens on scaling down Screen (like from startup.blend) */ - /* view2d has no type specific for filewindow case, which doesn't scroll vertically */ - if (v2d->cur.ymax < 0) { - v2d->cur.ymin -= v2d->cur.ymax; - v2d->cur.ymax = 0; - } - } - /* v2d has initialized flag, so this call will only set the mask correct */ - UI_view2d_region_reinit(v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); - - /* sets tile/border settings in sfile */ - file_calc_previews(C, ar); - - /* set view */ - UI_view2d_view_ortho(v2d); - - /* on first read, find active file */ - if (params->highlight_file == -1) { - wmEvent *event = CTX_wm_window(C)->eventstate; - file_highlight_set(sfile, ar, event->x, event->y); - } - - file_draw_list(C, ar); - - /* reset view matrix */ - UI_view2d_view_restore(C); - - /* scrollers */ - scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); - UI_view2d_scrollers_draw(C, v2d, scrollers); - UI_view2d_scrollers_free(scrollers); - + /* draw entirely, view changes should be handled here */ + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_params(sfile); + + View2D *v2d = &ar->v2d; + View2DScrollers *scrollers; + float col[3]; + + /* Needed, because filelist is not initialized on loading */ + if (!sfile->files || filelist_empty(sfile->files)) + file_refresh(C, NULL); + + /* clear and setup matrix */ + UI_GetThemeColor3fv(TH_BACK, col); + GPU_clear_color(col[0], col[1], col[2], 0.0); + GPU_clear(GPU_COLOR_BIT); + + /* Allow dynamically sliders to be set, saves notifiers etc. */ + + if (params->display == FILE_IMGDISPLAY) { + v2d->scroll = V2D_SCROLL_RIGHT; + v2d->keepofs &= ~V2D_LOCKOFS_Y; + v2d->keepofs |= V2D_LOCKOFS_X; + } + else { + v2d->scroll = V2D_SCROLL_BOTTOM; + v2d->keepofs &= ~V2D_LOCKOFS_X; + v2d->keepofs |= V2D_LOCKOFS_Y; + + /* XXX this happens on scaling down Screen (like from startup.blend) */ + /* view2d has no type specific for filewindow case, which doesn't scroll vertically */ + if (v2d->cur.ymax < 0) { + v2d->cur.ymin -= v2d->cur.ymax; + v2d->cur.ymax = 0; + } + } + /* v2d has initialized flag, so this call will only set the mask correct */ + UI_view2d_region_reinit(v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); + + /* sets tile/border settings in sfile */ + file_calc_previews(C, ar); + + /* set view */ + UI_view2d_view_ortho(v2d); + + /* on first read, find active file */ + if (params->highlight_file == -1) { + wmEvent *event = CTX_wm_window(C)->eventstate; + file_highlight_set(sfile, ar, event->x, event->y); + } + + file_draw_list(C, ar); + + /* reset view matrix */ + UI_view2d_view_restore(C); + + /* scrollers */ + scrollers = UI_view2d_scrollers_calc( + C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); } static void file_operatortypes(void) { - WM_operatortype_append(FILE_OT_select); - WM_operatortype_append(FILE_OT_select_walk); - WM_operatortype_append(FILE_OT_select_all); - WM_operatortype_append(FILE_OT_select_box); - WM_operatortype_append(FILE_OT_select_bookmark); - WM_operatortype_append(FILE_OT_highlight); - WM_operatortype_append(FILE_OT_execute); - WM_operatortype_append(FILE_OT_cancel); - WM_operatortype_append(FILE_OT_parent); - WM_operatortype_append(FILE_OT_previous); - WM_operatortype_append(FILE_OT_next); - WM_operatortype_append(FILE_OT_refresh); - WM_operatortype_append(FILE_OT_bookmark_toggle); - WM_operatortype_append(FILE_OT_bookmark_add); - WM_operatortype_append(FILE_OT_bookmark_delete); - WM_operatortype_append(FILE_OT_bookmark_cleanup); - WM_operatortype_append(FILE_OT_bookmark_move); - WM_operatortype_append(FILE_OT_reset_recent); - WM_operatortype_append(FILE_OT_hidedot); - WM_operatortype_append(FILE_OT_filenum); - WM_operatortype_append(FILE_OT_directory_new); - WM_operatortype_append(FILE_OT_delete); - WM_operatortype_append(FILE_OT_rename); - WM_operatortype_append(FILE_OT_smoothscroll); - WM_operatortype_append(FILE_OT_filepath_drop); + WM_operatortype_append(FILE_OT_select); + WM_operatortype_append(FILE_OT_select_walk); + WM_operatortype_append(FILE_OT_select_all); + WM_operatortype_append(FILE_OT_select_box); + WM_operatortype_append(FILE_OT_select_bookmark); + WM_operatortype_append(FILE_OT_highlight); + WM_operatortype_append(FILE_OT_execute); + WM_operatortype_append(FILE_OT_cancel); + WM_operatortype_append(FILE_OT_parent); + WM_operatortype_append(FILE_OT_previous); + WM_operatortype_append(FILE_OT_next); + WM_operatortype_append(FILE_OT_refresh); + WM_operatortype_append(FILE_OT_bookmark_toggle); + WM_operatortype_append(FILE_OT_bookmark_add); + WM_operatortype_append(FILE_OT_bookmark_delete); + WM_operatortype_append(FILE_OT_bookmark_cleanup); + WM_operatortype_append(FILE_OT_bookmark_move); + WM_operatortype_append(FILE_OT_reset_recent); + WM_operatortype_append(FILE_OT_hidedot); + WM_operatortype_append(FILE_OT_filenum); + WM_operatortype_append(FILE_OT_directory_new); + WM_operatortype_append(FILE_OT_delete); + WM_operatortype_append(FILE_OT_rename); + WM_operatortype_append(FILE_OT_smoothscroll); + WM_operatortype_append(FILE_OT_filepath_drop); } /* NOTE: do not add .blend file reading on this level */ static void file_keymap(struct wmKeyConfig *keyconf) { - /* keys for all regions */ - WM_keymap_ensure(keyconf, "File Browser", SPACE_FILE, 0); + /* keys for all regions */ + WM_keymap_ensure(keyconf, "File Browser", SPACE_FILE, 0); - /* keys for main region */ - WM_keymap_ensure(keyconf, "File Browser Main", SPACE_FILE, 0); + /* keys for main region */ + WM_keymap_ensure(keyconf, "File Browser Main", SPACE_FILE, 0); - /* keys for button region (top) */ - WM_keymap_ensure(keyconf, "File Browser Buttons", SPACE_FILE, 0); + /* keys for button region (top) */ + WM_keymap_ensure(keyconf, "File Browser Buttons", SPACE_FILE, 0); } - static void file_tools_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE; - ED_region_panels_init(wm, ar); + ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE; + ED_region_panels_init(wm, ar); - /* own keymaps */ - keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + /* own keymaps */ + keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } static void file_tools_region_draw(const bContext *C, ARegion *ar) { - ED_region_panels(C, ar); + ED_region_panels(C, ar); } -static void file_tools_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), - wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene)) +static void file_tools_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *UNUSED(ar), + wmNotifier *UNUSED(wmn), + const Scene *UNUSED(scene)) { #if 0 - /* context changes */ - switch (wmn->category) { - /* pass */ - } + /* context changes */ + switch (wmn->category) { + /* pass */ + } #endif } /* add handlers, stuff you only do once or on area/region changes */ static void file_header_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - ED_region_header_init(ar); + ED_region_header_init(ar); - keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } static void file_header_region_draw(const bContext *C, ARegion *ar) { - ED_region_header(C, ar); + ED_region_header(C, ar); } /* add handlers, stuff you only do once or on area/region changes */ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap; + wmKeyMap *keymap; - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); - /* own keymap */ - keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + /* own keymap */ + keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap = WM_keymap_ensure(wm->defaultconf, "File Browser Buttons", SPACE_FILE, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + keymap = WM_keymap_ensure(wm->defaultconf, "File Browser Buttons", SPACE_FILE, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } static void file_ui_region_draw(const bContext *C, ARegion *ar) { - float col[3]; - /* clear */ - UI_GetThemeColor3fv(TH_BACK, col); - GPU_clear_color(col[0], col[1], col[2], 0.0); - GPU_clear(GPU_COLOR_BIT); + float col[3]; + /* clear */ + UI_GetThemeColor3fv(TH_BACK, col); + GPU_clear_color(col[0], col[1], col[2], 0.0); + GPU_clear(GPU_COLOR_BIT); - /* scrolling here is just annoying, disable it */ - ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur); - ar->v2d.cur.ymin = 0; + /* scrolling here is just annoying, disable it */ + ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur); + ar->v2d.cur.ymin = 0; - /* set view2d view matrix for scrolling (without scrollers) */ - UI_view2d_view_ortho(&ar->v2d); + /* set view2d view matrix for scrolling (without scrollers) */ + UI_view2d_view_ortho(&ar->v2d); + file_draw_buttons(C, ar); - file_draw_buttons(C, ar); - - UI_view2d_view_restore(C); + UI_view2d_view_restore(C); } -static void file_ui_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void file_ui_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_SPACE: - switch (wmn->data) { - case ND_SPACE_FILE_LIST: - ED_region_tag_redraw(ar); - break; - } - break; - } + /* context changes */ + switch (wmn->category) { + case NC_SPACE: + switch (wmn->data) { + case ND_SPACE_FILE_LIST: + ED_region_tag_redraw(ar); + break; + } + break; + } } -static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) +static bool filepath_drop_poll(bContext *C, + wmDrag *drag, + const wmEvent *UNUSED(event), + const char **UNUSED(tooltip)) { - if (drag->type == WM_DRAG_PATH) { - SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile) { - return 1; - } - } - return 0; + if (drag->type == WM_DRAG_PATH) { + SpaceFile *sfile = CTX_wm_space_file(C); + if (sfile) { + return 1; + } + } + return 0; } static void filepath_drop_copy(wmDrag *drag, wmDropBox *drop) { - RNA_string_set(drop->ptr, "filepath", drag->path); + RNA_string_set(drop->ptr, "filepath", drag->path); } /* region dropbox definition */ static void file_dropboxes(void) { - ListBase *lb = WM_dropboxmap_find("Window", SPACE_EMPTY, RGN_TYPE_WINDOW); + ListBase *lb = WM_dropboxmap_find("Window", SPACE_EMPTY, RGN_TYPE_WINDOW); - WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy); + WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy); } /* only called once, from space/spacetypes.c */ void ED_spacetype_file(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file"); - ARegionType *art; - - st->spaceid = SPACE_FILE; - strncpy(st->name, "File", BKE_ST_MAXNAME); - - st->new = file_new; - st->free = file_free; - st->init = file_init; - st->exit = file_exit; - st->duplicate = file_duplicate; - st->refresh = file_refresh; - st->listener = file_listener; - st->operatortypes = file_operatortypes; - st->keymap = file_keymap; - st->dropboxes = file_dropboxes; - - /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); - art->regionid = RGN_TYPE_WINDOW; - art->init = file_main_region_init; - art->draw = file_main_region_draw; - art->listener = file_main_region_listener; - art->message_subscribe = file_main_region_message_subscribe; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; - BLI_addhead(&st->regiontypes, art); - - /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); - art->regionid = RGN_TYPE_HEADER; - art->prefsizey = HEADERY; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; - art->init = file_header_region_init; - art->draw = file_header_region_draw; - // art->listener = file_header_region_listener; - BLI_addhead(&st->regiontypes, art); - - /* regions: ui */ - art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); - art->regionid = RGN_TYPE_UI; - art->prefsizey = 60; - art->keymapflag = ED_KEYMAP_UI; - art->listener = file_ui_region_listener; - art->init = file_ui_region_init; - art->draw = file_ui_region_draw; - BLI_addhead(&st->regiontypes, art); - - /* regions: channels (directories) */ - art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); - art->regionid = RGN_TYPE_TOOLS; - art->prefsizex = 240; - art->prefsizey = 60; - art->keymapflag = ED_KEYMAP_UI; - art->listener = file_tools_region_listener; - art->init = file_tools_region_init; - art->draw = file_tools_region_draw; - BLI_addhead(&st->regiontypes, art); - - /* regions: tool properties */ - art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region"); - art->regionid = RGN_TYPE_TOOL_PROPS; - art->prefsizex = 0; - art->prefsizey = 360; - art->keymapflag = ED_KEYMAP_UI; - art->listener = file_tools_region_listener; - art->init = file_tools_region_init; - art->draw = file_tools_region_draw; - BLI_addhead(&st->regiontypes, art); - file_panels_register(art); - - BKE_spacetype_register(st); - + SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file"); + ARegionType *art; + + st->spaceid = SPACE_FILE; + strncpy(st->name, "File", BKE_ST_MAXNAME); + + st->new = file_new; + st->free = file_free; + st->init = file_init; + st->exit = file_exit; + st->duplicate = file_duplicate; + st->refresh = file_refresh; + st->listener = file_listener; + st->operatortypes = file_operatortypes; + st->keymap = file_keymap; + st->dropboxes = file_dropboxes; + + /* regions: main window */ + art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); + art->regionid = RGN_TYPE_WINDOW; + art->init = file_main_region_init; + art->draw = file_main_region_draw; + art->listener = file_main_region_listener; + art->message_subscribe = file_main_region_message_subscribe; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; + BLI_addhead(&st->regiontypes, art); + + /* regions: header */ + art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); + art->regionid = RGN_TYPE_HEADER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; + art->init = file_header_region_init; + art->draw = file_header_region_draw; + // art->listener = file_header_region_listener; + BLI_addhead(&st->regiontypes, art); + + /* regions: ui */ + art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); + art->regionid = RGN_TYPE_UI; + art->prefsizey = 60; + art->keymapflag = ED_KEYMAP_UI; + art->listener = file_ui_region_listener; + art->init = file_ui_region_init; + art->draw = file_ui_region_draw; + BLI_addhead(&st->regiontypes, art); + + /* regions: channels (directories) */ + art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); + art->regionid = RGN_TYPE_TOOLS; + art->prefsizex = 240; + art->prefsizey = 60; + art->keymapflag = ED_KEYMAP_UI; + art->listener = file_tools_region_listener; + art->init = file_tools_region_init; + art->draw = file_tools_region_draw; + BLI_addhead(&st->regiontypes, art); + + /* regions: tool properties */ + art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region"); + art->regionid = RGN_TYPE_TOOL_PROPS; + art->prefsizex = 0; + art->prefsizey = 360; + art->keymapflag = ED_KEYMAP_UI; + art->listener = file_tools_region_listener; + art->init = file_tools_region_init; + art->draw = file_tools_region_draw; + BLI_addhead(&st->regiontypes, art); + file_panels_register(art); + + BKE_spacetype_register(st); } void ED_file_init(void) { - ED_file_read_bookmarks(); + ED_file_read_bookmarks(); - if (G.background == false) { - filelist_init_icons(); - } + if (G.background == false) { + filelist_init_icons(); + } - IMB_thumb_makedirs(); + IMB_thumb_makedirs(); } void ED_file_exit(void) { - fsmenu_free(); + fsmenu_free(); - if (G.background == false) { - filelist_free_icons(); - } + if (G.background == false) { + filelist_free_icons(); + } } void ED_file_read_bookmarks(void) { - const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); + const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); - fsmenu_free(); + fsmenu_free(); - fsmenu_read_system(ED_fsmenu_get(), true); + fsmenu_read_system(ED_fsmenu_get(), true); - if (cfgdir) { - char name[FILE_MAX]; - BLI_make_file_string("/", name, cfgdir, BLENDER_BOOKMARK_FILE); - fsmenu_read_bookmarks(ED_fsmenu_get(), name); - } + if (cfgdir) { + char name[FILE_MAX]; + BLI_make_file_string("/", name, cfgdir, BLENDER_BOOKMARK_FILE); + fsmenu_read_bookmarks(ED_fsmenu_get(), name); + } } |