UI: Asset Shelf (Experimental Feature) #104831
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
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(®ion->v2d.cur) /
|
||||
(BLI_rcti_size_x(®ion->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);
|
||||
|
|
|
@ -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(®ion.v2d.cur) / (BLI_rcti_size_x(®ion.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
Hans Goudey
commented
If the dynamic_cast isn't meant to fail in some cases, it's probably better to use Also, class methods should generally be accessed with 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->`
Julian Eisel
commented
Not a fan of using https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-dynamic_cast 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
Hans Goudey
commented
Hard to argue with the code guidelines I guess.. Still though, I'd find it clearer to use 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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
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.