From 07820b0703f9f0bbf359cf86020755e508b497bf Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 17 Nov 2023 00:11:40 +0100 Subject: [PATCH] UI: File Browser Display Narrowing Change the format of columns, and remove columns, as the File Browser window narrows. Pull Request: https://projects.blender.org/blender/blender/pulls/112464 --- source/blender/blenlib/BLI_string.h | 30 ++++++++++++++++ source/blender/blenlib/intern/BLI_filelist.cc | 17 +++++++--- source/blender/blenlib/intern/string.c | 33 ++++++++++++++++++ .../blender/editors/space_file/file_draw.cc | 34 ++++++++++++------- .../blender/editors/space_file/file_intern.hh | 7 +++- source/blender/editors/space_file/filesel.cc | 24 ++++++++----- 6 files changed, 120 insertions(+), 25 deletions(-) diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 76892c1fbdb..bb3a9407d85 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -27,6 +27,9 @@ extern "C" { /* Buffer size of maximum `int64` formatted as byte size (with GiB for example). */ #define BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE 15 +/* Buffer size of maximum `int64` formatted as byte size, minimum length (".1G" for example). */ +#define BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE 5 + /* Buffer size of maximum `int32` formatted as compact decimal size ("15.6M" for example). */ #define BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE 7 @@ -305,6 +308,33 @@ size_t BLI_str_format_uint64_grouped(char dst[BLI_STR_FORMAT_UINT64_GROUPED_SIZE void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE], long long int bytes, bool base_10) ATTR_NONNULL(1); + +/** + * Format a size in bytes using binary units in compact (max 4 chars) format. + * + * It shows a lower bound instead of rounding the number. + * + * 1 -> 1B + * 15 -> 15B + * 155 -> 155B + * 1555 -> 1K + * 15555 -> 15K + * 155555 -> .1M + * 1555555 -> 1M + * 15555555 -> 15M + * 155555555 -> .1G + * 1000000000 -> 1G + * ... + * + * \param dst: The resulting string. + * Dimension of 5 to support largest possible value for \a bytes (#LLONG_MAX). + * \param bytes: Number to format. + * \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...). + */ +void BLI_str_format_byte_unit_compact(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE], + long long int bytes, + bool base_10) ATTR_NONNULL(1); + /** * Format a count to up to 6 places (plus `\0` terminator) string using long number * names abbreviations. Used to produce a compact representation of large numbers. diff --git a/source/blender/blenlib/intern/BLI_filelist.cc b/source/blender/blenlib/intern/BLI_filelist.cc index c3da3ae9353..7f23be0f6a7 100644 --- a/source/blender/blenlib/intern/BLI_filelist.cc +++ b/source/blender/blenlib/intern/BLI_filelist.cc @@ -249,8 +249,7 @@ uint BLI_filelist_dir_contents(const char *dirname, direntry **r_filelist) void BLI_filelist_entry_size_to_string(const struct stat *st, const uint64_t st_size_fallback, - /* Used to change MB -> M, etc. - is that really useful? */ - const bool /*compact*/, + const bool compact, char r_size[FILELIST_DIRENTRY_SIZE_LEN]) { /* @@ -260,9 +259,19 @@ void BLI_filelist_entry_size_to_string(const struct stat *st, */ double size = double(st ? st->st_size : st_size_fallback); #ifdef WIN32 - BLI_str_format_byte_unit(r_size, size, false); + if (compact) { + BLI_str_format_byte_unit_compact(r_size, size, false); + } + else { + BLI_str_format_byte_unit(r_size, size, false); + } #else - BLI_str_format_byte_unit(r_size, size, true); + if (compact) { + BLI_str_format_byte_unit_compact(r_size, size, true); + } + else { + BLI_str_format_byte_unit(r_size, size, true); + } #endif } diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 178e1b7f632..1a957fb89fe 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1199,6 +1199,39 @@ void BLI_str_format_byte_unit(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_SIZE], BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_maxncpy - len); } +void BLI_str_format_byte_unit_compact(char dst[BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE], + long long int bytes, + const bool base_10) +{ + const size_t dst_maxncpy = BLI_STR_FORMAT_INT64_BYTE_UNIT_COMPACT_SIZE; + BLI_string_debug_size(dst, dst_maxncpy); + + float number_to_format_converted = (float)bytes; + int order = 0; + const int base = base_10 ? 1000 : 1024; + const char *units[] = {"B", "K", "M", "G", "T", "P"}; + const int units_num = ARRAY_SIZE(units); + + while ((fabsf(number_to_format_converted) >= base) && ((order + 1) < units_num)) { + number_to_format_converted /= (float)base; + order++; + } + + const bool add_dot = (llabs(bytes) > 99999) && fabsf(number_to_format_converted) > 99; + + if (add_dot) { + number_to_format_converted /= 100.0f; + order++; + } + + BLI_snprintf(dst, + dst_maxncpy, + "%s%d%s", + add_dot ? "." : "", + (int)floorf(fabsf(number_to_format_converted)), + units[order]); +} + void BLI_str_format_decimal_unit(char dst[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE], int number_to_format) { diff --git a/source/blender/editors/space_file/file_draw.cc b/source/blender/editors/space_file/file_draw.cc index 1f720c8f706..ec78de51171 100644 --- a/source/blender/editors/space_file/file_draw.cc +++ b/source/blender/editors/space_file/file_draw.cc @@ -743,7 +743,8 @@ static void draw_columnheader_columns(const FileSelectParams *params, int sx = v2d->cur.xmin, sy = v2d->cur.ymax; for (int column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; column_type++) { - if (!file_attribute_column_type_enabled(params, FileAttributeColumnType(column_type))) { + if (!file_attribute_column_type_enabled(params, FileAttributeColumnType(column_type), layout)) + { continue; } const FileAttributeColumn *column = &layout->attribute_columns[column_type]; @@ -806,22 +807,24 @@ static void draw_columnheader_columns(const FileSelectParams *params, static const char *filelist_get_details_column_string( FileAttributeColumnType column, /* Generated string will be cached in the file, so non-const. */ - FileDirEntry *file) + FileDirEntry *file, + const bool compact, + const bool update_stat_strings) { switch (column) { case COLUMN_DATETIME: if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) { - if (file->draw_data.datetime_str[0] == '\0') { + if (file->draw_data.datetime_str[0] == '\0' || update_stat_strings) { char date[FILELIST_DIRENTRY_DATE_LEN], time[FILELIST_DIRENTRY_TIME_LEN]; bool is_today, is_yesterday; BLI_filelist_entry_datetime_to_string( - nullptr, file->time, false, time, date, &is_today, &is_yesterday); + nullptr, file->time, compact, time, date, &is_today, &is_yesterday); - if (is_today || is_yesterday) { + if (!compact && (is_today || is_yesterday)) { STRNCPY(date, is_today ? IFACE_("Today") : IFACE_("Yesterday")); } - SNPRINTF(file->draw_data.datetime_str, "%s %s", date, time); + SNPRINTF(file->draw_data.datetime_str, compact ? "%s" : "%s %s", date, time); } return file->draw_data.datetime_str; @@ -831,8 +834,9 @@ static const char *filelist_get_details_column_string( if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { - if (file->draw_data.size_str[0] == '\0') { - BLI_filelist_entry_size_to_string(nullptr, file->size, false, file->draw_data.size_str); + if (file->draw_data.size_str[0] == '\0' || update_stat_strings) { + BLI_filelist_entry_size_to_string( + nullptr, file->size, compact, file->draw_data.size_str); } return file->draw_data.size_str; @@ -851,6 +855,8 @@ static void draw_details_columns(const FileSelectParams *params, const rcti *tile_draw_rect, const uchar text_col[4]) { + const bool compact = FILE_LAYOUT_COMPACT(layout); + const bool update_stat_strings = layout->width != layout->curr_size; int sx = tile_draw_rect->xmin - layout->tile_border_x - (UI_UNIT_X * 0.1f); for (int column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; column_type++) { @@ -861,12 +867,13 @@ static void draw_details_columns(const FileSelectParams *params, sx += column->width; continue; } - if (!file_attribute_column_type_enabled(params, FileAttributeColumnType(column_type))) { + if (!file_attribute_column_type_enabled(params, FileAttributeColumnType(column_type), layout)) + { continue; } - const char *str = filelist_get_details_column_string(FileAttributeColumnType(column_type), - file); + const char *str = filelist_get_details_column_string( + FileAttributeColumnType(column_type), file, compact, update_stat_strings); if (str) { file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING, @@ -1170,7 +1177,10 @@ void file_draw_list(const bContext *C, ARegion *region) draw_columnheader_columns(params, layout, v2d, text_col); } - layout->curr_size = params->thumbnail_size; + if (numfiles != -1) { + /* Only save current size if there is something to show. */ + layout->curr_size = layout->width; + } } static void file_draw_invalid_asset_library_hint(const bContext *C, diff --git a/source/blender/editors/space_file/file_intern.hh b/source/blender/editors/space_file/file_intern.hh index a1cde9d263a..ff79ec9174e 100644 --- a/source/blender/editors/space_file/file_intern.hh +++ b/source/blender/editors/space_file/file_intern.hh @@ -36,6 +36,10 @@ int /*eContextResult*/ file_context(const bContext *C, #define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X) +#define FILE_LAYOUT_COMPACT(_layout) ((_layout->width / UI_SCALE_FAC) < 500) +#define FILE_LAYOUT_HIDE_DATE(_layout) ((_layout->width / UI_SCALE_FAC) < 250) +#define FILE_LAYOUT_HIDE_SIZE(_layout) ((_layout->width / UI_SCALE_FAC) < 350) + void file_calc_previews(const bContext *C, ARegion *region); void file_draw_list(const bContext *C, ARegion *region); /** @@ -122,7 +126,8 @@ void fileselect_refresh_params(SpaceFile *sfile); */ void fileselect_file_set(bContext *C, SpaceFile *sfile, int index); bool file_attribute_column_type_enabled(const FileSelectParams *params, - FileAttributeColumnType column); + FileAttributeColumnType column, + const FileLayout *layout); /** * Check if the region coordinate defined by \a x and \a y are inside the column header. */ diff --git a/source/blender/editors/space_file/filesel.cc b/source/blender/editors/space_file/filesel.cc index 0699fe9f1da..b770e2e88a0 100644 --- a/source/blender/editors/space_file/filesel.cc +++ b/source/blender/editors/space_file/filesel.cc @@ -893,16 +893,18 @@ bool file_attribute_column_header_is_inside(const View2D *v2d, } bool file_attribute_column_type_enabled(const FileSelectParams *params, - FileAttributeColumnType column) + FileAttributeColumnType column, + const FileLayout *layout) { switch (column) { case COLUMN_NAME: /* Always enabled */ return true; case COLUMN_DATETIME: - return (params->details_flags & FILE_DETAILS_DATETIME) != 0; + return ((params->details_flags & FILE_DETAILS_DATETIME) != 0) && + !FILE_LAYOUT_HIDE_DATE(layout); case COLUMN_SIZE: - return (params->details_flags & FILE_DETAILS_SIZE) != 0; + return ((params->details_flags & FILE_DETAILS_SIZE) != 0) && !FILE_LAYOUT_HIDE_SIZE(layout); default: return false; } @@ -932,7 +934,7 @@ FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, column < ATTRIBUTE_COLUMN_MAX; column = FileAttributeColumnType(int(column) + 1)) { - if (!file_attribute_column_type_enabled(params, column)) { + if (!file_attribute_column_type_enabled(params, column, layout)) { continue; } const int width = layout->attribute_columns[column].width; @@ -975,14 +977,16 @@ static void file_attribute_columns_widths(const FileSelectParams *params, FileLa { FileAttributeColumn *columns = layout->attribute_columns; const int pad = ATTRIBUTE_COLUMN_PADDING * 2; + const bool compact = FILE_LAYOUT_COMPACT(layout); for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; i++) { layout->attribute_columns[i].width = 0; } /* Biggest possible reasonable values... */ - columns[COLUMN_DATETIME].width = file_string_width("23 Dec 6789, 23:59") + pad; - columns[COLUMN_SIZE].width = file_string_width("098.7 MiB") + pad; + columns[COLUMN_DATETIME].width = file_string_width(compact ? "23/08/89" : "23 Dec 6789, 23:59") + + pad; + columns[COLUMN_SIZE].width = file_string_width(compact ? "369G" : "098.7 MiB") + pad; if (params->display == FILE_IMGDISPLAY) { columns[COLUMN_NAME].width = (float(params->thumbnail_size) / 8.0f) * UI_UNIT_X; } @@ -994,7 +998,8 @@ static void file_attribute_columns_widths(const FileSelectParams *params, FileLa column_type >= 0; column_type = FileAttributeColumnType(int(column_type) - 1)) { - if ((column_type == COLUMN_NAME) || !file_attribute_column_type_enabled(params, column_type)) + if ((column_type == COLUMN_NAME) || + !file_attribute_column_type_enabled(params, column_type, layout)) { continue; } @@ -1011,7 +1016,10 @@ static void file_attribute_columns_init(const FileSelectParams *params, FileLayo layout->attribute_columns[COLUMN_NAME].name = N_("Name"); layout->attribute_columns[COLUMN_NAME].sort_type = FILE_SORT_ALPHA; layout->attribute_columns[COLUMN_NAME].text_align = UI_STYLE_TEXT_LEFT; - layout->attribute_columns[COLUMN_DATETIME].name = N_("Date Modified"); + + const bool compact = FILE_LAYOUT_COMPACT(layout); + layout->attribute_columns[COLUMN_DATETIME].name = compact ? N_("Date") : N_("Date Modified"); + layout->attribute_columns[COLUMN_DATETIME].sort_type = FILE_SORT_TIME; layout->attribute_columns[COLUMN_DATETIME].text_align = UI_STYLE_TEXT_LEFT; layout->attribute_columns[COLUMN_SIZE].name = N_("Size");