UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
7 changed files with 118 additions and 22 deletions
Showing only changes of commit 6da90998e2 - Show all commits

View File

@ -4184,6 +4184,26 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (sl->spacetype == SPACE_VIEW3D) {
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
/* TODO for old files saved with the branch only. */
{
SpaceType *space_type = BKE_spacetype_from_id(sl->spacetype);
if (ARegion *asset_shelf = BKE_region_find_in_listbase_by_type(
regionbase, RGN_TYPE_ASSET_SHELF)) {
BLI_remlink(regionbase, asset_shelf);
BKE_area_region_free(space_type, asset_shelf);
MEM_freeN(asset_shelf);
}
if (ARegion *asset_shelf_footer = BKE_region_find_in_listbase_by_type(
regionbase, RGN_TYPE_ASSET_SHELF_FOOTER)) {
BLI_remlink(regionbase, asset_shelf_footer);
BKE_area_region_free(space_type, asset_shelf_footer);
MEM_freeN(asset_shelf_footer);
}
}
{
ARegion *new_asset_shelf_footer = do_versions_add_region_if_not_found(
regionbase,
@ -4196,14 +4216,20 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
{
ARegion *new_asset_shelf = do_versions_add_region_if_not_found(
regionbase,
RGN_TYPE_ASSET_SHELF,
"asset shelf for view3d (versioning)",
RGN_TYPE_ASSET_SHELF_FOOTER);
if (new_asset_shelf != nullptr) {
new_asset_shelf->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
new_asset_shelf->flag |= RGN_FLAG_DYNAMIC_SIZE;
ARegion *asset_shelf = BKE_region_find_in_listbase_by_type(regionbase,
RGN_TYPE_ASSET_SHELF);
/* TODO for old files saved with the branch only. */
if (asset_shelf) {
asset_shelf->flag &= ~RGN_FLAG_DYNAMIC_SIZE;
}
else {
ARegion *new_asset_shelf = do_versions_add_region_if_not_found(
regionbase,
RGN_TYPE_ASSET_SHELF,
"asset shelf for view3d (versioning)",
RGN_TYPE_ASSET_SHELF_FOOTER);
new_asset_shelf->alignment = RGN_ALIGN_BOTTOM;
new_asset_shelf->flag |= RGN_FLAG_HIDDEN;
}
}
}

View File

@ -24,10 +24,13 @@ struct wmWindowManager;
/** Only needed for #RGN_TYPE_ASSET_SHELF (not #RGN_TYPE_ASSET_SHELF_FOOTER). */
void ED_asset_shelf_region_init(ARegion *region);
int ED_asset_shelf_region_snap(const ARegion *region, int size, int axis);
void ED_asset_shelf_region_listen(const struct wmRegionListenerParams *params);
void ED_asset_shelf_region_draw(const bContext *C,
struct ARegion *region,
struct AssetShelfSettings *shelf_settings);
int ED_asset_shelf_region_default_tile_height(void);
int ED_asset_shelf_region_prefsizey(void);
void ED_asset_shelf_footer_region_init(struct wmWindowManager *wm, struct ARegion *region);
void ED_asset_shelf_footer_region(const struct bContext *C, struct ARegion *region);

View File

@ -6,6 +6,8 @@
* General asset shelf code, mostly region callbacks, drawing and context stuff.
*/
#include <algorithm>
#include "AS_asset_catalog_path.hh"
#include "BKE_context.h"
@ -88,6 +90,56 @@ void ED_asset_shelf_region_init(ARegion *region)
v2d.keepofs = V2D_LOCKOFS_X;
}
static constexpr int main_region_padding_y_not_scaled()
{
return 2;
}
static int main_region_padding_y_scaled()
{
return main_region_padding_y_not_scaled() * UI_SCALE_FAC;
}
JulianEisel marked this conversation as resolved Outdated

Suggestion: I find it reads baddy when it's the existence of data in a list is undefined.
In this case the caller can ensure it's in the list in the case it's just been created.

Suggestion: I find it reads baddy when it's the existence of data in a list is undefined. In this case the caller can ensure it's in the list in the case it's just been created.
static int main_region_padding_x_scaled()
{
return 2 * UI_SCALE_FAC;
}
int ED_asset_shelf_region_snap(const ARegion *region, const int size, const int axis)
{
/* Only on Y axis. */
if (axis != 1) {
return size;
}
const int size_scaled = size * UI_SCALE_FAC;
/* Using X axis avoids slight feedback loop when adjusting Y. */
const float aspect = BLI_rctf_size_x(&region->v2d.cur) /
(BLI_rcti_size_x(&region->v2d.mask) + 1);
const float tile_size = ED_asset_shelf_region_default_tile_height() / aspect;
const int region_padding = main_region_padding_y_scaled();
/* How many rows fit into the region (accounting for padding). */
const int rows = std::max(1, int((size_scaled - 2 * region_padding) / tile_size));
const int new_size_scaled = (rows * tile_size + 2 * region_padding);
return new_size_scaled / UI_SCALE_FAC;
}
int ED_asset_shelf_region_default_tile_height()
{
return UI_preview_tile_size_x() * 0.8f;
}
int ED_asset_shelf_region_prefsizey()
{
/* Can't account for DPI here since this is expected to be called on region type initialization
* at startup, when #U isn't available yet. */
return ED_asset_shelf_region_default_tile_height() + 2 * main_region_padding_y_not_scaled();
}
/**
* Check if there is any asset shelf type returning true in it's poll. If not, no asset shelf
* region should be displayed.
@ -123,13 +175,14 @@ void ED_asset_shelf_region_draw(const bContext *C,
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
const uiStyle *style = UI_style_get();
const float padding = style->panelouter;
const float padding_y = main_region_padding_y_scaled();
const float padding_x = main_region_padding_x_scaled();
uiLayout *layout = UI_block_layout(block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
padding,
-padding,
region->winx - 2 * padding,
padding_x,
-padding_y,
region->winx - 2 * padding_x,
1,
0,
style);

View File

@ -17,6 +17,7 @@
#include "ED_asset_handle.h"
#include "ED_asset_list.h"
#include "ED_asset_list.hh"
#include "ED_asset_shelf.h"
#include "UI_grid_view.hh"
#include "UI_interface.h"
@ -184,9 +185,13 @@ void build_asset_view(uiLayout &layout,
return;
}
/* TODO deduplicate from #ED_asset_shelf_region_snap() */
const float aspect = BLI_rctf_size_x(&region.v2d.cur) / (BLI_rcti_size_x(&region.v2d.mask) + 1);
const float tile_size = ED_asset_shelf_region_default_tile_height() / aspect;
std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, const_cast<bContext &>(C));
asset_view->set_catalog_filter(catalog_filter_from_shelf_settings(shelf_settings, *library));
asset_view->set_tile_size(UI_preview_tile_size_x() * 0.8, UI_preview_tile_size_y() * 0.8);
asset_view->set_tile_size(tile_size, tile_size);
uiBlock *block = uiLayoutGetBlock(&layout);
JulianEisel marked this conversation as resolved Outdated

If the dynamic_cast isn't meant to fail in some cases, it's probably better to use static_cast to avoid bloating the code with dynamic casting.

Also, class methods should generally be accessed with this->

If the dynamic_cast isn't meant to fail in some cases, it's probably better to use `static_cast` to avoid bloating the code with dynamic casting. Also, class methods should generally be accessed with `this->`

Not a fan of using static_cast for down casting. It removes type safety for virtually (pun intended) no benefit. Sure it's unlikely to cause issues here, but if it does it's good to get an exception thrown. There's a language feature designed for this, so I rather use it.

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-dynamic_cast
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c147-use-dynamic_cast-to-a-reference-type-when-failure-to-find-the-required-class-is-considered-an-error

Not a fan of using `static_cast` for down casting. It removes type safety for virtually (pun intended) no benefit. Sure it's unlikely to cause issues here, but if it does it's good to get an exception thrown. There's a language feature designed for this, so I rather use it. https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-dynamic_cast https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c147-use-dynamic_cast-to-a-reference-type-when-failure-to-find-the-required-class-is-considered-an-error

Hard to argue with the code guidelines I guess.. Still though, I'd find it clearer to use static_cast, since dynamic_cast gives the impression that the author thinks the cast might fail. But using a reference for the variable negates that impression, making the whole thing confusing. Not a big deal though

Hard to argue with the code guidelines I guess.. Still though, I'd find it clearer to use `static_cast`, since `dynamic_cast` gives the impression that the author thinks the cast might fail. But using a reference for the variable negates that impression, making the whole thing confusing. Not a big deal though
ui::AbstractGridView *grid_view = UI_block_add_view(

View File

@ -1249,9 +1249,7 @@ bool ED_region_is_overlap(int spacetype, int regiontype)
RGN_TYPE_UI,
RGN_TYPE_TOOL_PROPS,
RGN_TYPE_FOOTER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_ASSET_SHELF,
RGN_TYPE_ASSET_SHELF_FOOTER)) {
RGN_TYPE_TOOL_HEADER)) {
return true;
}
}
@ -1308,6 +1306,11 @@ static void region_rect_recursive(
}
}
if (const int snap_flags = ED_region_snap_size_test(region)) {
/* Apply snapping, which updates #ARegion.sizex/sizey values. */
ED_region_snap_size_apply(region, snap_flags);
}
/* `prefsizex/y`, taking into account DPI. */
int prefsizex = UI_SCALE_FAC *
((region->sizex > 1) ? region->sizex + 0.5f : region->type->prefsizex);

