Display a basic list of assets, set up scrolling and notifier listening

* Display a non-interactive list of assets, updates as assets get
  loaded.
* Notifier listening happens via the view, so the grid-view supports
  listening to notifiers. This is what triggers regular redraws as
  assets get loaded.
* Scrolling may need more fine tuning, so that scroll-bars are
  hidden if they don't apply (e.g. don't show horizontal scroll-bar for
  the vertically expanding grid-view layout).
This commit is contained in:
Julian Eisel 2022-02-03 15:30:55 +01:00
parent a54bd5fe19
commit 3df2e4e888
12 changed files with 213 additions and 21 deletions

View File

@ -0,0 +1,49 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup editorui
*
* API for simple creation of grid UIs, supporting typically needed features.
* https://wiki.blender.org/wiki/Source/Interface/Views/Grid_Views
*/
#pragma once
struct wmNotifier;
namespace blender::ui {
class AbstractGridViewItem {
public:
virtual ~AbstractGridViewItem() = default;
protected:
AbstractGridViewItem() = default;
};
class AbstractGridView {
public:
virtual ~AbstractGridView() = default;
/** Listen to a notifier, returning true if a redraw is needed. */
virtual bool listen(const wmNotifier &) const;
// protected:
virtual void build() = 0;
};
} // namespace blender::ui

View File

@ -80,6 +80,7 @@ struct wmKeyMapItem;
struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
struct wmRegionListenerParams;
struct wmWindow;
typedef struct uiBlock uiBlock;
@ -91,6 +92,8 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
typedef struct uiTreeViewHandle uiTreeViewHandle;
/* C handle for C++ #ui::AbstractTreeViewItem type. */
typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
/* C handle for C++ #ui::AbstractGridView type. */
typedef struct uiGridViewHandle uiGridViewHandle;
/* Defines */
@ -3163,6 +3166,9 @@ void UI_interface_tag_script_reload(void);
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
#define USE_UI_POPOVER_ONCE
void UI_block_views_listen(const uiBlock *block,
const struct wmRegionListenerParams *listener_params);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
/**
@ -3201,6 +3207,11 @@ uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *regi
const int xy[2]) ATTR_NONNULL(1, 2);
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
/**
* Listen to \a notifier, returning true if the region should redraw.
*/
bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view, const wmNotifier *notifier);
#ifdef __cplusplus
}
#endif

View File

@ -37,6 +37,7 @@ struct uiSearchItems;
namespace blender::ui {
class AbstractGridView;
class AbstractTreeView;
/**
@ -69,6 +70,10 @@ void attribute_search_add_items(
/**
* Override this for all available tree types.
*/
blender::ui::AbstractGridView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
std::unique_ptr<blender::ui::AbstractGridView> tree_view);
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,

View File

@ -38,6 +38,7 @@ set(INC
)
set(SRC
grid_view.cc
interface.c
interface_align.c
interface_anim.c

View File

@ -0,0 +1,48 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup edinterface
*/
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_grid_view.hh"
namespace blender::ui {
/* ---------------------------------------------------------------------- */
bool AbstractGridView::listen(const wmNotifier &) const
{
/* Nothing by default. */
return false;
}
} // namespace blender::ui
using namespace blender::ui;
/* ---------------------------------------------------------------------- */
bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view_handle,
const wmNotifier *notifier)
{
const AbstractGridView &view = *reinterpret_cast<const AbstractGridView *>(view_handle);
return view.listen(*notifier);
}

View File

@ -24,15 +24,22 @@
*/
#include <memory>
#include <type_traits>
#include <variant>
#include "DNA_screen_types.h"
#include "BKE_screen.h"
#include "BLI_listbase.h"
#include "ED_screen.h"
#include "interface_intern.h"
#include "UI_interface.hh"
#include "UI_grid_view.hh"
#include "UI_tree_view.hh"
using namespace blender;
@ -44,10 +51,11 @@ using namespace blender::ui;
*/
struct ViewLink : public Link {
using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
using GridViewPtr = std::unique_ptr<AbstractGridView>;
std::string idname;
/* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
std::variant<TreeViewPtr> view;
std::variant<TreeViewPtr, GridViewPtr> view;
};
template<class T> T *get_view_from_link(ViewLink &link)
@ -56,17 +64,32 @@ template<class T> T *get_view_from_link(ViewLink &link)
return t_uptr ? t_uptr->get() : nullptr;
}
template<class T>
static T *ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr<T> view)
{
static_assert(std::is_same_v<T, AbstractTreeView> || std::is_same_v<T, AbstractGridView>,
"Unsupported view type");
ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
view_link->view = std::move(view);
view_link->idname = idname;
return get_view_from_link<T>(*view_link);
}
AbstractGridView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractGridView> tree_view)
{
return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(tree_view));
}
AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
{
ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
view_link->view = std::move(tree_view);
view_link->idname = idname;
return get_view_from_link<AbstractTreeView>(*view_link);
return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
}
void ui_block_free_views(uiBlock *block)
@ -76,6 +99,19 @@ void ui_block_free_views(uiBlock *block)
}
}
void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
{
LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
/* TODO only grid views, should this be supported by all views? */
if (AbstractGridView *grid_view = get_view_from_link<AbstractGridView>(*view_link)) {
if (UI_grid_view_listen_should_redraw(reinterpret_cast<uiGridViewHandle *>(grid_view),
listener_params->notifier)) {
ED_region_tag_redraw(listener_params->region);
}
}
}
}
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);

