Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2022-07-21 15:55:18 +0300
committerJulian Eisel <julian@blender.org>2022-07-21 18:16:10 +0300
commit3a97c4056f8b9f663150a988b9aa9647517c33ed (patch)
treec4a2f6eecefb9a09b092e162284c8aba79674d90
parent9dbcefb10e53cc809eb2e99333376b2a881c0863 (diff)
Proof of Concept: File Browser thumbnail mode using grid viewfile-browser-grid-view
This was meant as an experiment to see how tangible it is to rewrite the File Browser UI code to be based on views, starting with the grid view for thumbnail mode. See T99890. My initial conclusion is that porting to views is quite doable, but we'll need some further UI code features to make certain things possible. Like big "composed" icons, where a file type icon is displayed on top of a big, generic file icon. There is a fair bit of stuff here that I'm not happy with. Plus things like selection, double clicking to open and renaming don't work yet. It's a start, a proof of concept even :)
-rw-r--r--source/blender/blenkernel/BKE_icons.h2
-rw-r--r--source/blender/editors/include/UI_grid_view.hh6
-rw-r--r--source/blender/editors/include/UI_interface.h10
-rw-r--r--source/blender/editors/include/UI_interface_icons.h3
-rw-r--r--source/blender/editors/interface/interface.cc55
-rw-r--r--source/blender/editors/interface/interface_icons.c26
-rw-r--r--source/blender/editors/interface/interface_intern.h3
-rw-r--r--source/blender/editors/interface/interface_widgets.c56
-rw-r--r--source/blender/editors/interface/views/grid_view.cc36
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_file/file_draw.c37
-rw-r--r--source/blender/editors/space_file/file_intern.h8
-rw-r--r--source/blender/editors/space_file/file_view_grid.cc190
-rw-r--r--source/blender/editors/space_file/filelist.c5
-rw-r--r--source/blender/editors/space_file/filelist.h1
-rw-r--r--source/blender/editors/space_file/space_file.c8
16 files changed, 400 insertions, 47 deletions
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 8d9351806c4..4ab3a2ac904 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -77,7 +77,9 @@ struct PreviewImage;
struct StudioLight;
struct bGPDlayer;
+#ifndef __cplusplus
enum eIconSizes;
+#endif
void BKE_icons_init(int first_dyn_id);
diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
index 402c0c8512f..2d5b5f941ed 100644
--- a/source/blender/editors/include/UI_grid_view.hh
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -194,7 +194,11 @@ class PreviewGridItem : public AbstractGridViewItem {
std::string label{};
int preview_icon_id = ICON_NONE;
- PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id);
+ PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id = ICON_NONE);
+
+ uiBut *add_preview_button(uiLayout &layout,
+ int preview_icon_id,
+ const uchar mono_color[4] = nullptr) const;
void build_grid_tile(uiLayout &layout) const override;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index a8d25b75036..20f2a553a52 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1228,6 +1228,15 @@ uiBut *uiDefIconButO_ptr(uiBlock *block,
short width,
short height,
const char *tip);
+uiBut *uiDefButPadding(uiBlock *block, int x, int y, short width, short height);
+uiBut *uiDefButPreviewTile(uiBlock *block,
+ int preview_icon_id,
+ const char *label,
+ int x,
+ int y,
+ short width,
+ short height,
+ const uchar mono_color[4]);
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]);
uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height);
@@ -1746,6 +1755,7 @@ struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon
int UI_preview_tile_size_x(void);
int UI_preview_tile_size_y(void);
int UI_preview_tile_size_y_no_label(void);
+rcti UI_preview_tile_but_preview_rect_get(const uiBut *but);
/* Autocomplete
*
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index a1a98a4b08c..1cfec698680 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -96,7 +96,8 @@ int UI_icon_preview_to_render_size(enum eIconSizes size);
*/
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
-void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size);
+void UI_icon_draw_preview(
+ float x, float y, int icon_id, float aspect, float alpha, int size, const uchar mono_color[4]);
void UI_icon_draw_ex(float x,
float y,
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index 2f9e69137ed..b6d212b891e 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -4826,6 +4826,37 @@ uiBut *uiDefBut(uiBlock *block,
return but;
}
+uiBut *uiDefButPadding(uiBlock *block, int x, int y, short width, short height)
+{
+ uiBut *but = ui_def_but(
+ block, UI_BTYPE_LABEL, 0, "", x, y, width, height, nullptr, 0, 0, 0, 0, "");
+ ui_but_update(but);
+ return but;
+}
+
+uiBut *uiDefButPreviewTile(uiBlock *block,
+ int preview_icon_id,
+ const char *label,
+ int x,
+ int y,
+ short width,
+ short height,
+ const uchar mono_color[4])
+{
+ uiBut *but = ui_def_but(
+ block, UI_BTYPE_PREVIEW_TILE, 0, label, x, y, width, height, nullptr, 0, 0, 0, 0, "");
+ ui_def_but_icon(but,
+ preview_icon_id,
+ /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ if (mono_color) {
+ copy_v4_v4_uchar(but->col, mono_color);
+ }
+
+ ui_but_update(but);
+ return but;
+}
+
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4])
{
@@ -4993,6 +5024,30 @@ int UI_preview_tile_size_y_no_label(void)
return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y + 2.0f * pad);
}
+#define PREVIEW_PAD 4
+
+rcti UI_preview_tile_but_preview_rect_get(const uiBut *but)
+{
+ rcti rect;
+
+ BLI_rcti_rctf_copy_round(&rect, &but->rect);
+
+ if (but->drawstr[0]) {
+ const uiStyle *style = UI_style_get();
+ const uiFontStyle *fstyle = &style->widget;
+ float font_dims[2] = {0.0f, 0.0f};
+
+ UI_fontstyle_set(fstyle);
+ BLF_width_and_height(
+ fstyle->uifont_id, but->drawstr, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
+ /* draw icon in rect above the space reserved for the label */
+ rect.ymin += round_fl_to_int(font_dims[1] + 2 * PREVIEW_PAD);
+ }
+
+ return ui_preview_draw_rect_get(&rect);
+}
+
+#undef PREVIEW_PAD
#undef PREVIEW_TILE_PAD
static void ui_but_update_and_icon_set(uiBut *but, int icon)
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c19e842aad8..71bd61764c0 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1503,6 +1503,7 @@ static void icon_draw_rect(float x,
int rh,
uint *rect,
float alpha,
+ const uchar mono_rgba[4],
const float desaturate)
{
int draw_w = w;
@@ -1518,7 +1519,12 @@ static void icon_draw_rect(float x,
return;
}
/* modulate color */
- const float col[4] = {alpha, alpha, alpha, alpha};
+ float col[4] = {alpha, alpha, alpha, alpha};
+ if (mono_rgba) {
+ /* Optionally use a mono color to recolor the image. */
+ rgba_uchar_to_float(col, mono_rgba);
+ mul_v4_fl(col, alpha);
+ }
float scale_x = 1.0f;
float scale_y = 1.0f;
@@ -1813,9 +1819,10 @@ static void icon_draw_size(float x,
if (di->type == ICON_TYPE_IMBUF) {
ImBuf *ibuf = icon->obj;
- GPU_blend(GPU_BLEND_ALPHA_PREMULT);
- icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate);
- GPU_blend(GPU_BLEND_ALPHA);
+ /* TODO preview images are premultiplied apparently (see ICON_TYPE_PREVIEW). */
+ // GPU_blend(GPU_BLEND_ALPHA_PREMULT);
+ icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, mono_rgba, desaturate);
+ // GPU_blend(GPU_BLEND_ALPHA);
}
else if (di->type == ICON_TYPE_VECTOR) {
/* vector icons use the uiBlock transformation, they are not drawn
@@ -1854,7 +1861,7 @@ static void icon_draw_size(float x,
}
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
- icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, desaturate);
+ icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, NULL, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
}
else if (di->type == ICON_TYPE_EVENT) {
@@ -1922,7 +1929,7 @@ static void icon_draw_size(float x,
return;
}
- icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate);
+ icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, NULL, desaturate);
}
else if (di->type == ICON_TYPE_PREVIEW) {
PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
@@ -1938,7 +1945,7 @@ static void icon_draw_size(float x,
/* Preview images use premultiplied alpha. */
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
icon_draw_rect(
- x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, desaturate);
+ x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, NULL, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
}
}
@@ -2433,9 +2440,10 @@ void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
}
-void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
+void UI_icon_draw_preview(
+ float x, float y, int icon_id, float aspect, float alpha, int size, const uchar mono_color[4])
{
- icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false);
+ icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, 0.0f, mono_color, false);
}
void UI_icon_draw_ex(float x,
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 03b9d03a6e3..ade238a86ef 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -1236,6 +1236,8 @@ void ui_draw_preview_item(const struct uiFontStyle *fstyle,
int iconid,
int but_flag,
eFontStyle_Align text_align);
+rcti ui_preview_draw_rect_get(const rcti *bounds_rect);
+
/**
* Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
* state. It just draws the preview and text directly.
@@ -1245,6 +1247,7 @@ void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
const char *name,
int iconid,
const uchar text_col[4],
+ const uchar mono_col[4],
eFontStyle_Align text_align);
#define UI_TEXT_MARGIN_X 0.4f
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index c939ba461c9..b0400f687aa 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1316,22 +1316,40 @@ static float widget_alpha_factor(const uiWidgetStateInfo *state)
return 1.0f;
}
-static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
+rcti ui_preview_draw_rect_get(const rcti *bounds_rect)
{
- if (icon == ICON_NONE) {
- return;
+ const int max_width = BLI_rcti_size_x(bounds_rect);
+ const int max_height = BLI_rcti_size_y(bounds_rect);
+
+ rcti rect = {0};
+
+ const int draw_size = MIN2(max_width, max_height) - PREVIEW_PAD * 2;
+ if (draw_size > 0) {
+ rect.xmin = bounds_rect->xmin + max_width / 2 - draw_size / 2;
+ rect.ymin = bounds_rect->ymin + max_height / 2 - draw_size / 2;
+ rect.xmax = rect.xmin + draw_size;
+ rect.ymax = rect.ymin + draw_size;
}
- const int w = BLI_rcti_size_x(rect);
- const int h = BLI_rcti_size_y(rect);
- const int size = MIN2(w, h) - PREVIEW_PAD * 2;
+ return rect;
+}
- if (size > 0) {
- const int x = rect->xmin + w / 2 - size / 2;
- const int y = rect->ymin + h / 2 - size / 2;
+static void widget_draw_preview(BIFIconID icon,
+ float alpha,
+ const rcti *rect,
+ const uchar mono_color[4])
+{
+ if (icon == ICON_NONE) {
+ return;
+ }
- UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size);
+ const rcti draw_rect = ui_preview_draw_rect_get(rect);
+ if (BLI_rcti_is_empty(&draw_rect)) {
+ return;
}
+
+ UI_icon_draw_preview(
+ draw_rect.xmin, draw_rect.ymin, icon, 1.0f, alpha, BLI_rcti_size_x(&draw_rect), mono_color);
}
static int ui_but_draw_menu_icon(const uiBut *but)
@@ -1346,7 +1364,7 @@ static void widget_draw_icon(
{
if (but->flag & UI_BUT_ICON_PREVIEW) {
GPU_blend(GPU_BLEND_ALPHA);
- widget_draw_preview(icon, alpha, rect);
+ widget_draw_preview(icon, alpha, rect, mono_color);
GPU_blend(GPU_BLEND_NONE);
return;
}
@@ -2313,7 +2331,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
GPU_blend(GPU_BLEND_ALPHA);
- widget_draw_preview(icon, alpha, rect);
+ widget_draw_preview(icon, alpha, rect, but->col[3] != 0 ? but->col : NULL);
GPU_blend(GPU_BLEND_NONE);
/* offset rect to draw label in */
@@ -4002,8 +4020,13 @@ static void widget_preview_tile(uiBut *but,
const float UNUSED(zoom))
{
const uiStyle *style = UI_style_get();
- ui_draw_preview_item_stateless(
- &style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
+ ui_draw_preview_item_stateless(&style->widget,
+ rect,
+ but->drawstr,
+ but->icon,
+ wcol->text,
+ but->col[3] ? but->col : NULL,
+ UI_STYLE_TEXT_CENTER);
}
static void widget_menuiconbut(uiWidgetColors *wcol,
@@ -5510,6 +5533,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
const char *name,
int iconid,
const uchar text_col[4],
+ const uchar mono_col[4],
eFontStyle_Align text_align)
{
rcti trect = *rect;
@@ -5526,7 +5550,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rect->ymin += round_fl_to_int(font_dims[1] + 2 * padding);
}
GPU_blend(GPU_BLEND_ALPHA);
- widget_draw_preview(iconid, 1.0f, rect);
+ widget_draw_preview(iconid, 1.0f, rect, mono_col);
GPU_blend(GPU_BLEND_NONE);
if (!has_text) {
@@ -5573,7 +5597,7 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
- ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
+ ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, NULL, text_align);
}
/** \} */
diff --git a/source/blender/editors/interface/views/grid_view.cc b/source/blender/editors/interface/views/grid_view.cc
index 52ff1460cbd..edc33fcf944 100644
--- a/source/blender/editors/interface/views/grid_view.cc
+++ b/source/blender/editors/interface/views/grid_view.cc
@@ -8,6 +8,7 @@
#include <stdexcept>
#include "BLI_index_range.hh"
+#include "BLI_math_vector.h"
#include "WM_types.h"
@@ -410,29 +411,26 @@ PreviewGridItem::PreviewGridItem(StringRef identifier, StringRef label, int prev
{
}
-void PreviewGridItem::build_grid_tile(uiLayout &layout) const
+uiBut *PreviewGridItem::add_preview_button(uiLayout &layout,
+ const int preview_icon_id,
+ const uchar mono_color[4]) const
{
const GridViewStyle &style = get_view().get_style();
uiBlock *block = uiLayoutGetBlock(&layout);
- uiBut *but = uiDefBut(block,
- UI_BTYPE_PREVIEW_TILE,
- 0,
- label.c_str(),
- 0,
- 0,
- style.tile_width,
- style.tile_height,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
- ui_def_but_icon(but,
- preview_icon_id,
- /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
- UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ return uiDefButPreviewTile(block,
+ preview_icon_id,
+ label.c_str(),
+ 0,
+ 0,
+ style.tile_width,
+ style.tile_height,
+ mono_color);
+}
+
+void PreviewGridItem::build_grid_tile(uiLayout &layout) const
+{
+ add_preview_button(layout, preview_icon_id);
}
void PreviewGridItem::set_on_activate_fn(ActivateFn fn)
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index b8c28e354da..e932feef2aa 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SRC
file_ops.c
file_panels.c
file_utils.c
+ file_view_grid.cc
filelist.c
filesel.c
fsmenu.c
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index f3359336b14..8a0f40f9045 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -1161,3 +1161,40 @@ bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegio
return true;
}
+
+void file_view_preview_grid_draw(const bContext *C, ARegion *region)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ // bScreen *screen = CTX_wm_screen(C);
+ View2D *v2d = &region->v2d;
+
+ const uiStyle *style = UI_style_get_dpi();
+ const float padding = style->panelouter;
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ uiLayout *layout = UI_block_layout(
+ block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ padding,
+ -padding,
+ /* 3x (instead of 2x) padding to add extra space for the scrollbar on the right. */
+ region->winx - 3 * padding,
+ 1,
+ 0,
+ style);
+
+ // PointerRNA asset_space_ptr;
+ // RNA_pointer_create(&screen->id, &RNA_SpaceAssetBrowser, asset_space, &asset_space_ptr);
+ // PropertyRNA *active_asset_idx_prop = RNA_struct_find_property(&asset_space_ptr,
+ // "active_asset_idx");
+
+ file_grid_view_create_in_layout(sfile->files, v2d, layout);
+
+ /* Update main region View2d dimensions. */
+ int layout_width, layout_height;
+ UI_block_layout_resolve(block, &layout_width, &layout_height);
+ UI_view2d_totRect_set(v2d, layout_width, layout_height);
+
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
+}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index ce0a2e8fc04..50493b4865c 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -19,6 +19,7 @@ struct ARegion;
struct ARegionType;
struct AssetLibrary;
struct FileAssetSelectParams;
+struct FileList;
struct FileSelectParams;
struct SpaceFile;
struct View2D;
@@ -38,6 +39,7 @@ void file_draw_list(const bContext *C, ARegion *region);
* \return true if the list is invalid and a hint was drawn.
*/
bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region);
+void file_view_preview_grid_draw(const bContext *C, ARegion *region);
void file_draw_check_ex(bContext *C, struct ScrArea *area);
void file_draw_check(bContext *C);
@@ -196,6 +198,12 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rct
*/
void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
+/* file_view_grid.cc */
+
+void file_grid_view_create_in_layout(struct FileList *files,
+ const View2D *v2d,
+ struct uiLayout *layout);
+
/* asset_catalog_tree_view.cc */
void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
diff --git a/source/blender/editors/space_file/file_view_grid.cc b/source/blender/editors/space_file/file_view_grid.cc
new file mode 100644
index 00000000000..348ec921e0c
--- /dev/null
+++ b/source/blender/editors/space_file/file_view_grid.cc
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spfile
+ */
+
+#include "DNA_ID_enums.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_icons.h"
+
+#include "BLI_fileops.h"
+#include "BLI_math_vector.h"
+#include "BLI_rect.h"
+
+/* TODO temp for static ImBuf -> icon_id map. */
+#include "BLI_map.hh"
+#include "IMB_imbuf.h"
+
+#include "ED_fileselect.h"
+
+#include "UI_grid_view.hh"
+#include "UI_interface.h"
+#include "UI_interface.hh"
+
+#include "file_intern.h"
+#include "filelist.h"
+
+namespace blender::ed::file_browser {
+
+class FilePreviewGridView : public ui::AbstractGridView {
+ friend class FilePreviewGridItem;
+
+ FileList &files_;
+
+ public:
+ FilePreviewGridView(FileList &filelist);
+ void build_items() override;
+
+ BIFIconID file_preview_icon_id_get(const FileDirEntry &file);
+};
+
+class FilePreviewGridItem : public ui::PreviewGridItem {
+ const FileDirEntry &file_;
+ std::string file_identifier_;
+ /* Index in the file list. */
+ const int file_idx_;
+
+ public:
+ FilePreviewGridItem(const FileDirEntry &file, int file_idx);
+
+ void build_grid_tile(uiLayout &layout) const override;
+
+ FileList &get_file_list() const;
+ void icon_mono_color_get(uchar r_mono_color[4]);
+ void add_big_combined_file_icon(uiLayout &overlap) const;
+};
+
+FilePreviewGridView::FilePreviewGridView(FileList &files) : files_(files)
+{
+}
+
+void FilePreviewGridView::build_items()
+{
+
+ const int numfiles = filelist_files_ensure(&files_);
+
+ for (int file_idx = 0; file_idx < numfiles; file_idx++) {
+ const FileDirEntry *file = filelist_file(&files_, file_idx);
+
+ add_item<FilePreviewGridItem>(*file, file_idx);
+ }
+}
+
+FilePreviewGridItem::FilePreviewGridItem(const FileDirEntry &file, const int file_idx)
+ : ui::PreviewGridItem(file.relpath, file.name),
+ file_(file),
+ /* Get a copy so the identifier is always available (the file data may be freed). */
+ file_identifier_(identifier_),
+ file_idx_(file_idx)
+{
+ /* Update reference so we don't point into the possibly freed file data. */
+ /* TODO always store the identifier as std::string in the item base class? Avoids these issues.
+ */
+ identifier_ = file_identifier_;
+}
+
+FileList &FilePreviewGridItem::get_file_list() const
+{
+ const FilePreviewGridView &view = dynamic_cast<const FilePreviewGridView &>(get_view());
+ return view.files_;
+}
+
+static BIFIconID file_big_file_icon_get(const FileDirEntry &file)
+{
+ /* TODO temp!! Needs proper lifetime/memory management */
+ static Map<const ImBuf *, BIFIconID> imbuf_icon_map;
+
+ ImBuf *imb = filelist_file_geticon_image(&file);
+ return imbuf_icon_map.lookup_or_add_cb(imb,
+ [&]() { return (BIFIconID)BKE_icon_imbuf_create(imb); });
+}
+
+static void file_icon_mono_color_get(const FileDirEntry &file, uchar r_col[4])
+{
+ uchar col[4] = {255, 255, 255, 255};
+ if (file.typeflag & FILE_TYPE_DIR) {
+ UI_GetThemeColor4ubv(TH_ICON_FOLDER, col);
+ }
+ else {
+ UI_GetThemeColor4ubv(TH_TEXT, col);
+ }
+
+ const bool is_hidden = (file.attributes & FILE_ATTR_HIDDEN);
+ if (is_hidden) {
+ col[3] *= 0.3f;
+ }
+
+ copy_v4_v4_uchar(r_col, col);
+}
+
+void FilePreviewGridItem::add_big_combined_file_icon(uiLayout &layout) const
+{
+ uiLayout *overlap = uiLayoutOverlap(&layout);
+
+ BIFIconID file_icon_id = file_big_file_icon_get(file_);
+ uiBut *preview_but = nullptr;
+ if (file_icon_id != ICON_NONE) {
+ uchar mono_col[4];
+ file_icon_mono_color_get(file_, mono_col);
+
+ preview_but = add_preview_button(*overlap, file_icon_id, mono_col);
+ }
+
+ /* Smaller file type icon in the middle of image, scaled to fit container and UI scale */
+ {
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
+ }
+ icon_color[3] *= icon_opacity;
+
+ FileList &files = get_file_list();
+ const int icon_id = filelist_geticon(&files, file_idx_, false);
+
+ // uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_CENTER);
+ const ui::GridViewStyle &style = get_view().get_style();
+ int icon_size = style.tile_width / 3.5f;
+
+ uiLayout *col = uiLayoutColumn(overlap, false);
+ uiBlock *block = uiLayoutGetBlock(col);
+
+ /* Add padding to vertically center the icon. */
+ const rcti preview_img_rect = UI_preview_tile_but_preview_rect_get(preview_but);
+ const int icon_ofs_y = style.tile_height - BLI_rcti_cent_y(&preview_img_rect) -
+ (icon_size * ((file_.typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)) / 2;
+ uiDefButPadding(block, 0, 0, 0, icon_ofs_y);
+ uiDefButPreviewTile(block, icon_id, "", 0, 0, icon_size, icon_size, icon_color);
+ }
+}
+
+void FilePreviewGridItem::build_grid_tile(uiLayout &layout) const
+{
+ uiLayout &overlap = *uiLayoutOverlap(&layout);
+ add_big_combined_file_icon(overlap);
+}
+
+} // namespace blender::ed::file_browser
+
+namespace ui = blender::ui;
+using namespace blender::ed::file_browser;
+
+void file_grid_view_create_in_layout(FileList *files, const View2D *v2d, uiLayout *layout)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ UI_block_layout_set_current(block, layout);
+
+ ui::AbstractGridView *grid_view = UI_block_add_view(
+ *block, "file preview grid view", std::make_unique<FilePreviewGridView>(*files));
+
+ ui::GridViewBuilder builder(*block);
+ builder.build_grid_view(*grid_view, *v2d);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 1859e7ccdfc..4b3873bac64 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1331,6 +1331,11 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
return filelist_geticon_image_ex(file);
}
+ImBuf *filelist_file_geticon_image(const FileDirEntry *file)
+{
+ return filelist_geticon_image_ex(file);
+}
+
static int filelist_geticon_ex(const FileDirEntry *file,
const char *root,
const bool is_main,
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index d8297226a8d..fc86744c6ba 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -85,6 +85,7 @@ struct ImBuf *filelist_getimage(struct FileList *filelist, int index);
struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index);
+struct ImBuf *filelist_file_geticon_image(const FileDirEntry *file);
int filelist_geticon(struct FileList *filelist, int index, bool is_main);
int /* ThumbSource */ filelist_preview_source_get(int /* eFileSel_File_Types */ file_type);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index a462476aae0..720e33cfedb 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -653,7 +653,13 @@ static void file_main_region_draw(const bContext *C, ARegion *region)
file_highlight_set(sfile, region, event->xy[0], event->xy[1]);
}
- if (!file_draw_hint_if_invalid(C, sfile, region)) {
+ if (file_draw_hint_if_invalid(C, sfile, region)) {
+ /* Pass. */
+ }
+ else if (params->display == FILE_IMGDISPLAY) {
+ file_view_preview_grid_draw(C, region);
+ }
+ else {
file_draw_list(C, region);
}