View File

@ -2789,14 +2789,16 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
const int size_no_snap = rmd->origval + delta;
rmd->region->sizex = size_no_snap;
CLAMP(rmd->region->sizex, 0, rmd->maxsize);
if (rmd->region->type->snap_size) {
short sizex_test = rmd->region->type->snap_size(rmd->region, rmd->region->sizex, 0);
if (abs(rmd->region->sizex - sizex_test) < snap_size_threshold) {
if ((abs(rmd->region->sizex - sizex_test) < snap_size_threshold) &&
(sizex_test <= rmd->maxsize)) {
rmd->region->sizex = sizex_test;
}
}
CLAMP(rmd->region->sizex, 0, rmd->maxsize);
BLI_assert(rmd->region->sizex <= rmd->maxsize);
if (size_no_snap < UI_UNIT_X / aspect) {
rmd->region->sizex = rmd->origval;
@ -2822,14 +2824,16 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
const int size_no_snap = rmd->origval + delta;
rmd->region->sizey = size_no_snap;
CLAMP(rmd->region->sizey, 0, rmd->maxsize);
if (rmd->region->type->snap_size) {
short sizey_test = rmd->region->type->snap_size(rmd->region, rmd->region->sizey, 1);
if (abs(rmd->region->sizey - sizey_test) < snap_size_threshold) {
if ((abs(rmd->region->sizey - sizey_test) < snap_size_threshold) &&
(sizey_test <= rmd->maxsize)) {
rmd->region->sizey = sizey_test;
}
}
CLAMP(rmd->region->sizey, 0, rmd->maxsize);
BLI_assert(rmd->region->sizey <= rmd->maxsize);
/* NOTE: `UI_UNIT_Y / 4` means you need to drag the footer and execute region
* almost all the way down for it to become hidden, this is done

View File

@ -303,7 +303,8 @@ static SpaceLink *view3d_create(const ScrArea * /*area*/, const Scene *scene)
BLI_addtail(&v3d->regionbase, region);
region->regiontype = RGN_TYPE_ASSET_SHELF;
region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
region->alignment = RGN_ALIGN_BOTTOM;
region->flag = RGN_FLAG_HIDDEN;
/* main region */
region = MEM_cnew<ARegion>("main region for view3d");
@ -2254,10 +2255,11 @@ void ED_spacetype_view3d()
/* regions: asset shelf */
art = MEM_cnew<ARegionType>("spacetype view3d asset shelf region");
art->regionid = RGN_TYPE_ASSET_SHELF;
art->prefsizey = HEADERY * 3.5f;
art->prefsizey = ED_asset_shelf_region_prefsizey();
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_ASSET_SHELF | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
ED_KEYMAP_HEADER;
art->listener = ED_asset_shelf_region_listen;
art->snap_size = ED_asset_shelf_region_snap;
art->context = view3d_asset_shelf_context;
art->init = view3d_asset_shelf_region_init;
art->draw = view3d_asset_shelf_region_draw;