View File

@ -161,6 +161,10 @@ void ED_region_do_listen(wmRegionListenerParams *params)
region->type->listener(params);
}
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
UI_block_views_listen(block, params);
}
LISTBASE_FOREACH (uiList *, list, &region->ui_lists) {
if (list->type && list->type->listener) {
list->type->listener(list, params);

View File

@ -25,6 +25,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "asset_browser_intern.hh"
#include "asset_view.hh"
@ -38,9 +39,12 @@ using namespace blender::ed::asset_browser;
void asset_browser_main_region_draw(const bContext *C, ARegion *region)
{
const SpaceAssets *asset_space = CTX_wm_space_assets(C);
View2D *v2d = &region->v2d;
UI_ThemeClearColor(TH_BACK);
UI_view2d_view_ortho(v2d);
const uiStyle *style = UI_style_get_dpi();
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
uiLayout *layout = UI_block_layout(block,
@ -55,6 +59,15 @@ void asset_browser_main_region_draw(const bContext *C, ARegion *region)
asset_view_create_in_layout(*C, asset_space->asset_library_ref, *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);
/* reset view matrix */
UI_view2d_view_restore(C);
UI_view2d_scrollers_draw(v2d, nullptr);
}

View File

@ -25,23 +25,31 @@
#include "ED_asset.h"
#include "UI_interface.h"
#include "UI_interface.hh"
#include "asset_view.hh"
namespace ui = blender::ui;
namespace blender::ed::asset_browser {
AssetGridView::AssetGridView(const AssetLibraryReference &asset_library_ref)
: asset_library_ref_(asset_library_ref)
AssetGridView::AssetGridView(const AssetLibraryReference &asset_library_ref, uiLayout &layout)
: asset_library_ref_(asset_library_ref), layout(layout)
{
}
void AssetGridView::build()
{
ED_assetlist_iterate(asset_library_ref_, [](AssetHandle asset) {
std::cout << ED_asset_handle_get_name(&asset) << std::endl;
ED_assetlist_iterate(asset_library_ref_, [this](AssetHandle asset) {
uiItemL(
&layout, ED_asset_handle_get_name(&asset), ED_asset_handle_get_preview_icon_id(&asset));
return true;
});
std::cout << std::endl;
}
bool AssetGridView::listen(const wmNotifier &notifier) const
{
return ED_assetlist_listen(&asset_library_ref_, &notifier);
}
void asset_view_create_in_layout(const bContext &C,
@ -55,8 +63,10 @@ void asset_view_create_in_layout(const bContext &C,
UI_block_layout_set_current(block, &layout);
AssetGridView grid_view{asset_library_ref};
grid_view.build();
ui::AbstractGridView *grid_view = UI_block_add_view(
*block, "asset grid view", std::make_unique<AssetGridView>(asset_library_ref, layout));
grid_view->build();
}
} // namespace blender::ed::asset_browser

View File

@ -20,19 +20,25 @@
#pragma once
#include "UI_grid_view.hh"
struct bContext;
struct AssetLibraryReference;
struct uiLayout;
namespace blender::ed::asset_browser {
class AssetGridView {
class AssetGridView : public blender::ui::AbstractGridView {
AssetLibraryReference asset_library_ref_;
public:
AssetGridView(const AssetLibraryReference &);
/* TODO temp. */
uiLayout &layout;
void build();
public:
AssetGridView(const AssetLibraryReference &, uiLayout &layout);
void build() override;
bool listen(const wmNotifier &) const override;
};
void asset_view_create_in_layout(const bContext &C,

View File

@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "asset_browser_intern.hh"
#include "asset_view.hh"
@ -57,10 +58,16 @@ static SpaceLink *asset_browser_create(const ScrArea *UNUSED(area), const Scene
}
{
/* Main window. */
/* Main region. */
ARegion *region = MEM_cnew<ARegion>("asset browser main region");
BLI_addtail(&assets_space->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
region->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
region->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
region->v2d.keeptot = V2D_KEEPTOT_STRICT;
region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
}
return (SpaceLink *)assets_space;
@ -90,8 +97,9 @@ static void asset_browser_keymap(wmKeyConfig *UNUSED(keyconf))
/* ---------------------------------------------------------------------- */
/* Main Region */
static void asset_browser_main_region_init(wmWindowManager *UNUSED(wm), ARegion *UNUSED(region))
static void asset_browser_main_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
{
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
}
static void asset_browser_main_region_listener(const wmRegionListenerParams *UNUSED(params))

View File

@ -102,6 +102,7 @@ set(SRC
../include/ED_uvedit.h
../include/ED_view3d.h
../include/ED_view3d_offscreen.h
../include/UI_grid_view.hh
../include/UI_icons.h
../include/UI_interface.h
../include/UI_interface.hh